Linux 4.18.10
[linux/fpc-iii.git] / drivers / clk / berlin / berlin2-div.c
blob4d0be66aa6a8cc979088a84655ef06cd6614ef02
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2014 Marvell Technology Group Ltd.
5 * Alexandre Belloni <alexandre.belloni@free-electrons.com>
6 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
7 */
8 #include <linux/bitops.h>
9 #include <linux/clk-provider.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
15 #include "berlin2-div.h"
18 * Clock dividers in Berlin2 SoCs comprise a complex cell to select
19 * input pll and divider. The virtual structure as it is used in Marvell
20 * BSP code can be seen as:
22 * +---+
23 * pll0 --------------->| 0 | +---+
24 * +---+ |(B)|--+--------------->| 0 | +---+
25 * pll1.0 -->| 0 | +-->| 1 | | +--------+ |(E)|----->| 0 | +---+
26 * pll1.1 -->| 1 | | +---+ +-->|(C) 1:M |-->| 1 | |(F)|-->|(G)|->
27 * ... -->|(A)|--+ | +--------+ +---+ +-->| 1 | +---+
28 * ... -->| | +-->|(D) 1:3 |----------+ +---+
29 * pll1.N -->| N | +---------
30 * +---+
32 * (A) input pll clock mux controlled by <PllSelect[1:n]>
33 * (B) input pll bypass mux controlled by <PllSwitch>
34 * (C) programmable clock divider controlled by <Select[1:n]>
35 * (D) constant div-by-3 clock divider
36 * (E) programmable clock divider bypass controlled by <Switch>
37 * (F) constant div-by-3 clock mux controlled by <D3Switch>
38 * (G) clock gate controlled by <Enable>
40 * For whatever reason, above control signals come in two flavors:
41 * - single register dividers with all bits in one register
42 * - shared register dividers with bits spread over multiple registers
43 * (including signals for the same cell spread over consecutive registers)
45 * Also, clock gate and pll mux is not available on every div cell, so
46 * we have to deal with those, too. We reuse common clock composite driver
47 * for it.
50 #define PLL_SELECT_MASK 0x7
51 #define DIV_SELECT_MASK 0x7
53 struct berlin2_div {
54 struct clk_hw hw;
55 void __iomem *base;
56 struct berlin2_div_map map;
57 spinlock_t *lock;
60 #define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
62 static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
64 static int berlin2_div_is_enabled(struct clk_hw *hw)
66 struct berlin2_div *div = to_berlin2_div(hw);
67 struct berlin2_div_map *map = &div->map;
68 u32 reg;
70 if (div->lock)
71 spin_lock(div->lock);
73 reg = readl_relaxed(div->base + map->gate_offs);
74 reg >>= map->gate_shift;
76 if (div->lock)
77 spin_unlock(div->lock);
79 return (reg & 0x1);
82 static int berlin2_div_enable(struct clk_hw *hw)
84 struct berlin2_div *div = to_berlin2_div(hw);
85 struct berlin2_div_map *map = &div->map;
86 u32 reg;
88 if (div->lock)
89 spin_lock(div->lock);
91 reg = readl_relaxed(div->base + map->gate_offs);
92 reg |= BIT(map->gate_shift);
93 writel_relaxed(reg, div->base + map->gate_offs);
95 if (div->lock)
96 spin_unlock(div->lock);
98 return 0;
101 static void berlin2_div_disable(struct clk_hw *hw)
103 struct berlin2_div *div = to_berlin2_div(hw);
104 struct berlin2_div_map *map = &div->map;
105 u32 reg;
107 if (div->lock)
108 spin_lock(div->lock);
110 reg = readl_relaxed(div->base + map->gate_offs);
111 reg &= ~BIT(map->gate_shift);
112 writel_relaxed(reg, div->base + map->gate_offs);
114 if (div->lock)
115 spin_unlock(div->lock);
118 static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
120 struct berlin2_div *div = to_berlin2_div(hw);
121 struct berlin2_div_map *map = &div->map;
122 u32 reg;
124 if (div->lock)
125 spin_lock(div->lock);
127 /* index == 0 is PLL_SWITCH */
128 reg = readl_relaxed(div->base + map->pll_switch_offs);
129 if (index == 0)
130 reg &= ~BIT(map->pll_switch_shift);
131 else
132 reg |= BIT(map->pll_switch_shift);
133 writel_relaxed(reg, div->base + map->pll_switch_offs);
135 /* index > 0 is PLL_SELECT */
136 if (index > 0) {
137 reg = readl_relaxed(div->base + map->pll_select_offs);
138 reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
139 reg |= (index - 1) << map->pll_select_shift;
140 writel_relaxed(reg, div->base + map->pll_select_offs);
143 if (div->lock)
144 spin_unlock(div->lock);
146 return 0;
149 static u8 berlin2_div_get_parent(struct clk_hw *hw)
151 struct berlin2_div *div = to_berlin2_div(hw);
152 struct berlin2_div_map *map = &div->map;
153 u32 reg;
154 u8 index = 0;
156 if (div->lock)
157 spin_lock(div->lock);
159 /* PLL_SWITCH == 0 is index 0 */
160 reg = readl_relaxed(div->base + map->pll_switch_offs);
161 reg &= BIT(map->pll_switch_shift);
162 if (reg) {
163 reg = readl_relaxed(div->base + map->pll_select_offs);
164 reg >>= map->pll_select_shift;
165 reg &= PLL_SELECT_MASK;
166 index = 1 + reg;
169 if (div->lock)
170 spin_unlock(div->lock);
172 return index;
175 static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
176 unsigned long parent_rate)
178 struct berlin2_div *div = to_berlin2_div(hw);
179 struct berlin2_div_map *map = &div->map;
180 u32 divsw, div3sw, divider = 1;
182 if (div->lock)
183 spin_lock(div->lock);
185 divsw = readl_relaxed(div->base + map->div_switch_offs) &
186 (1 << map->div_switch_shift);
187 div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
188 (1 << map->div3_switch_shift);
190 /* constant divide-by-3 (dominant) */
191 if (div3sw != 0) {
192 divider = 3;
193 /* divider can be bypassed with DIV_SWITCH == 0 */
194 } else if (divsw == 0) {
195 divider = 1;
196 /* clock divider determined by DIV_SELECT */
197 } else {
198 u32 reg;
199 reg = readl_relaxed(div->base + map->div_select_offs);
200 reg >>= map->div_select_shift;
201 reg &= DIV_SELECT_MASK;
202 divider = clk_div[reg];
205 if (div->lock)
206 spin_unlock(div->lock);
208 return parent_rate / divider;
211 static const struct clk_ops berlin2_div_rate_ops = {
212 .recalc_rate = berlin2_div_recalc_rate,
215 static const struct clk_ops berlin2_div_gate_ops = {
216 .is_enabled = berlin2_div_is_enabled,
217 .enable = berlin2_div_enable,
218 .disable = berlin2_div_disable,
221 static const struct clk_ops berlin2_div_mux_ops = {
222 .set_parent = berlin2_div_set_parent,
223 .get_parent = berlin2_div_get_parent,
226 struct clk_hw * __init
227 berlin2_div_register(const struct berlin2_div_map *map,
228 void __iomem *base, const char *name, u8 div_flags,
229 const char **parent_names, int num_parents,
230 unsigned long flags, spinlock_t *lock)
232 const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
233 const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
234 const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
235 struct berlin2_div *div;
237 div = kzalloc(sizeof(*div), GFP_KERNEL);
238 if (!div)
239 return ERR_PTR(-ENOMEM);
241 /* copy div_map to allow __initconst */
242 memcpy(&div->map, map, sizeof(*map));
243 div->base = base;
244 div->lock = lock;
246 if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
247 gate_ops = NULL;
248 if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
249 mux_ops = NULL;
251 return clk_hw_register_composite(NULL, name, parent_names, num_parents,
252 &div->hw, mux_ops, &div->hw, rate_ops,
253 &div->hw, gate_ops, flags);