1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for Renesas Versaclock 3 |
4 | * |
5 | * Copyright (C) 2023 Renesas Electronics Corp. |
6 | */ |
7 | |
8 | #include <linux/clk-provider.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/limits.h> |
11 | #include <linux/module.h> |
12 | #include <linux/regmap.h> |
13 | |
14 | #define NUM_CONFIG_REGISTERS 37 |
15 | |
16 | #define VC3_GENERAL_CTR 0x0 |
17 | #define VC3_GENERAL_CTR_DIV1_SRC_SEL BIT(3) |
18 | #define VC3_GENERAL_CTR_PLL3_REFIN_SEL BIT(2) |
19 | |
20 | #define VC3_PLL3_M_DIVIDER 0x3 |
21 | #define VC3_PLL3_M_DIV1 BIT(7) |
22 | #define VC3_PLL3_M_DIV2 BIT(6) |
23 | #define VC3_PLL3_M_DIV(n) ((n) & GENMASK(5, 0)) |
24 | |
25 | #define VC3_PLL3_N_DIVIDER 0x4 |
26 | #define VC3_PLL3_LOOP_FILTER_N_DIV_MSB 0x5 |
27 | |
28 | #define VC3_PLL3_CHARGE_PUMP_CTRL 0x6 |
29 | #define VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL BIT(7) |
30 | |
31 | #define VC3_PLL1_CTRL_OUTDIV5 0x7 |
32 | #define VC3_PLL1_CTRL_OUTDIV5_PLL1_MDIV_DOUBLER BIT(7) |
33 | |
34 | #define VC3_PLL1_M_DIVIDER 0x8 |
35 | #define VC3_PLL1_M_DIV1 BIT(7) |
36 | #define VC3_PLL1_M_DIV2 BIT(6) |
37 | #define VC3_PLL1_M_DIV(n) ((n) & GENMASK(5, 0)) |
38 | |
39 | #define VC3_PLL1_VCO_N_DIVIDER 0x9 |
40 | #define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0xa |
41 | |
42 | #define VC3_OUT_DIV1_DIV2_CTRL 0xf |
43 | |
44 | #define VC3_PLL2_FB_INT_DIV_MSB 0x10 |
45 | #define VC3_PLL2_FB_INT_DIV_LSB 0x11 |
46 | #define VC3_PLL2_FB_FRC_DIV_MSB 0x12 |
47 | #define VC3_PLL2_FB_FRC_DIV_LSB 0x13 |
48 | |
49 | #define VC3_PLL2_M_DIVIDER 0x1a |
50 | #define VC3_PLL2_MDIV_DOUBLER BIT(7) |
51 | #define VC3_PLL2_M_DIV1 BIT(6) |
52 | #define VC3_PLL2_M_DIV2 BIT(5) |
53 | #define VC3_PLL2_M_DIV(n) ((n) & GENMASK(4, 0)) |
54 | |
55 | #define VC3_OUT_DIV3_DIV4_CTRL 0x1b |
56 | |
57 | #define VC3_PLL_OP_CTRL 0x1c |
58 | #define VC3_PLL_OP_CTRL_PLL2_REFIN_SEL 6 |
59 | |
60 | #define VC3_OUTPUT_CTR 0x1d |
61 | #define VC3_OUTPUT_CTR_DIV4_SRC_SEL BIT(3) |
62 | |
63 | #define VC3_SE2_CTRL_REG0 0x1f |
64 | #define VC3_SE2_CTRL_REG0_SE2_CLK_SEL BIT(6) |
65 | |
66 | #define VC3_SE3_DIFF1_CTRL_REG 0x21 |
67 | #define VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL BIT(6) |
68 | |
69 | #define VC3_DIFF1_CTRL_REG 0x22 |
70 | #define VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL BIT(7) |
71 | |
72 | #define VC3_DIFF2_CTRL_REG 0x23 |
73 | #define VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL BIT(7) |
74 | |
75 | #define VC3_SE1_DIV4_CTRL 0x24 |
76 | #define VC3_SE1_DIV4_CTRL_SE1_CLK_SEL BIT(3) |
77 | |
78 | #define VC3_PLL1_VCO_MIN 300000000UL |
79 | #define VC3_PLL1_VCO_MAX 600000000UL |
80 | |
81 | #define VC3_PLL2_VCO_MIN 400000000UL |
82 | #define VC3_PLL2_VCO_MAX 1200000000UL |
83 | |
84 | #define VC3_PLL3_VCO_MIN 300000000UL |
85 | #define VC3_PLL3_VCO_MAX 800000000UL |
86 | |
87 | #define VC3_2_POW_16 (U16_MAX + 1) |
88 | #define VC3_DIV_MASK(width) ((1 << (width)) - 1) |
89 | |
90 | enum vc3_pfd_mux { |
91 | VC3_PFD2_MUX, |
92 | VC3_PFD3_MUX, |
93 | }; |
94 | |
95 | enum vc3_pfd { |
96 | VC3_PFD1, |
97 | VC3_PFD2, |
98 | VC3_PFD3, |
99 | }; |
100 | |
101 | enum vc3_pll { |
102 | VC3_PLL1, |
103 | VC3_PLL2, |
104 | VC3_PLL3, |
105 | }; |
106 | |
107 | enum vc3_div_mux { |
108 | VC3_DIV1_MUX, |
109 | VC3_DIV3_MUX, |
110 | VC3_DIV4_MUX, |
111 | }; |
112 | |
113 | enum vc3_div { |
114 | VC3_DIV1, |
115 | VC3_DIV2, |
116 | VC3_DIV3, |
117 | VC3_DIV4, |
118 | VC3_DIV5, |
119 | }; |
120 | |
121 | enum vc3_clk { |
122 | VC3_REF, |
123 | VC3_SE1, |
124 | VC3_SE2, |
125 | VC3_SE3, |
126 | VC3_DIFF1, |
127 | VC3_DIFF2, |
128 | }; |
129 | |
130 | enum vc3_clk_mux { |
131 | VC3_SE1_MUX = VC3_SE1 - 1, |
132 | VC3_SE2_MUX = VC3_SE2 - 1, |
133 | VC3_SE3_MUX = VC3_SE3 - 1, |
134 | VC3_DIFF1_MUX = VC3_DIFF1 - 1, |
135 | VC3_DIFF2_MUX = VC3_DIFF2 - 1, |
136 | }; |
137 | |
138 | struct vc3_clk_data { |
139 | u8 offs; |
140 | u8 bitmsk; |
141 | }; |
142 | |
143 | struct vc3_pfd_data { |
144 | u8 num; |
145 | u8 offs; |
146 | u8 mdiv1_bitmsk; |
147 | u8 mdiv2_bitmsk; |
148 | }; |
149 | |
150 | struct vc3_pll_data { |
151 | unsigned long vco_min; |
152 | unsigned long vco_max; |
153 | u8 num; |
154 | u8 int_div_msb_offs; |
155 | u8 int_div_lsb_offs; |
156 | }; |
157 | |
158 | struct vc3_div_data { |
159 | const struct clk_div_table *table; |
160 | u8 offs; |
161 | u8 shift; |
162 | u8 width; |
163 | u8 flags; |
164 | }; |
165 | |
166 | struct vc3_hw_data { |
167 | struct clk_hw hw; |
168 | struct regmap *regmap; |
169 | const void *data; |
170 | |
171 | u32 div_int; |
172 | u32 div_frc; |
173 | }; |
174 | |
175 | static const struct clk_div_table div1_divs[] = { |
176 | { .val = 0, .div = 1, }, { .val = 1, .div = 4, }, |
177 | { .val = 2, .div = 5, }, { .val = 3, .div = 6, }, |
178 | { .val = 4, .div = 2, }, { .val = 5, .div = 8, }, |
179 | { .val = 6, .div = 10, }, { .val = 7, .div = 12, }, |
180 | { .val = 8, .div = 4, }, { .val = 9, .div = 16, }, |
181 | { .val = 10, .div = 20, }, { .val = 11, .div = 24, }, |
182 | { .val = 12, .div = 8, }, { .val = 13, .div = 32, }, |
183 | { .val = 14, .div = 40, }, { .val = 15, .div = 48, }, |
184 | {} |
185 | }; |
186 | |
187 | static const struct clk_div_table div245_divs[] = { |
188 | { .val = 0, .div = 1, }, { .val = 1, .div = 3, }, |
189 | { .val = 2, .div = 5, }, { .val = 3, .div = 10, }, |
190 | { .val = 4, .div = 2, }, { .val = 5, .div = 6, }, |
191 | { .val = 6, .div = 10, }, { .val = 7, .div = 20, }, |
192 | { .val = 8, .div = 4, }, { .val = 9, .div = 12, }, |
193 | { .val = 10, .div = 20, }, { .val = 11, .div = 40, }, |
194 | { .val = 12, .div = 5, }, { .val = 13, .div = 15, }, |
195 | { .val = 14, .div = 25, }, { .val = 15, .div = 50, }, |
196 | {} |
197 | }; |
198 | |
199 | static const struct clk_div_table div3_divs[] = { |
200 | { .val = 0, .div = 1, }, { .val = 1, .div = 3, }, |
201 | { .val = 2, .div = 5, }, { .val = 3, .div = 10, }, |
202 | { .val = 4, .div = 2, }, { .val = 5, .div = 6, }, |
203 | { .val = 6, .div = 10, }, { .val = 7, .div = 20, }, |
204 | { .val = 8, .div = 4, }, { .val = 9, .div = 12, }, |
205 | { .val = 10, .div = 20, }, { .val = 11, .div = 40, }, |
206 | { .val = 12, .div = 8, }, { .val = 13, .div = 24, }, |
207 | { .val = 14, .div = 40, }, { .val = 15, .div = 80, }, |
208 | {} |
209 | }; |
210 | |
211 | static struct clk_hw *clk_out[6]; |
212 | |
213 | static u8 vc3_pfd_mux_get_parent(struct clk_hw *hw) |
214 | { |
215 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
216 | const struct vc3_clk_data *pfd_mux = vc3->data; |
217 | u32 src; |
218 | |
219 | regmap_read(map: vc3->regmap, reg: pfd_mux->offs, val: &src); |
220 | |
221 | return !!(src & pfd_mux->bitmsk); |
222 | } |
223 | |
224 | static int vc3_pfd_mux_set_parent(struct clk_hw *hw, u8 index) |
225 | { |
226 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
227 | const struct vc3_clk_data *pfd_mux = vc3->data; |
228 | |
229 | return regmap_update_bits(map: vc3->regmap, reg: pfd_mux->offs, mask: pfd_mux->bitmsk, |
230 | val: index ? pfd_mux->bitmsk : 0); |
231 | } |
232 | |
233 | static const struct clk_ops vc3_pfd_mux_ops = { |
234 | .determine_rate = clk_hw_determine_rate_no_reparent, |
235 | .set_parent = vc3_pfd_mux_set_parent, |
236 | .get_parent = vc3_pfd_mux_get_parent, |
237 | }; |
238 | |
239 | static unsigned long vc3_pfd_recalc_rate(struct clk_hw *hw, |
240 | unsigned long parent_rate) |
241 | { |
242 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
243 | const struct vc3_pfd_data *pfd = vc3->data; |
244 | unsigned int prediv, premul; |
245 | unsigned long rate; |
246 | u8 mdiv; |
247 | |
248 | regmap_read(map: vc3->regmap, reg: pfd->offs, val: &prediv); |
249 | if (pfd->num == VC3_PFD1) { |
250 | /* The bypass_prediv is set, PLL fed from Ref_in directly. */ |
251 | if (prediv & pfd->mdiv1_bitmsk) { |
252 | /* check doubler is set or not */ |
253 | regmap_read(map: vc3->regmap, VC3_PLL1_CTRL_OUTDIV5, val: &premul); |
254 | if (premul & VC3_PLL1_CTRL_OUTDIV5_PLL1_MDIV_DOUBLER) |
255 | parent_rate *= 2; |
256 | return parent_rate; |
257 | } |
258 | mdiv = VC3_PLL1_M_DIV(prediv); |
259 | } else if (pfd->num == VC3_PFD2) { |
260 | /* The bypass_prediv is set, PLL fed from Ref_in directly. */ |
261 | if (prediv & pfd->mdiv1_bitmsk) { |
262 | regmap_read(map: vc3->regmap, VC3_PLL2_M_DIVIDER, val: &premul); |
263 | /* check doubler is set or not */ |
264 | if (premul & VC3_PLL2_MDIV_DOUBLER) |
265 | parent_rate *= 2; |
266 | return parent_rate; |
267 | } |
268 | |
269 | mdiv = VC3_PLL2_M_DIV(prediv); |
270 | } else { |
271 | /* The bypass_prediv is set, PLL fed from Ref_in directly. */ |
272 | if (prediv & pfd->mdiv1_bitmsk) |
273 | return parent_rate; |
274 | |
275 | mdiv = VC3_PLL3_M_DIV(prediv); |
276 | } |
277 | |
278 | if (prediv & pfd->mdiv2_bitmsk) |
279 | rate = parent_rate / 2; |
280 | else |
281 | rate = parent_rate / mdiv; |
282 | |
283 | return rate; |
284 | } |
285 | |
286 | static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate, |
287 | unsigned long *parent_rate) |
288 | { |
289 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
290 | const struct vc3_pfd_data *pfd = vc3->data; |
291 | unsigned long idiv; |
292 | |
293 | /* PLL cannot operate with input clock above 50 MHz. */ |
294 | if (rate > 50000000) |
295 | return -EINVAL; |
296 | |
297 | /* CLKIN within range of PLL input, feed directly to PLL. */ |
298 | if (*parent_rate <= 50000000) |
299 | return *parent_rate; |
300 | |
301 | idiv = DIV_ROUND_UP(*parent_rate, rate); |
302 | if (pfd->num == VC3_PFD1 || pfd->num == VC3_PFD3) { |
303 | if (idiv > 63) |
304 | return -EINVAL; |
305 | } else { |
306 | if (idiv > 31) |
307 | return -EINVAL; |
308 | } |
309 | |
310 | return *parent_rate / idiv; |
311 | } |
312 | |
313 | static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate, |
314 | unsigned long parent_rate) |
315 | { |
316 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
317 | const struct vc3_pfd_data *pfd = vc3->data; |
318 | unsigned long idiv; |
319 | u8 div; |
320 | |
321 | /* CLKIN within range of PLL input, feed directly to PLL. */ |
322 | if (parent_rate <= 50000000) { |
323 | regmap_update_bits(map: vc3->regmap, reg: pfd->offs, mask: pfd->mdiv1_bitmsk, |
324 | val: pfd->mdiv1_bitmsk); |
325 | regmap_update_bits(map: vc3->regmap, reg: pfd->offs, mask: pfd->mdiv2_bitmsk, val: 0); |
326 | return 0; |
327 | } |
328 | |
329 | idiv = DIV_ROUND_UP(parent_rate, rate); |
330 | /* We have dedicated div-2 predivider. */ |
331 | if (idiv == 2) { |
332 | regmap_update_bits(map: vc3->regmap, reg: pfd->offs, mask: pfd->mdiv2_bitmsk, |
333 | val: pfd->mdiv2_bitmsk); |
334 | regmap_update_bits(map: vc3->regmap, reg: pfd->offs, mask: pfd->mdiv1_bitmsk, val: 0); |
335 | } else { |
336 | if (pfd->num == VC3_PFD1) |
337 | div = VC3_PLL1_M_DIV(idiv); |
338 | else if (pfd->num == VC3_PFD2) |
339 | div = VC3_PLL2_M_DIV(idiv); |
340 | else |
341 | div = VC3_PLL3_M_DIV(idiv); |
342 | |
343 | regmap_write(map: vc3->regmap, reg: pfd->offs, val: div); |
344 | } |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static const struct clk_ops vc3_pfd_ops = { |
350 | .recalc_rate = vc3_pfd_recalc_rate, |
351 | .round_rate = vc3_pfd_round_rate, |
352 | .set_rate = vc3_pfd_set_rate, |
353 | }; |
354 | |
355 | static unsigned long vc3_pll_recalc_rate(struct clk_hw *hw, |
356 | unsigned long parent_rate) |
357 | { |
358 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
359 | const struct vc3_pll_data *pll = vc3->data; |
360 | u32 div_int, div_frc, val; |
361 | unsigned long rate; |
362 | |
363 | regmap_read(map: vc3->regmap, reg: pll->int_div_msb_offs, val: &val); |
364 | div_int = (val & GENMASK(2, 0)) << 8; |
365 | regmap_read(map: vc3->regmap, reg: pll->int_div_lsb_offs, val: &val); |
366 | div_int |= val; |
367 | |
368 | if (pll->num == VC3_PLL2) { |
369 | regmap_read(map: vc3->regmap, VC3_PLL2_FB_FRC_DIV_MSB, val: &val); |
370 | div_frc = val << 8; |
371 | regmap_read(map: vc3->regmap, VC3_PLL2_FB_FRC_DIV_LSB, val: &val); |
372 | div_frc |= val; |
373 | rate = (parent_rate * |
374 | (div_int * VC3_2_POW_16 + div_frc) / VC3_2_POW_16); |
375 | } else { |
376 | rate = parent_rate * div_int; |
377 | } |
378 | |
379 | return rate; |
380 | } |
381 | |
382 | static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
383 | unsigned long *parent_rate) |
384 | { |
385 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
386 | const struct vc3_pll_data *pll = vc3->data; |
387 | u64 div_frc; |
388 | |
389 | if (rate < pll->vco_min) |
390 | rate = pll->vco_min; |
391 | if (rate > pll->vco_max) |
392 | rate = pll->vco_max; |
393 | |
394 | vc3->div_int = rate / *parent_rate; |
395 | |
396 | if (pll->num == VC3_PLL2) { |
397 | if (vc3->div_int > 0x7ff) |
398 | rate = *parent_rate * 0x7ff; |
399 | |
400 | /* Determine best fractional part, which is 16 bit wide */ |
401 | div_frc = rate % *parent_rate; |
402 | div_frc *= BIT(16) - 1; |
403 | |
404 | vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX); |
405 | rate = (*parent_rate * |
406 | (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16); |
407 | } else { |
408 | rate = *parent_rate * vc3->div_int; |
409 | } |
410 | |
411 | return rate; |
412 | } |
413 | |
414 | static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
415 | unsigned long parent_rate) |
416 | { |
417 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
418 | const struct vc3_pll_data *pll = vc3->data; |
419 | u32 val; |
420 | |
421 | regmap_read(map: vc3->regmap, reg: pll->int_div_msb_offs, val: &val); |
422 | val = (val & 0xf8) | ((vc3->div_int >> 8) & 0x7); |
423 | regmap_write(map: vc3->regmap, reg: pll->int_div_msb_offs, val); |
424 | regmap_write(map: vc3->regmap, reg: pll->int_div_lsb_offs, val: vc3->div_int & 0xff); |
425 | |
426 | if (pll->num == VC3_PLL2) { |
427 | regmap_write(map: vc3->regmap, VC3_PLL2_FB_FRC_DIV_MSB, |
428 | val: vc3->div_frc >> 8); |
429 | regmap_write(map: vc3->regmap, VC3_PLL2_FB_FRC_DIV_LSB, |
430 | val: vc3->div_frc & 0xff); |
431 | } |
432 | |
433 | return 0; |
434 | } |
435 | |
436 | static const struct clk_ops vc3_pll_ops = { |
437 | .recalc_rate = vc3_pll_recalc_rate, |
438 | .round_rate = vc3_pll_round_rate, |
439 | .set_rate = vc3_pll_set_rate, |
440 | }; |
441 | |
442 | static u8 vc3_div_mux_get_parent(struct clk_hw *hw) |
443 | { |
444 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
445 | const struct vc3_clk_data *div_mux = vc3->data; |
446 | u32 src; |
447 | |
448 | regmap_read(map: vc3->regmap, reg: div_mux->offs, val: &src); |
449 | |
450 | return !!(src & div_mux->bitmsk); |
451 | } |
452 | |
453 | static int vc3_div_mux_set_parent(struct clk_hw *hw, u8 index) |
454 | { |
455 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
456 | const struct vc3_clk_data *div_mux = vc3->data; |
457 | |
458 | return regmap_update_bits(map: vc3->regmap, reg: div_mux->offs, mask: div_mux->bitmsk, |
459 | val: index ? div_mux->bitmsk : 0); |
460 | } |
461 | |
462 | static const struct clk_ops vc3_div_mux_ops = { |
463 | .determine_rate = clk_hw_determine_rate_no_reparent, |
464 | .set_parent = vc3_div_mux_set_parent, |
465 | .get_parent = vc3_div_mux_get_parent, |
466 | }; |
467 | |
468 | static unsigned int vc3_get_div(const struct clk_div_table *table, |
469 | unsigned int val, unsigned long flag) |
470 | { |
471 | const struct clk_div_table *clkt; |
472 | |
473 | for (clkt = table; clkt->div; clkt++) |
474 | if (clkt->val == val) |
475 | return clkt->div; |
476 | |
477 | return 1; |
478 | } |
479 | |
480 | static unsigned long vc3_div_recalc_rate(struct clk_hw *hw, |
481 | unsigned long parent_rate) |
482 | { |
483 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
484 | const struct vc3_div_data *div_data = vc3->data; |
485 | unsigned int val; |
486 | |
487 | regmap_read(map: vc3->regmap, reg: div_data->offs, val: &val); |
488 | val >>= div_data->shift; |
489 | val &= VC3_DIV_MASK(div_data->width); |
490 | |
491 | return divider_recalc_rate(hw, parent_rate, val, table: div_data->table, |
492 | flags: div_data->flags, width: div_data->width); |
493 | } |
494 | |
495 | static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate, |
496 | unsigned long *parent_rate) |
497 | { |
498 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
499 | const struct vc3_div_data *div_data = vc3->data; |
500 | unsigned int bestdiv; |
501 | |
502 | /* if read only, just return current value */ |
503 | if (div_data->flags & CLK_DIVIDER_READ_ONLY) { |
504 | regmap_read(map: vc3->regmap, reg: div_data->offs, val: &bestdiv); |
505 | bestdiv >>= div_data->shift; |
506 | bestdiv &= VC3_DIV_MASK(div_data->width); |
507 | bestdiv = vc3_get_div(table: div_data->table, val: bestdiv, flag: div_data->flags); |
508 | return DIV_ROUND_UP(*parent_rate, bestdiv); |
509 | } |
510 | |
511 | return divider_round_rate(hw, rate, prate: parent_rate, table: div_data->table, |
512 | width: div_data->width, flags: div_data->flags); |
513 | } |
514 | |
515 | static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, |
516 | unsigned long parent_rate) |
517 | { |
518 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
519 | const struct vc3_div_data *div_data = vc3->data; |
520 | unsigned int value; |
521 | |
522 | value = divider_get_val(rate, parent_rate, table: div_data->table, |
523 | width: div_data->width, flags: div_data->flags); |
524 | return regmap_update_bits(map: vc3->regmap, reg: div_data->offs, |
525 | VC3_DIV_MASK(div_data->width) << div_data->shift, |
526 | val: value << div_data->shift); |
527 | } |
528 | |
529 | static const struct clk_ops vc3_div_ops = { |
530 | .recalc_rate = vc3_div_recalc_rate, |
531 | .round_rate = vc3_div_round_rate, |
532 | .set_rate = vc3_div_set_rate, |
533 | }; |
534 | |
535 | static int vc3_clk_mux_determine_rate(struct clk_hw *hw, |
536 | struct clk_rate_request *req) |
537 | { |
538 | int frc; |
539 | |
540 | if (clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT)) { |
541 | /* The below check is equivalent to (best_parent_rate/rate) */ |
542 | if (req->best_parent_rate >= req->rate) { |
543 | frc = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate, |
544 | req->rate); |
545 | req->rate *= frc; |
546 | return clk_mux_determine_rate_flags(hw, req, |
547 | CLK_SET_RATE_PARENT); |
548 | } |
549 | } |
550 | |
551 | return 0; |
552 | } |
553 | |
554 | static u8 vc3_clk_mux_get_parent(struct clk_hw *hw) |
555 | { |
556 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
557 | const struct vc3_clk_data *clk_mux = vc3->data; |
558 | u32 val; |
559 | |
560 | regmap_read(map: vc3->regmap, reg: clk_mux->offs, val: &val); |
561 | |
562 | return !!(val & clk_mux->bitmsk); |
563 | } |
564 | |
565 | static int vc3_clk_mux_set_parent(struct clk_hw *hw, u8 index) |
566 | { |
567 | struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); |
568 | const struct vc3_clk_data *clk_mux = vc3->data; |
569 | |
570 | return regmap_update_bits(map: vc3->regmap, reg: clk_mux->offs, mask: clk_mux->bitmsk, |
571 | val: index ? clk_mux->bitmsk : 0); |
572 | } |
573 | |
574 | static const struct clk_ops vc3_clk_mux_ops = { |
575 | .determine_rate = vc3_clk_mux_determine_rate, |
576 | .set_parent = vc3_clk_mux_set_parent, |
577 | .get_parent = vc3_clk_mux_get_parent, |
578 | }; |
579 | |
580 | static const struct regmap_config vc3_regmap_config = { |
581 | .reg_bits = 8, |
582 | .val_bits = 8, |
583 | .cache_type = REGCACHE_MAPLE, |
584 | .max_register = 0x24, |
585 | }; |
586 | |
587 | static struct vc3_hw_data clk_div[5]; |
588 | |
589 | static const struct clk_parent_data pfd_mux_parent_data[] = { |
590 | { .index = 0, }, |
591 | { .hw = &clk_div[VC3_DIV2].hw } |
592 | }; |
593 | |
594 | static struct vc3_hw_data clk_pfd_mux[] = { |
595 | [VC3_PFD2_MUX] = { |
596 | .data = &(struct vc3_clk_data) { |
597 | .offs = VC3_PLL_OP_CTRL, |
598 | .bitmsk = BIT(VC3_PLL_OP_CTRL_PLL2_REFIN_SEL) |
599 | }, |
600 | .hw.init = &(struct clk_init_data) { |
601 | .name = "pfd2_mux" , |
602 | .ops = &vc3_pfd_mux_ops, |
603 | .parent_data = pfd_mux_parent_data, |
604 | .num_parents = 2, |
605 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
606 | } |
607 | }, |
608 | [VC3_PFD3_MUX] = { |
609 | .data = &(struct vc3_clk_data) { |
610 | .offs = VC3_GENERAL_CTR, |
611 | .bitmsk = BIT(VC3_GENERAL_CTR_PLL3_REFIN_SEL) |
612 | }, |
613 | .hw.init = &(struct clk_init_data) { |
614 | .name = "pfd3_mux" , |
615 | .ops = &vc3_pfd_mux_ops, |
616 | .parent_data = pfd_mux_parent_data, |
617 | .num_parents = 2, |
618 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
619 | } |
620 | } |
621 | }; |
622 | |
623 | static struct vc3_hw_data clk_pfd[] = { |
624 | [VC3_PFD1] = { |
625 | .data = &(struct vc3_pfd_data) { |
626 | .num = VC3_PFD1, |
627 | .offs = VC3_PLL1_M_DIVIDER, |
628 | .mdiv1_bitmsk = VC3_PLL1_M_DIV1, |
629 | .mdiv2_bitmsk = VC3_PLL1_M_DIV2 |
630 | }, |
631 | .hw.init = &(struct clk_init_data) { |
632 | .name = "pfd1" , |
633 | .ops = &vc3_pfd_ops, |
634 | .parent_data = &(const struct clk_parent_data) { |
635 | .index = 0 |
636 | }, |
637 | .num_parents = 1, |
638 | .flags = CLK_SET_RATE_PARENT |
639 | } |
640 | }, |
641 | [VC3_PFD2] = { |
642 | .data = &(struct vc3_pfd_data) { |
643 | .num = VC3_PFD2, |
644 | .offs = VC3_PLL2_M_DIVIDER, |
645 | .mdiv1_bitmsk = VC3_PLL2_M_DIV1, |
646 | .mdiv2_bitmsk = VC3_PLL2_M_DIV2 |
647 | }, |
648 | .hw.init = &(struct clk_init_data) { |
649 | .name = "pfd2" , |
650 | .ops = &vc3_pfd_ops, |
651 | .parent_hws = (const struct clk_hw *[]) { |
652 | &clk_pfd_mux[VC3_PFD2_MUX].hw |
653 | }, |
654 | .num_parents = 1, |
655 | .flags = CLK_SET_RATE_PARENT |
656 | } |
657 | }, |
658 | [VC3_PFD3] = { |
659 | .data = &(struct vc3_pfd_data) { |
660 | .num = VC3_PFD3, |
661 | .offs = VC3_PLL3_M_DIVIDER, |
662 | .mdiv1_bitmsk = VC3_PLL3_M_DIV1, |
663 | .mdiv2_bitmsk = VC3_PLL3_M_DIV2 |
664 | }, |
665 | .hw.init = &(struct clk_init_data) { |
666 | .name = "pfd3" , |
667 | .ops = &vc3_pfd_ops, |
668 | .parent_hws = (const struct clk_hw *[]) { |
669 | &clk_pfd_mux[VC3_PFD3_MUX].hw |
670 | }, |
671 | .num_parents = 1, |
672 | .flags = CLK_SET_RATE_PARENT |
673 | } |
674 | } |
675 | }; |
676 | |
677 | static struct vc3_hw_data clk_pll[] = { |
678 | [VC3_PLL1] = { |
679 | .data = &(struct vc3_pll_data) { |
680 | .num = VC3_PLL1, |
681 | .int_div_msb_offs = VC3_PLL1_LOOP_FILTER_N_DIV_MSB, |
682 | .int_div_lsb_offs = VC3_PLL1_VCO_N_DIVIDER, |
683 | .vco_min = VC3_PLL1_VCO_MIN, |
684 | .vco_max = VC3_PLL1_VCO_MAX |
685 | }, |
686 | .hw.init = &(struct clk_init_data) { |
687 | .name = "pll1" , |
688 | .ops = &vc3_pll_ops, |
689 | .parent_hws = (const struct clk_hw *[]) { |
690 | &clk_pfd[VC3_PFD1].hw |
691 | }, |
692 | .num_parents = 1, |
693 | .flags = CLK_SET_RATE_PARENT |
694 | } |
695 | }, |
696 | [VC3_PLL2] = { |
697 | .data = &(struct vc3_pll_data) { |
698 | .num = VC3_PLL2, |
699 | .int_div_msb_offs = VC3_PLL2_FB_INT_DIV_MSB, |
700 | .int_div_lsb_offs = VC3_PLL2_FB_INT_DIV_LSB, |
701 | .vco_min = VC3_PLL2_VCO_MIN, |
702 | .vco_max = VC3_PLL2_VCO_MAX |
703 | }, |
704 | .hw.init = &(struct clk_init_data) { |
705 | .name = "pll2" , |
706 | .ops = &vc3_pll_ops, |
707 | .parent_hws = (const struct clk_hw *[]) { |
708 | &clk_pfd[VC3_PFD2].hw |
709 | }, |
710 | .num_parents = 1, |
711 | .flags = CLK_SET_RATE_PARENT |
712 | } |
713 | }, |
714 | [VC3_PLL3] = { |
715 | .data = &(struct vc3_pll_data) { |
716 | .num = VC3_PLL3, |
717 | .int_div_msb_offs = VC3_PLL3_LOOP_FILTER_N_DIV_MSB, |
718 | .int_div_lsb_offs = VC3_PLL3_N_DIVIDER, |
719 | .vco_min = VC3_PLL3_VCO_MIN, |
720 | .vco_max = VC3_PLL3_VCO_MAX |
721 | }, |
722 | .hw.init = &(struct clk_init_data) { |
723 | .name = "pll3" , |
724 | .ops = &vc3_pll_ops, |
725 | .parent_hws = (const struct clk_hw *[]) { |
726 | &clk_pfd[VC3_PFD3].hw |
727 | }, |
728 | .num_parents = 1, |
729 | .flags = CLK_SET_RATE_PARENT |
730 | } |
731 | } |
732 | }; |
733 | |
734 | static const struct clk_parent_data div_mux_parent_data[][2] = { |
735 | [VC3_DIV1_MUX] = { |
736 | { .hw = &clk_pll[VC3_PLL1].hw }, |
737 | { .index = 0 } |
738 | }, |
739 | [VC3_DIV3_MUX] = { |
740 | { .hw = &clk_pll[VC3_PLL2].hw }, |
741 | { .hw = &clk_pll[VC3_PLL3].hw } |
742 | }, |
743 | [VC3_DIV4_MUX] = { |
744 | { .hw = &clk_pll[VC3_PLL2].hw }, |
745 | { .index = 0 } |
746 | } |
747 | }; |
748 | |
749 | static struct vc3_hw_data clk_div_mux[] = { |
750 | [VC3_DIV1_MUX] = { |
751 | .data = &(struct vc3_clk_data) { |
752 | .offs = VC3_GENERAL_CTR, |
753 | .bitmsk = VC3_GENERAL_CTR_DIV1_SRC_SEL |
754 | }, |
755 | .hw.init = &(struct clk_init_data) { |
756 | .name = "div1_mux" , |
757 | .ops = &vc3_div_mux_ops, |
758 | .parent_data = div_mux_parent_data[VC3_DIV1_MUX], |
759 | .num_parents = 2, |
760 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
761 | } |
762 | }, |
763 | [VC3_DIV3_MUX] = { |
764 | .data = &(struct vc3_clk_data) { |
765 | .offs = VC3_PLL3_CHARGE_PUMP_CTRL, |
766 | .bitmsk = VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL |
767 | }, |
768 | .hw.init = &(struct clk_init_data) { |
769 | .name = "div3_mux" , |
770 | .ops = &vc3_div_mux_ops, |
771 | .parent_data = div_mux_parent_data[VC3_DIV3_MUX], |
772 | .num_parents = 2, |
773 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
774 | } |
775 | }, |
776 | [VC3_DIV4_MUX] = { |
777 | .data = &(struct vc3_clk_data) { |
778 | .offs = VC3_OUTPUT_CTR, |
779 | .bitmsk = VC3_OUTPUT_CTR_DIV4_SRC_SEL |
780 | }, |
781 | .hw.init = &(struct clk_init_data) { |
782 | .name = "div4_mux" , |
783 | .ops = &vc3_div_mux_ops, |
784 | .parent_data = div_mux_parent_data[VC3_DIV4_MUX], |
785 | .num_parents = 2, |
786 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT |
787 | } |
788 | } |
789 | }; |
790 | |
791 | static struct vc3_hw_data clk_div[] = { |
792 | [VC3_DIV1] = { |
793 | .data = &(struct vc3_div_data) { |
794 | .offs = VC3_OUT_DIV1_DIV2_CTRL, |
795 | .table = div1_divs, |
796 | .shift = 4, |
797 | .width = 4, |
798 | .flags = CLK_DIVIDER_READ_ONLY |
799 | }, |
800 | .hw.init = &(struct clk_init_data) { |
801 | .name = "div1" , |
802 | .ops = &vc3_div_ops, |
803 | .parent_hws = (const struct clk_hw *[]) { |
804 | &clk_div_mux[VC3_DIV1_MUX].hw |
805 | }, |
806 | .num_parents = 1, |
807 | .flags = CLK_SET_RATE_PARENT |
808 | } |
809 | }, |
810 | [VC3_DIV2] = { |
811 | .data = &(struct vc3_div_data) { |
812 | .offs = VC3_OUT_DIV1_DIV2_CTRL, |
813 | .table = div245_divs, |
814 | .shift = 0, |
815 | .width = 4, |
816 | .flags = CLK_DIVIDER_READ_ONLY |
817 | }, |
818 | .hw.init = &(struct clk_init_data) { |
819 | .name = "div2" , |
820 | .ops = &vc3_div_ops, |
821 | .parent_hws = (const struct clk_hw *[]) { |
822 | &clk_pll[VC3_PLL1].hw |
823 | }, |
824 | .num_parents = 1, |
825 | .flags = CLK_SET_RATE_PARENT |
826 | } |
827 | }, |
828 | [VC3_DIV3] = { |
829 | .data = &(struct vc3_div_data) { |
830 | .offs = VC3_OUT_DIV3_DIV4_CTRL, |
831 | .table = div3_divs, |
832 | .shift = 4, |
833 | .width = 4, |
834 | .flags = CLK_DIVIDER_READ_ONLY |
835 | }, |
836 | .hw.init = &(struct clk_init_data) { |
837 | .name = "div3" , |
838 | .ops = &vc3_div_ops, |
839 | .parent_hws = (const struct clk_hw *[]) { |
840 | &clk_div_mux[VC3_DIV3_MUX].hw |
841 | }, |
842 | .num_parents = 1, |
843 | .flags = CLK_SET_RATE_PARENT |
844 | } |
845 | }, |
846 | [VC3_DIV4] = { |
847 | .data = &(struct vc3_div_data) { |
848 | .offs = VC3_OUT_DIV3_DIV4_CTRL, |
849 | .table = div245_divs, |
850 | .shift = 0, |
851 | .width = 4, |
852 | .flags = CLK_DIVIDER_READ_ONLY |
853 | }, |
854 | .hw.init = &(struct clk_init_data) { |
855 | .name = "div4" , |
856 | .ops = &vc3_div_ops, |
857 | .parent_hws = (const struct clk_hw *[]) { |
858 | &clk_div_mux[VC3_DIV4_MUX].hw |
859 | }, |
860 | .num_parents = 1, |
861 | .flags = CLK_SET_RATE_PARENT |
862 | } |
863 | }, |
864 | [VC3_DIV5] = { |
865 | .data = &(struct vc3_div_data) { |
866 | .offs = VC3_PLL1_CTRL_OUTDIV5, |
867 | .table = div245_divs, |
868 | .shift = 0, |
869 | .width = 4, |
870 | .flags = CLK_DIVIDER_READ_ONLY |
871 | }, |
872 | .hw.init = &(struct clk_init_data) { |
873 | .name = "div5" , |
874 | .ops = &vc3_div_ops, |
875 | .parent_hws = (const struct clk_hw *[]) { |
876 | &clk_pll[VC3_PLL3].hw |
877 | }, |
878 | .num_parents = 1, |
879 | .flags = CLK_SET_RATE_PARENT |
880 | } |
881 | } |
882 | }; |
883 | |
884 | static struct vc3_hw_data clk_mux[] = { |
885 | [VC3_SE1_MUX] = { |
886 | .data = &(struct vc3_clk_data) { |
887 | .offs = VC3_SE1_DIV4_CTRL, |
888 | .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL |
889 | }, |
890 | .hw.init = &(struct clk_init_data) { |
891 | .name = "se1_mux" , |
892 | .ops = &vc3_clk_mux_ops, |
893 | .parent_hws = (const struct clk_hw *[]) { |
894 | &clk_div[VC3_DIV5].hw, |
895 | &clk_div[VC3_DIV4].hw |
896 | }, |
897 | .num_parents = 2, |
898 | .flags = CLK_SET_RATE_PARENT |
899 | } |
900 | }, |
901 | [VC3_SE2_MUX] = { |
902 | .data = &(struct vc3_clk_data) { |
903 | .offs = VC3_SE2_CTRL_REG0, |
904 | .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL |
905 | }, |
906 | .hw.init = &(struct clk_init_data) { |
907 | .name = "se2_mux" , |
908 | .ops = &vc3_clk_mux_ops, |
909 | .parent_hws = (const struct clk_hw *[]) { |
910 | &clk_div[VC3_DIV5].hw, |
911 | &clk_div[VC3_DIV4].hw |
912 | }, |
913 | .num_parents = 2, |
914 | .flags = CLK_SET_RATE_PARENT |
915 | } |
916 | }, |
917 | [VC3_SE3_MUX] = { |
918 | .data = &(struct vc3_clk_data) { |
919 | .offs = VC3_SE3_DIFF1_CTRL_REG, |
920 | .bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL |
921 | }, |
922 | .hw.init = &(struct clk_init_data) { |
923 | .name = "se3_mux" , |
924 | .ops = &vc3_clk_mux_ops, |
925 | .parent_hws = (const struct clk_hw *[]) { |
926 | &clk_div[VC3_DIV2].hw, |
927 | &clk_div[VC3_DIV4].hw |
928 | }, |
929 | .num_parents = 2, |
930 | .flags = CLK_SET_RATE_PARENT |
931 | } |
932 | }, |
933 | [VC3_DIFF1_MUX] = { |
934 | .data = &(struct vc3_clk_data) { |
935 | .offs = VC3_DIFF1_CTRL_REG, |
936 | .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL |
937 | }, |
938 | .hw.init = &(struct clk_init_data) { |
939 | .name = "diff1_mux" , |
940 | .ops = &vc3_clk_mux_ops, |
941 | .parent_hws = (const struct clk_hw *[]) { |
942 | &clk_div[VC3_DIV1].hw, |
943 | &clk_div[VC3_DIV3].hw |
944 | }, |
945 | .num_parents = 2, |
946 | .flags = CLK_SET_RATE_PARENT |
947 | } |
948 | }, |
949 | [VC3_DIFF2_MUX] = { |
950 | .data = &(struct vc3_clk_data) { |
951 | .offs = VC3_DIFF2_CTRL_REG, |
952 | .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL |
953 | }, |
954 | .hw.init = &(struct clk_init_data) { |
955 | .name = "diff2_mux" , |
956 | .ops = &vc3_clk_mux_ops, |
957 | .parent_hws = (const struct clk_hw *[]) { |
958 | &clk_div[VC3_DIV1].hw, |
959 | &clk_div[VC3_DIV3].hw |
960 | }, |
961 | .num_parents = 2, |
962 | .flags = CLK_SET_RATE_PARENT |
963 | } |
964 | } |
965 | }; |
966 | |
967 | static struct clk_hw *vc3_of_clk_get(struct of_phandle_args *clkspec, |
968 | void *data) |
969 | { |
970 | unsigned int idx = clkspec->args[0]; |
971 | struct clk_hw **clkout_hw = data; |
972 | |
973 | if (idx >= ARRAY_SIZE(clk_out)) { |
974 | pr_err("invalid clk index %u for provider %pOF\n" , idx, clkspec->np); |
975 | return ERR_PTR(error: -EINVAL); |
976 | } |
977 | |
978 | return clkout_hw[idx]; |
979 | } |
980 | |
981 | static int vc3_probe(struct i2c_client *client) |
982 | { |
983 | struct device *dev = &client->dev; |
984 | u8 settings[NUM_CONFIG_REGISTERS]; |
985 | struct regmap *regmap; |
986 | const char *name; |
987 | int ret, i; |
988 | |
989 | regmap = devm_regmap_init_i2c(client, &vc3_regmap_config); |
990 | if (IS_ERR(ptr: regmap)) |
991 | return dev_err_probe(dev, err: PTR_ERR(ptr: regmap), |
992 | fmt: "failed to allocate register map\n" ); |
993 | |
994 | ret = of_property_read_u8_array(np: dev->of_node, propname: "renesas,settings" , |
995 | out_values: settings, ARRAY_SIZE(settings)); |
996 | if (!ret) { |
997 | /* |
998 | * A raw settings array was specified in the DT. Write the |
999 | * settings to the device immediately. |
1000 | */ |
1001 | for (i = 0; i < NUM_CONFIG_REGISTERS; i++) { |
1002 | ret = regmap_write(map: regmap, reg: i, val: settings[i]); |
1003 | if (ret) { |
1004 | dev_err(dev, "error writing to chip (%i)\n" , ret); |
1005 | return ret; |
1006 | } |
1007 | } |
1008 | } else if (ret == -EOVERFLOW) { |
1009 | dev_err(&client->dev, "EOVERFLOW reg settings. ARRAY_SIZE: %zu\n" , |
1010 | ARRAY_SIZE(settings)); |
1011 | return ret; |
1012 | } |
1013 | |
1014 | /* Register pfd muxes */ |
1015 | for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) { |
1016 | clk_pfd_mux[i].regmap = regmap; |
1017 | ret = devm_clk_hw_register(dev, hw: &clk_pfd_mux[i].hw); |
1018 | if (ret) |
1019 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1020 | clk_pfd_mux[i].hw.init->name); |
1021 | } |
1022 | |
1023 | /* Register pfd's */ |
1024 | for (i = 0; i < ARRAY_SIZE(clk_pfd); i++) { |
1025 | clk_pfd[i].regmap = regmap; |
1026 | ret = devm_clk_hw_register(dev, hw: &clk_pfd[i].hw); |
1027 | if (ret) |
1028 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1029 | clk_pfd[i].hw.init->name); |
1030 | } |
1031 | |
1032 | /* Register pll's */ |
1033 | for (i = 0; i < ARRAY_SIZE(clk_pll); i++) { |
1034 | clk_pll[i].regmap = regmap; |
1035 | ret = devm_clk_hw_register(dev, hw: &clk_pll[i].hw); |
1036 | if (ret) |
1037 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1038 | clk_pll[i].hw.init->name); |
1039 | } |
1040 | |
1041 | /* Register divider muxes */ |
1042 | for (i = 0; i < ARRAY_SIZE(clk_div_mux); i++) { |
1043 | clk_div_mux[i].regmap = regmap; |
1044 | ret = devm_clk_hw_register(dev, hw: &clk_div_mux[i].hw); |
1045 | if (ret) |
1046 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1047 | clk_div_mux[i].hw.init->name); |
1048 | } |
1049 | |
1050 | /* Register dividers */ |
1051 | for (i = 0; i < ARRAY_SIZE(clk_div); i++) { |
1052 | clk_div[i].regmap = regmap; |
1053 | ret = devm_clk_hw_register(dev, hw: &clk_div[i].hw); |
1054 | if (ret) |
1055 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1056 | clk_div[i].hw.init->name); |
1057 | } |
1058 | |
1059 | /* Register clk muxes */ |
1060 | for (i = 0; i < ARRAY_SIZE(clk_mux); i++) { |
1061 | clk_mux[i].regmap = regmap; |
1062 | ret = devm_clk_hw_register(dev, hw: &clk_mux[i].hw); |
1063 | if (ret) |
1064 | return dev_err_probe(dev, err: ret, fmt: "%s failed\n" , |
1065 | clk_mux[i].hw.init->name); |
1066 | } |
1067 | |
1068 | /* Register clk outputs */ |
1069 | for (i = 0; i < ARRAY_SIZE(clk_out); i++) { |
1070 | switch (i) { |
1071 | case VC3_DIFF2: |
1072 | name = "diff2" ; |
1073 | break; |
1074 | case VC3_DIFF1: |
1075 | name = "diff1" ; |
1076 | break; |
1077 | case VC3_SE3: |
1078 | name = "se3" ; |
1079 | break; |
1080 | case VC3_SE2: |
1081 | name = "se2" ; |
1082 | break; |
1083 | case VC3_SE1: |
1084 | name = "se1" ; |
1085 | break; |
1086 | case VC3_REF: |
1087 | name = "ref" ; |
1088 | break; |
1089 | default: |
1090 | return dev_err_probe(dev, err: -EINVAL, fmt: "invalid clk output %d\n" , i); |
1091 | } |
1092 | |
1093 | if (i == VC3_REF) |
1094 | clk_out[i] = devm_clk_hw_register_fixed_factor_index(dev, |
1095 | name, index: 0, CLK_SET_RATE_PARENT, mult: 1, div: 1); |
1096 | else |
1097 | clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev, |
1098 | name, parent_hw: &clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, mult: 1, div: 1); |
1099 | |
1100 | if (IS_ERR(ptr: clk_out[i])) |
1101 | return PTR_ERR(ptr: clk_out[i]); |
1102 | } |
1103 | |
1104 | ret = devm_of_clk_add_hw_provider(dev, get: vc3_of_clk_get, data: clk_out); |
1105 | if (ret) |
1106 | return dev_err_probe(dev, err: ret, fmt: "unable to add clk provider\n" ); |
1107 | |
1108 | return ret; |
1109 | } |
1110 | |
1111 | static const struct of_device_id dev_ids[] = { |
1112 | { .compatible = "renesas,5p35023" }, |
1113 | { /* Sentinel */ } |
1114 | }; |
1115 | MODULE_DEVICE_TABLE(of, dev_ids); |
1116 | |
1117 | static struct i2c_driver vc3_driver = { |
1118 | .driver = { |
1119 | .name = "vc3" , |
1120 | .of_match_table = of_match_ptr(dev_ids), |
1121 | }, |
1122 | .probe = vc3_probe, |
1123 | }; |
1124 | module_i2c_driver(vc3_driver); |
1125 | |
1126 | MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>" ); |
1127 | MODULE_DESCRIPTION("Renesas VersaClock 3 driver" ); |
1128 | MODULE_LICENSE("GPL" ); |
1129 | |