1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * TI CDCE706 programmable 3-PLL clock synthesizer driver |
4 | * |
5 | * Copyright (c) 2014 Cadence Design Systems Inc. |
6 | * |
7 | * Reference: https://www.ti.com/lit/ds/symlink/cdce706.pdf |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/mod_devicetable.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/rational.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/slab.h> |
21 | |
22 | #define CDCE706_CLKIN_CLOCK 10 |
23 | #define CDCE706_CLKIN_SOURCE 11 |
24 | #define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll)) |
25 | #define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll)) |
26 | #define CDCE706_PLL_HI(pll) (3 + 3 * (pll)) |
27 | #define CDCE706_PLL_MUX 3 |
28 | #define CDCE706_PLL_FVCO 6 |
29 | #define CDCE706_DIVIDER(div) (13 + (div)) |
30 | #define CDCE706_CLKOUT(out) (19 + (out)) |
31 | |
32 | #define CDCE706_CLKIN_CLOCK_MASK 0x10 |
33 | #define CDCE706_CLKIN_SOURCE_SHIFT 6 |
34 | #define CDCE706_CLKIN_SOURCE_MASK 0xc0 |
35 | #define CDCE706_CLKIN_SOURCE_LVCMOS 0x40 |
36 | |
37 | #define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll)) |
38 | #define CDCE706_PLL_LOW_M_MASK 0xff |
39 | #define CDCE706_PLL_LOW_N_MASK 0xff |
40 | #define CDCE706_PLL_HI_M_MASK 0x1 |
41 | #define CDCE706_PLL_HI_N_MASK 0x1e |
42 | #define CDCE706_PLL_HI_N_SHIFT 1 |
43 | #define CDCE706_PLL_M_MAX 0x1ff |
44 | #define CDCE706_PLL_N_MAX 0xfff |
45 | #define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll)) |
46 | #define CDCE706_PLL_FREQ_MIN 80000000 |
47 | #define CDCE706_PLL_FREQ_MAX 300000000 |
48 | #define CDCE706_PLL_FREQ_HI 180000000 |
49 | |
50 | #define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4)) |
51 | #define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1)) |
52 | #define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div)) |
53 | #define CDCE706_DIVIDER_DIVIDER_MASK 0x7f |
54 | #define CDCE706_DIVIDER_DIVIDER_MAX 0x7f |
55 | |
56 | #define CDCE706_CLKOUT_DIVIDER_MASK 0x7 |
57 | #define CDCE706_CLKOUT_ENABLE_MASK 0x8 |
58 | |
59 | static const struct regmap_config cdce706_regmap_config = { |
60 | .reg_bits = 8, |
61 | .val_bits = 8, |
62 | .val_format_endian = REGMAP_ENDIAN_NATIVE, |
63 | }; |
64 | |
65 | #define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw)) |
66 | |
67 | struct cdce706_hw_data { |
68 | struct cdce706_dev_data *dev_data; |
69 | unsigned idx; |
70 | unsigned parent; |
71 | struct clk_hw hw; |
72 | unsigned div; |
73 | unsigned mul; |
74 | unsigned mux; |
75 | }; |
76 | |
77 | struct cdce706_dev_data { |
78 | struct i2c_client *client; |
79 | struct regmap *regmap; |
80 | struct clk *clkin_clk[2]; |
81 | const char *clkin_name[2]; |
82 | struct cdce706_hw_data clkin[1]; |
83 | struct cdce706_hw_data pll[3]; |
84 | struct cdce706_hw_data divider[6]; |
85 | struct cdce706_hw_data clkout[6]; |
86 | }; |
87 | |
88 | static const char * const cdce706_source_name[] = { |
89 | "clk_in0" , "clk_in1" , |
90 | }; |
91 | |
92 | static const char * const cdce706_clkin_name[] = { |
93 | "clk_in" , |
94 | }; |
95 | |
96 | static const char * const cdce706_pll_name[] = { |
97 | "pll1" , "pll2" , "pll3" , |
98 | }; |
99 | |
100 | static const char * const cdce706_divider_parent_name[] = { |
101 | "clk_in" , "pll1" , "pll2" , "pll2" , "pll3" , |
102 | }; |
103 | |
104 | static const char *cdce706_divider_name[] = { |
105 | "p0" , "p1" , "p2" , "p3" , "p4" , "p5" , |
106 | }; |
107 | |
108 | static const char * const cdce706_clkout_name[] = { |
109 | "clk_out0" , "clk_out1" , "clk_out2" , "clk_out3" , "clk_out4" , "clk_out5" , |
110 | }; |
111 | |
112 | static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg, |
113 | unsigned *val) |
114 | { |
115 | int rc = regmap_read(map: dev_data->regmap, reg: reg | 0x80, val); |
116 | |
117 | if (rc < 0) |
118 | dev_err(&dev_data->client->dev, "error reading reg %u" , reg); |
119 | return rc; |
120 | } |
121 | |
122 | static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg, |
123 | unsigned val) |
124 | { |
125 | int rc = regmap_write(map: dev_data->regmap, reg: reg | 0x80, val); |
126 | |
127 | if (rc < 0) |
128 | dev_err(&dev_data->client->dev, "error writing reg %u" , reg); |
129 | return rc; |
130 | } |
131 | |
132 | static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg, |
133 | unsigned mask, unsigned val) |
134 | { |
135 | int rc = regmap_update_bits(map: dev_data->regmap, reg: reg | 0x80, mask, val); |
136 | |
137 | if (rc < 0) |
138 | dev_err(&dev_data->client->dev, "error updating reg %u" , reg); |
139 | return rc; |
140 | } |
141 | |
142 | static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index) |
143 | { |
144 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
145 | |
146 | hwd->parent = index; |
147 | return 0; |
148 | } |
149 | |
150 | static u8 cdce706_clkin_get_parent(struct clk_hw *hw) |
151 | { |
152 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
153 | |
154 | return hwd->parent; |
155 | } |
156 | |
157 | static const struct clk_ops cdce706_clkin_ops = { |
158 | .determine_rate = clk_hw_determine_rate_no_reparent, |
159 | .set_parent = cdce706_clkin_set_parent, |
160 | .get_parent = cdce706_clkin_get_parent, |
161 | }; |
162 | |
163 | static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw, |
164 | unsigned long parent_rate) |
165 | { |
166 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
167 | |
168 | dev_dbg(&hwd->dev_data->client->dev, |
169 | "%s, pll: %d, mux: %d, mul: %u, div: %u\n" , |
170 | __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div); |
171 | |
172 | if (!hwd->mux) { |
173 | if (hwd->div && hwd->mul) { |
174 | u64 res = (u64)parent_rate * hwd->mul; |
175 | |
176 | do_div(res, hwd->div); |
177 | return res; |
178 | } |
179 | } else { |
180 | if (hwd->div) |
181 | return parent_rate / hwd->div; |
182 | } |
183 | return 0; |
184 | } |
185 | |
186 | static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
187 | unsigned long *parent_rate) |
188 | { |
189 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
190 | unsigned long mul, div; |
191 | u64 res; |
192 | |
193 | dev_dbg(&hwd->dev_data->client->dev, |
194 | "%s, rate: %lu, parent_rate: %lu\n" , |
195 | __func__, rate, *parent_rate); |
196 | |
197 | rational_best_approximation(given_numerator: rate, given_denominator: *parent_rate, |
198 | CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX, |
199 | best_numerator: &mul, best_denominator: &div); |
200 | hwd->mul = mul; |
201 | hwd->div = div; |
202 | |
203 | dev_dbg(&hwd->dev_data->client->dev, |
204 | "%s, pll: %d, mul: %lu, div: %lu\n" , |
205 | __func__, hwd->idx, mul, div); |
206 | |
207 | res = (u64)*parent_rate * hwd->mul; |
208 | do_div(res, hwd->div); |
209 | return res; |
210 | } |
211 | |
212 | static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
213 | unsigned long parent_rate) |
214 | { |
215 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
216 | unsigned long mul = hwd->mul, div = hwd->div; |
217 | int err; |
218 | |
219 | dev_dbg(&hwd->dev_data->client->dev, |
220 | "%s, pll: %d, mul: %lu, div: %lu\n" , |
221 | __func__, hwd->idx, mul, div); |
222 | |
223 | err = cdce706_reg_update(dev_data: hwd->dev_data, |
224 | CDCE706_PLL_HI(hwd->idx), |
225 | CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK, |
226 | val: ((div >> 8) & CDCE706_PLL_HI_M_MASK) | |
227 | ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) & |
228 | CDCE706_PLL_HI_N_MASK)); |
229 | if (err < 0) |
230 | return err; |
231 | |
232 | err = cdce706_reg_write(dev_data: hwd->dev_data, |
233 | CDCE706_PLL_M_LOW(hwd->idx), |
234 | val: div & CDCE706_PLL_LOW_M_MASK); |
235 | if (err < 0) |
236 | return err; |
237 | |
238 | err = cdce706_reg_write(dev_data: hwd->dev_data, |
239 | CDCE706_PLL_N_LOW(hwd->idx), |
240 | val: mul & CDCE706_PLL_LOW_N_MASK); |
241 | if (err < 0) |
242 | return err; |
243 | |
244 | err = cdce706_reg_update(dev_data: hwd->dev_data, |
245 | CDCE706_PLL_FVCO, |
246 | CDCE706_PLL_FVCO_MASK(hwd->idx), |
247 | val: rate > CDCE706_PLL_FREQ_HI ? |
248 | CDCE706_PLL_FVCO_MASK(hwd->idx) : 0); |
249 | return err; |
250 | } |
251 | |
252 | static const struct clk_ops cdce706_pll_ops = { |
253 | .recalc_rate = cdce706_pll_recalc_rate, |
254 | .round_rate = cdce706_pll_round_rate, |
255 | .set_rate = cdce706_pll_set_rate, |
256 | }; |
257 | |
258 | static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index) |
259 | { |
260 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
261 | |
262 | if (hwd->parent == index) |
263 | return 0; |
264 | hwd->parent = index; |
265 | return cdce706_reg_update(dev_data: hwd->dev_data, |
266 | CDCE706_DIVIDER_PLL(hwd->idx), |
267 | CDCE706_DIVIDER_PLL_MASK(hwd->idx), |
268 | val: index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx)); |
269 | } |
270 | |
271 | static u8 cdce706_divider_get_parent(struct clk_hw *hw) |
272 | { |
273 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
274 | |
275 | return hwd->parent; |
276 | } |
277 | |
278 | static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw, |
279 | unsigned long parent_rate) |
280 | { |
281 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
282 | |
283 | dev_dbg(&hwd->dev_data->client->dev, |
284 | "%s, divider: %d, div: %u\n" , |
285 | __func__, hwd->idx, hwd->div); |
286 | if (hwd->div) |
287 | return parent_rate / hwd->div; |
288 | return 0; |
289 | } |
290 | |
291 | static int cdce706_divider_determine_rate(struct clk_hw *hw, |
292 | struct clk_rate_request *req) |
293 | { |
294 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
295 | struct cdce706_dev_data *cdce = hwd->dev_data; |
296 | unsigned long rate = req->rate; |
297 | unsigned long mul, div; |
298 | |
299 | dev_dbg(&hwd->dev_data->client->dev, |
300 | "%s, rate: %lu, parent_rate: %lu\n" , |
301 | __func__, rate, req->best_parent_rate); |
302 | |
303 | rational_best_approximation(given_numerator: rate, given_denominator: req->best_parent_rate, |
304 | max_numerator: 1, CDCE706_DIVIDER_DIVIDER_MAX, |
305 | best_numerator: &mul, best_denominator: &div); |
306 | if (!mul) |
307 | div = CDCE706_DIVIDER_DIVIDER_MAX; |
308 | |
309 | if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { |
310 | unsigned long best_diff = rate; |
311 | unsigned long best_div = 0; |
312 | struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent]; |
313 | unsigned long gp_rate = gp_clk ? clk_get_rate(clk: gp_clk) : 0; |
314 | |
315 | for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff && |
316 | div <= CDCE706_PLL_FREQ_MAX / rate; ++div) { |
317 | unsigned long n, m; |
318 | unsigned long diff; |
319 | unsigned long div_rate; |
320 | u64 div_rate64; |
321 | |
322 | if (rate * div < CDCE706_PLL_FREQ_MIN) |
323 | continue; |
324 | |
325 | rational_best_approximation(given_numerator: rate * div, given_denominator: gp_rate, |
326 | CDCE706_PLL_N_MAX, |
327 | CDCE706_PLL_M_MAX, |
328 | best_numerator: &n, best_denominator: &m); |
329 | div_rate64 = (u64)gp_rate * n; |
330 | do_div(div_rate64, m); |
331 | do_div(div_rate64, div); |
332 | div_rate = div_rate64; |
333 | diff = max(div_rate, rate) - min(div_rate, rate); |
334 | |
335 | if (diff < best_diff) { |
336 | best_diff = diff; |
337 | best_div = div; |
338 | dev_dbg(&hwd->dev_data->client->dev, |
339 | "%s, %lu * %lu / %lu / %lu = %lu\n" , |
340 | __func__, gp_rate, n, m, div, div_rate); |
341 | } |
342 | } |
343 | |
344 | div = best_div; |
345 | |
346 | dev_dbg(&hwd->dev_data->client->dev, |
347 | "%s, altering parent rate: %lu -> %lu\n" , |
348 | __func__, req->best_parent_rate, rate * div); |
349 | req->best_parent_rate = rate * div; |
350 | } |
351 | hwd->div = div; |
352 | |
353 | dev_dbg(&hwd->dev_data->client->dev, |
354 | "%s, divider: %d, div: %lu\n" , |
355 | __func__, hwd->idx, div); |
356 | |
357 | req->rate = req->best_parent_rate / div; |
358 | return 0; |
359 | } |
360 | |
361 | static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
362 | unsigned long parent_rate) |
363 | { |
364 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
365 | |
366 | dev_dbg(&hwd->dev_data->client->dev, |
367 | "%s, divider: %d, div: %u\n" , |
368 | __func__, hwd->idx, hwd->div); |
369 | |
370 | return cdce706_reg_update(dev_data: hwd->dev_data, |
371 | CDCE706_DIVIDER(hwd->idx), |
372 | CDCE706_DIVIDER_DIVIDER_MASK, |
373 | val: hwd->div); |
374 | } |
375 | |
376 | static const struct clk_ops cdce706_divider_ops = { |
377 | .set_parent = cdce706_divider_set_parent, |
378 | .get_parent = cdce706_divider_get_parent, |
379 | .recalc_rate = cdce706_divider_recalc_rate, |
380 | .determine_rate = cdce706_divider_determine_rate, |
381 | .set_rate = cdce706_divider_set_rate, |
382 | }; |
383 | |
384 | static int cdce706_clkout_prepare(struct clk_hw *hw) |
385 | { |
386 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
387 | |
388 | return cdce706_reg_update(dev_data: hwd->dev_data, CDCE706_CLKOUT(hwd->idx), |
389 | CDCE706_CLKOUT_ENABLE_MASK, |
390 | CDCE706_CLKOUT_ENABLE_MASK); |
391 | } |
392 | |
393 | static void cdce706_clkout_unprepare(struct clk_hw *hw) |
394 | { |
395 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
396 | |
397 | cdce706_reg_update(dev_data: hwd->dev_data, CDCE706_CLKOUT(hwd->idx), |
398 | CDCE706_CLKOUT_ENABLE_MASK, val: 0); |
399 | } |
400 | |
401 | static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index) |
402 | { |
403 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
404 | |
405 | if (hwd->parent == index) |
406 | return 0; |
407 | hwd->parent = index; |
408 | return cdce706_reg_update(dev_data: hwd->dev_data, |
409 | CDCE706_CLKOUT(hwd->idx), |
410 | CDCE706_CLKOUT_ENABLE_MASK, val: index); |
411 | } |
412 | |
413 | static u8 cdce706_clkout_get_parent(struct clk_hw *hw) |
414 | { |
415 | struct cdce706_hw_data *hwd = to_hw_data(hw); |
416 | |
417 | return hwd->parent; |
418 | } |
419 | |
420 | static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw, |
421 | unsigned long parent_rate) |
422 | { |
423 | return parent_rate; |
424 | } |
425 | |
426 | static int cdce706_clkout_determine_rate(struct clk_hw *hw, |
427 | struct clk_rate_request *req) |
428 | { |
429 | req->best_parent_rate = req->rate; |
430 | |
431 | return 0; |
432 | } |
433 | |
434 | static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate, |
435 | unsigned long parent_rate) |
436 | { |
437 | return 0; |
438 | } |
439 | |
440 | static const struct clk_ops cdce706_clkout_ops = { |
441 | .prepare = cdce706_clkout_prepare, |
442 | .unprepare = cdce706_clkout_unprepare, |
443 | .set_parent = cdce706_clkout_set_parent, |
444 | .get_parent = cdce706_clkout_get_parent, |
445 | .recalc_rate = cdce706_clkout_recalc_rate, |
446 | .determine_rate = cdce706_clkout_determine_rate, |
447 | .set_rate = cdce706_clkout_set_rate, |
448 | }; |
449 | |
450 | static int cdce706_register_hw(struct cdce706_dev_data *cdce, |
451 | struct cdce706_hw_data *hw, unsigned num_hw, |
452 | const char * const *clk_names, |
453 | struct clk_init_data *init) |
454 | { |
455 | unsigned i; |
456 | int ret; |
457 | |
458 | for (i = 0; i < num_hw; ++i, ++hw) { |
459 | init->name = clk_names[i]; |
460 | hw->dev_data = cdce; |
461 | hw->idx = i; |
462 | hw->hw.init = init; |
463 | ret = devm_clk_hw_register(dev: &cdce->client->dev, |
464 | hw: &hw->hw); |
465 | if (ret) { |
466 | dev_err(&cdce->client->dev, "Failed to register %s\n" , |
467 | clk_names[i]); |
468 | return ret; |
469 | } |
470 | } |
471 | return 0; |
472 | } |
473 | |
474 | static int cdce706_register_clkin(struct cdce706_dev_data *cdce) |
475 | { |
476 | struct clk_init_data init = { |
477 | .ops = &cdce706_clkin_ops, |
478 | .parent_names = cdce->clkin_name, |
479 | .num_parents = ARRAY_SIZE(cdce->clkin_name), |
480 | }; |
481 | unsigned i; |
482 | int ret; |
483 | unsigned clock, source; |
484 | |
485 | for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) { |
486 | struct clk *parent = devm_clk_get(dev: &cdce->client->dev, |
487 | id: cdce706_source_name[i]); |
488 | |
489 | if (IS_ERR(ptr: parent)) { |
490 | cdce->clkin_name[i] = cdce706_source_name[i]; |
491 | } else { |
492 | cdce->clkin_name[i] = __clk_get_name(clk: parent); |
493 | cdce->clkin_clk[i] = parent; |
494 | } |
495 | } |
496 | |
497 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_CLKIN_SOURCE, val: &source); |
498 | if (ret < 0) |
499 | return ret; |
500 | if ((source & CDCE706_CLKIN_SOURCE_MASK) == |
501 | CDCE706_CLKIN_SOURCE_LVCMOS) { |
502 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_CLKIN_CLOCK, val: &clock); |
503 | if (ret < 0) |
504 | return ret; |
505 | cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK); |
506 | } |
507 | |
508 | ret = cdce706_register_hw(cdce, hw: cdce->clkin, |
509 | ARRAY_SIZE(cdce->clkin), |
510 | clk_names: cdce706_clkin_name, init: &init); |
511 | return ret; |
512 | } |
513 | |
514 | static int cdce706_register_plls(struct cdce706_dev_data *cdce) |
515 | { |
516 | struct clk_init_data init = { |
517 | .ops = &cdce706_pll_ops, |
518 | .parent_names = cdce706_clkin_name, |
519 | .num_parents = ARRAY_SIZE(cdce706_clkin_name), |
520 | }; |
521 | unsigned i; |
522 | int ret; |
523 | unsigned mux; |
524 | |
525 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_PLL_MUX, val: &mux); |
526 | if (ret < 0) |
527 | return ret; |
528 | |
529 | for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) { |
530 | unsigned m, n, v; |
531 | |
532 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_PLL_M_LOW(i), val: &m); |
533 | if (ret < 0) |
534 | return ret; |
535 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_PLL_N_LOW(i), val: &n); |
536 | if (ret < 0) |
537 | return ret; |
538 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_PLL_HI(i), val: &v); |
539 | if (ret < 0) |
540 | return ret; |
541 | cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8); |
542 | cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) << |
543 | (8 - CDCE706_PLL_HI_N_SHIFT)); |
544 | cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i); |
545 | dev_dbg(&cdce->client->dev, |
546 | "%s: i: %u, div: %u, mul: %u, mux: %d\n" , __func__, i, |
547 | cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux); |
548 | } |
549 | |
550 | ret = cdce706_register_hw(cdce, hw: cdce->pll, |
551 | ARRAY_SIZE(cdce->pll), |
552 | clk_names: cdce706_pll_name, init: &init); |
553 | return ret; |
554 | } |
555 | |
556 | static int cdce706_register_dividers(struct cdce706_dev_data *cdce) |
557 | { |
558 | struct clk_init_data init = { |
559 | .ops = &cdce706_divider_ops, |
560 | .parent_names = cdce706_divider_parent_name, |
561 | .num_parents = ARRAY_SIZE(cdce706_divider_parent_name), |
562 | .flags = CLK_SET_RATE_PARENT, |
563 | }; |
564 | unsigned i; |
565 | int ret; |
566 | |
567 | for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) { |
568 | unsigned val; |
569 | |
570 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_DIVIDER_PLL(i), val: &val); |
571 | if (ret < 0) |
572 | return ret; |
573 | cdce->divider[i].parent = |
574 | (val & CDCE706_DIVIDER_PLL_MASK(i)) >> |
575 | CDCE706_DIVIDER_PLL_SHIFT(i); |
576 | |
577 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_DIVIDER(i), val: &val); |
578 | if (ret < 0) |
579 | return ret; |
580 | cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK; |
581 | dev_dbg(&cdce->client->dev, |
582 | "%s: i: %u, parent: %u, div: %u\n" , __func__, i, |
583 | cdce->divider[i].parent, cdce->divider[i].div); |
584 | } |
585 | |
586 | ret = cdce706_register_hw(cdce, hw: cdce->divider, |
587 | ARRAY_SIZE(cdce->divider), |
588 | clk_names: cdce706_divider_name, init: &init); |
589 | return ret; |
590 | } |
591 | |
592 | static int cdce706_register_clkouts(struct cdce706_dev_data *cdce) |
593 | { |
594 | struct clk_init_data init = { |
595 | .ops = &cdce706_clkout_ops, |
596 | .parent_names = cdce706_divider_name, |
597 | .num_parents = ARRAY_SIZE(cdce706_divider_name), |
598 | .flags = CLK_SET_RATE_PARENT, |
599 | }; |
600 | unsigned i; |
601 | int ret; |
602 | |
603 | for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) { |
604 | unsigned val; |
605 | |
606 | ret = cdce706_reg_read(dev_data: cdce, CDCE706_CLKOUT(i), val: &val); |
607 | if (ret < 0) |
608 | return ret; |
609 | cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK; |
610 | dev_dbg(&cdce->client->dev, |
611 | "%s: i: %u, parent: %u\n" , __func__, i, |
612 | cdce->clkout[i].parent); |
613 | } |
614 | |
615 | return cdce706_register_hw(cdce, hw: cdce->clkout, |
616 | ARRAY_SIZE(cdce->clkout), |
617 | clk_names: cdce706_clkout_name, init: &init); |
618 | } |
619 | |
620 | static struct clk_hw * |
621 | of_clk_cdce_get(struct of_phandle_args *clkspec, void *data) |
622 | { |
623 | struct cdce706_dev_data *cdce = data; |
624 | unsigned int idx = clkspec->args[0]; |
625 | |
626 | if (idx >= ARRAY_SIZE(cdce->clkout)) { |
627 | pr_err("%s: invalid index %u\n" , __func__, idx); |
628 | return ERR_PTR(error: -EINVAL); |
629 | } |
630 | |
631 | return &cdce->clkout[idx].hw; |
632 | } |
633 | |
634 | static int cdce706_probe(struct i2c_client *client) |
635 | { |
636 | struct i2c_adapter *adapter = client->adapter; |
637 | struct cdce706_dev_data *cdce; |
638 | int ret; |
639 | |
640 | if (!i2c_check_functionality(adap: adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
641 | return -EIO; |
642 | |
643 | cdce = devm_kzalloc(dev: &client->dev, size: sizeof(*cdce), GFP_KERNEL); |
644 | if (!cdce) |
645 | return -ENOMEM; |
646 | |
647 | cdce->client = client; |
648 | cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config); |
649 | if (IS_ERR(ptr: cdce->regmap)) { |
650 | dev_err(&client->dev, "Failed to initialize regmap\n" ); |
651 | return -EINVAL; |
652 | } |
653 | |
654 | i2c_set_clientdata(client, data: cdce); |
655 | |
656 | ret = cdce706_register_clkin(cdce); |
657 | if (ret < 0) |
658 | return ret; |
659 | ret = cdce706_register_plls(cdce); |
660 | if (ret < 0) |
661 | return ret; |
662 | ret = cdce706_register_dividers(cdce); |
663 | if (ret < 0) |
664 | return ret; |
665 | ret = cdce706_register_clkouts(cdce); |
666 | if (ret < 0) |
667 | return ret; |
668 | return devm_of_clk_add_hw_provider(dev: &client->dev, get: of_clk_cdce_get, |
669 | data: cdce); |
670 | } |
671 | |
672 | #ifdef CONFIG_OF |
673 | static const struct of_device_id cdce706_dt_match[] = { |
674 | { .compatible = "ti,cdce706" }, |
675 | { }, |
676 | }; |
677 | MODULE_DEVICE_TABLE(of, cdce706_dt_match); |
678 | #endif |
679 | |
680 | static const struct i2c_device_id cdce706_id[] = { |
681 | { "cdce706" , 0 }, |
682 | { } |
683 | }; |
684 | MODULE_DEVICE_TABLE(i2c, cdce706_id); |
685 | |
686 | static struct i2c_driver cdce706_i2c_driver = { |
687 | .driver = { |
688 | .name = "cdce706" , |
689 | .of_match_table = of_match_ptr(cdce706_dt_match), |
690 | }, |
691 | .probe = cdce706_probe, |
692 | .id_table = cdce706_id, |
693 | }; |
694 | module_i2c_driver(cdce706_i2c_driver); |
695 | |
696 | MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>" ); |
697 | MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver" ); |
698 | MODULE_LICENSE("GPL" ); |
699 | |