Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2023 Linaro Ltd. * Sam Protsenko <semen.protsenko@linaro.org> * * This file includes utility functions to register clocks to common * clock framework for Samsung platforms. */ #include <dm.h> #include "clk.h" int samsung_clk_request(struct clk *clk) { struct clk *c; int ret; ret = clk_get_by_id(clk->id, &c); if (ret) return ret; clk->dev = c->dev; return 0; } static void samsung_clk_register_fixed_rate(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk) { unsigned int cnt; for (cnt = 0; cnt < nr_clk; cnt++) { struct clk *clk; const struct samsung_fixed_rate_clock *m; unsigned long clk_id; m = &clk_list[cnt]; clk = clk_register_fixed_rate(NULL, m->name, m->fixed_rate); clk_id = SAMSUNG_TO_CLK_ID(cmu_id, m->id); clk_dm(clk_id, clk); } } static void samsung_clk_register_fixed_factor(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_fixed_factor_clock *clk_list, unsigned int nr_clk) { unsigned int cnt; for (cnt = 0; cnt < nr_clk; cnt++) { struct clk *clk; const struct samsung_fixed_factor_clock *m; unsigned long clk_id; m = &clk_list[cnt]; clk = clk_register_fixed_factor(dev, m->name, m->parent_name, m->flags, m->mult, m->div); clk_id = SAMSUNG_TO_CLK_ID(cmu_id, m->id); clk_dm(clk_id, clk); } } static void samsung_clk_register_mux(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_mux_clock *clk_list, unsigned int nr_clk) { unsigned int cnt; for (cnt = 0; cnt < nr_clk; cnt++) { struct clk *clk; const struct samsung_mux_clock *m; unsigned long clk_id; m = &clk_list[cnt]; clk = clk_register_mux(dev, m->name, m->parent_names, m->num_parents, m->flags, base + m->offset, m->shift, m->width, m->mux_flags); clk_id = SAMSUNG_TO_CLK_ID(cmu_id, m->id); clk_dm(clk_id, clk); } } static void samsung_clk_register_div(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_div_clock *clk_list, unsigned int nr_clk) { unsigned int cnt; for (cnt = 0; cnt < nr_clk; cnt++) { struct clk *clk; const struct samsung_div_clock *d; unsigned long clk_id; d = &clk_list[cnt]; clk = clk_register_divider(dev, d->name, d->parent_name, d->flags, base + d->offset, d->shift, d->width, d->div_flags); clk_id = SAMSUNG_TO_CLK_ID(cmu_id, d->id); clk_dm(clk_id, clk); } } static void samsung_clk_register_gate(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_gate_clock *clk_list, unsigned int nr_clk) { unsigned int cnt; for (cnt = 0; cnt < nr_clk; cnt++) { struct clk *clk; const struct samsung_gate_clock *g; unsigned long clk_id; g = &clk_list[cnt]; clk = clk_register_gate(dev, g->name, g->parent_name, g->flags, base + g->offset, g->bit_idx, g->gate_flags, NULL); clk_id = SAMSUNG_TO_CLK_ID(cmu_id, g->id); clk_dm(clk_id, clk); } } typedef void (*samsung_clk_register_fn)(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const void *clk_list, unsigned int nr_clk); static const samsung_clk_register_fn samsung_clk_register_fns[] = { [S_CLK_FRATE] = (samsung_clk_register_fn)samsung_clk_register_fixed_rate, [S_CLK_FFACTOR] = (samsung_clk_register_fn)samsung_clk_register_fixed_factor, [S_CLK_MUX] = (samsung_clk_register_fn)samsung_clk_register_mux, [S_CLK_DIV] = (samsung_clk_register_fn)samsung_clk_register_div, [S_CLK_GATE] = (samsung_clk_register_fn)samsung_clk_register_gate, [S_CLK_PLL] = (samsung_clk_register_fn)samsung_clk_register_pll, }; /** * samsung_cmu_register_clocks() - Register provided clock groups * @base: Base address of CMU registers * @cmu_id: CMU index number * @clk_groups: list of clock groups * @nr_groups: count of clock groups in @clk_groups * * Having the array of clock groups @clk_groups makes it possible to keep a * correct clocks registration order. */ static void samsung_cmu_register_clocks(struct udevice *dev, void __iomem *base, unsigned int cmu_id, const struct samsung_clk_group *clk_groups, unsigned int nr_groups) { unsigned int i; for (i = 0; i < nr_groups; i++) { const struct samsung_clk_group *g = &clk_groups[i]; samsung_clk_register_fns[g->type](dev, base, cmu_id, g->clk_list, g->nr_clk); } } /** * samsung_cmu_register_one - Register all CMU clocks * @dev: CMU device * @cmu_id: CMU index number * @clk_groups: list of CMU clock groups * @nr_groups: count of CMU clock groups in @clk_groups * * Return: 0 on success or negative value on error. */ int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id, const struct samsung_clk_group *clk_groups, unsigned int nr_groups) { void __iomem *base; base = dev_read_addr_ptr(dev); if (!base) return -EINVAL; samsung_cmu_register_clocks(dev, base, cmu_id, clk_groups, nr_groups); return 0; } |