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 | |
| 13 | void samsung_clk_register_mux(void __iomem *base, |
| 14 | const struct samsung_mux_clock *clk_list, |
| 15 | unsigned int nr_clk) |
| 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; |
| 22 | |
| 23 | m = &clk_list[cnt]; |
| 24 | clk = clk_register_mux(NULL, m->name, m->parent_names, |
| 25 | m->num_parents, m->flags, base + m->offset, m->shift, |
| 26 | m->width, m->mux_flags); |
| 27 | clk_dm(m->id, clk); |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | void samsung_clk_register_div(void __iomem *base, |
| 32 | const struct samsung_div_clock *clk_list, |
| 33 | unsigned int nr_clk) |
| 34 | { |
| 35 | unsigned int cnt; |
| 36 | |
| 37 | for (cnt = 0; cnt < nr_clk; cnt++) { |
| 38 | struct clk *clk; |
| 39 | const struct samsung_div_clock *d; |
| 40 | |
| 41 | d = &clk_list[cnt]; |
| 42 | clk = clk_register_divider(NULL, d->name, d->parent_name, |
| 43 | d->flags, base + d->offset, d->shift, |
| 44 | d->width, d->div_flags); |
| 45 | clk_dm(d->id, clk); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | void samsung_clk_register_gate(void __iomem *base, |
| 50 | const struct samsung_gate_clock *clk_list, |
| 51 | unsigned int nr_clk) |
| 52 | { |
| 53 | unsigned int cnt; |
| 54 | |
| 55 | for (cnt = 0; cnt < nr_clk; cnt++) { |
| 56 | struct clk *clk; |
| 57 | const struct samsung_gate_clock *g; |
| 58 | |
| 59 | g = &clk_list[cnt]; |
| 60 | clk = clk_register_gate(NULL, g->name, g->parent_name, |
| 61 | g->flags, base + g->offset, g->bit_idx, |
| 62 | g->gate_flags, NULL); |
| 63 | clk_dm(g->id, clk); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | typedef void (*samsung_clk_register_fn)(void __iomem *base, |
| 68 | const void *clk_list, |
| 69 | unsigned int nr_clk); |
| 70 | |
| 71 | static const samsung_clk_register_fn samsung_clk_register_fns[] = { |
| 72 | [S_CLK_MUX] = (samsung_clk_register_fn)samsung_clk_register_mux, |
| 73 | [S_CLK_DIV] = (samsung_clk_register_fn)samsung_clk_register_div, |
| 74 | [S_CLK_GATE] = (samsung_clk_register_fn)samsung_clk_register_gate, |
| 75 | [S_CLK_PLL] = (samsung_clk_register_fn)samsung_clk_register_pll, |
| 76 | }; |
| 77 | |
| 78 | /** |
| 79 | * samsung_cmu_register_clocks() - Register provided clock groups |
| 80 | * @base: Base address of CMU registers |
| 81 | * @clk_groups: list of clock groups |
| 82 | * @nr_groups: count of clock groups in @clk_groups |
| 83 | * |
| 84 | * Having the array of clock groups @clk_groups makes it possible to keep a |
| 85 | * correct clocks registration order. |
| 86 | */ |
| 87 | void samsung_cmu_register_clocks(void __iomem *base, |
| 88 | const struct samsung_clk_group *clk_groups, |
| 89 | unsigned int nr_groups) |
| 90 | { |
| 91 | unsigned int i; |
| 92 | |
| 93 | for (i = 0; i < nr_groups; i++) { |
| 94 | const struct samsung_clk_group *g = &clk_groups[i]; |
| 95 | |
| 96 | samsung_clk_register_fns[g->type](base, g->clk_list, g->nr_clk); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * samsung_cmu_register_one - Register all CMU clocks |
| 102 | * @dev: CMU device |
| 103 | * @clk_groups: list of CMU clock groups |
| 104 | * @nr_groups: count of CMU clock groups in @clk_groups |
| 105 | * |
| 106 | * Return: 0 on success or negative value on error. |
| 107 | */ |
| 108 | int samsung_cmu_register_one(struct udevice *dev, |
| 109 | const struct samsung_clk_group *clk_groups, |
| 110 | unsigned int nr_groups) |
| 111 | { |
| 112 | void __iomem *base; |
| 113 | |
| 114 | base = dev_read_addr_ptr(dev); |
| 115 | if (!base) |
| 116 | return -EINVAL; |
| 117 | |
| 118 | samsung_cmu_register_clocks(base, clk_groups, nr_groups); |
| 119 | |
| 120 | return 0; |
| 121 | } |