Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * Copyright (C) 2023 Linaro Ltd. |
| 4 | * Sam Protsenko <semen.protsenko@linaro.org> |
| 5 | * |
| 6 | * This file includes utility functions to register clocks to common |
| 7 | * clock framework for Samsung platforms. |
| 8 | */ |
| 9 | |
| 10 | #include <dm.h> |
| 11 | #include "clk.h" |
| 12 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 13 | static void samsung_clk_register_mux(void __iomem *base, unsigned int cmu_id, |
| 14 | const struct samsung_mux_clock *clk_list, |
| 15 | unsigned int nr_clk) |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 16 | { |
| 17 | unsigned int cnt; |
| 18 | |
| 19 | for (cnt = 0; cnt < nr_clk; cnt++) { |
| 20 | struct clk *clk; |
| 21 | const struct samsung_mux_clock *m; |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 22 | unsigned long clk_id; |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 23 | |
| 24 | m = &clk_list[cnt]; |
| 25 | clk = clk_register_mux(NULL, m->name, m->parent_names, |
| 26 | m->num_parents, m->flags, base + m->offset, m->shift, |
| 27 | m->width, m->mux_flags); |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 28 | clk_id = SAMSUNG_TO_CLK_ID(cmu_id, m->id); |
| 29 | clk_dm(clk_id, clk); |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 30 | } |
| 31 | } |
| 32 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 33 | static void samsung_clk_register_div(void __iomem *base, unsigned int cmu_id, |
| 34 | const struct samsung_div_clock *clk_list, |
| 35 | unsigned int nr_clk) |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 36 | { |
| 37 | unsigned int cnt; |
| 38 | |
| 39 | for (cnt = 0; cnt < nr_clk; cnt++) { |
| 40 | struct clk *clk; |
| 41 | const struct samsung_div_clock *d; |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 42 | unsigned long clk_id; |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 43 | |
| 44 | d = &clk_list[cnt]; |
| 45 | clk = clk_register_divider(NULL, d->name, d->parent_name, |
| 46 | d->flags, base + d->offset, d->shift, |
| 47 | d->width, d->div_flags); |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 48 | clk_id = SAMSUNG_TO_CLK_ID(cmu_id, d->id); |
| 49 | clk_dm(clk_id, clk); |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 50 | } |
| 51 | } |
| 52 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 53 | static void samsung_clk_register_gate(void __iomem *base, unsigned int cmu_id, |
| 54 | const struct samsung_gate_clock *clk_list, |
| 55 | unsigned int nr_clk) |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 56 | { |
| 57 | unsigned int cnt; |
| 58 | |
| 59 | for (cnt = 0; cnt < nr_clk; cnt++) { |
| 60 | struct clk *clk; |
| 61 | const struct samsung_gate_clock *g; |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 62 | unsigned long clk_id; |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 63 | |
| 64 | g = &clk_list[cnt]; |
| 65 | clk = clk_register_gate(NULL, g->name, g->parent_name, |
| 66 | g->flags, base + g->offset, g->bit_idx, |
| 67 | g->gate_flags, NULL); |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 68 | clk_id = SAMSUNG_TO_CLK_ID(cmu_id, g->id); |
| 69 | clk_dm(clk_id, clk); |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 70 | } |
| 71 | } |
| 72 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 73 | typedef void (*samsung_clk_register_fn)(void __iomem *base, unsigned int cmu_id, |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 74 | const void *clk_list, |
| 75 | unsigned int nr_clk); |
| 76 | |
| 77 | static const samsung_clk_register_fn samsung_clk_register_fns[] = { |
| 78 | [S_CLK_MUX] = (samsung_clk_register_fn)samsung_clk_register_mux, |
| 79 | [S_CLK_DIV] = (samsung_clk_register_fn)samsung_clk_register_div, |
| 80 | [S_CLK_GATE] = (samsung_clk_register_fn)samsung_clk_register_gate, |
| 81 | [S_CLK_PLL] = (samsung_clk_register_fn)samsung_clk_register_pll, |
| 82 | }; |
| 83 | |
| 84 | /** |
| 85 | * samsung_cmu_register_clocks() - Register provided clock groups |
| 86 | * @base: Base address of CMU registers |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 87 | * @cmu_id: CMU index number |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 88 | * @clk_groups: list of clock groups |
| 89 | * @nr_groups: count of clock groups in @clk_groups |
| 90 | * |
| 91 | * Having the array of clock groups @clk_groups makes it possible to keep a |
| 92 | * correct clocks registration order. |
| 93 | */ |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 94 | static void samsung_cmu_register_clocks(void __iomem *base, unsigned int cmu_id, |
Sam Protsenko | 49ba25a | 2024-03-07 20:18:56 -0600 | [diff] [blame] | 95 | const struct samsung_clk_group *clk_groups, |
| 96 | unsigned int nr_groups) |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 97 | { |
| 98 | unsigned int i; |
| 99 | |
| 100 | for (i = 0; i < nr_groups; i++) { |
| 101 | const struct samsung_clk_group *g = &clk_groups[i]; |
| 102 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 103 | samsung_clk_register_fns[g->type](base, cmu_id, |
| 104 | g->clk_list, g->nr_clk); |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 105 | } |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * samsung_cmu_register_one - Register all CMU clocks |
| 110 | * @dev: CMU device |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 111 | * @cmu_id: CMU index number |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 112 | * @clk_groups: list of CMU clock groups |
| 113 | * @nr_groups: count of CMU clock groups in @clk_groups |
| 114 | * |
| 115 | * Return: 0 on success or negative value on error. |
| 116 | */ |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 117 | int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id, |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 118 | const struct samsung_clk_group *clk_groups, |
| 119 | unsigned int nr_groups) |
| 120 | { |
| 121 | void __iomem *base; |
| 122 | |
| 123 | base = dev_read_addr_ptr(dev); |
| 124 | if (!base) |
| 125 | return -EINVAL; |
| 126 | |
Sam Protsenko | 6211235 | 2024-03-07 20:18:57 -0600 | [diff] [blame] | 127 | samsung_cmu_register_clocks(base, cmu_id, clk_groups, nr_groups); |
Sam Protsenko | 8a0f634 | 2024-01-10 21:09:03 -0600 | [diff] [blame] | 128 | |
| 129 | return 0; |
| 130 | } |