diff options
Diffstat (limited to 'drivers/clk/clk-cdce706.c')
-rw-r--r-- | drivers/clk/clk-cdce706.c | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c new file mode 100644 index 000000000000..c386ad25beb4 --- /dev/null +++ b/drivers/clk/clk-cdce706.c | |||
@@ -0,0 +1,700 @@ | |||
1 | /* | ||
2 | * TI CDCE706 programmable 3-PLL clock synthesizer driver | ||
3 | * | ||
4 | * Copyright (c) 2014 Cadence Design Systems Inc. | ||
5 | * | ||
6 | * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/mod_devicetable.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/rational.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #define CDCE706_CLKIN_CLOCK 10 | ||
25 | #define CDCE706_CLKIN_SOURCE 11 | ||
26 | #define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll)) | ||
27 | #define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll)) | ||
28 | #define CDCE706_PLL_HI(pll) (3 + 3 * (pll)) | ||
29 | #define CDCE706_PLL_MUX 3 | ||
30 | #define CDCE706_PLL_FVCO 6 | ||
31 | #define CDCE706_DIVIDER(div) (13 + (div)) | ||
32 | #define CDCE706_CLKOUT(out) (19 + (out)) | ||
33 | |||
34 | #define CDCE706_CLKIN_CLOCK_MASK 0x10 | ||
35 | #define CDCE706_CLKIN_SOURCE_SHIFT 6 | ||
36 | #define CDCE706_CLKIN_SOURCE_MASK 0xc0 | ||
37 | #define CDCE706_CLKIN_SOURCE_LVCMOS 0x40 | ||
38 | |||
39 | #define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll)) | ||
40 | #define CDCE706_PLL_LOW_M_MASK 0xff | ||
41 | #define CDCE706_PLL_LOW_N_MASK 0xff | ||
42 | #define CDCE706_PLL_HI_M_MASK 0x1 | ||
43 | #define CDCE706_PLL_HI_N_MASK 0x1e | ||
44 | #define CDCE706_PLL_HI_N_SHIFT 1 | ||
45 | #define CDCE706_PLL_M_MAX 0x1ff | ||
46 | #define CDCE706_PLL_N_MAX 0xfff | ||
47 | #define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll)) | ||
48 | #define CDCE706_PLL_FREQ_MIN 80000000 | ||
49 | #define CDCE706_PLL_FREQ_MAX 300000000 | ||
50 | #define CDCE706_PLL_FREQ_HI 180000000 | ||
51 | |||
52 | #define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4)) | ||
53 | #define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1)) | ||
54 | #define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div)) | ||
55 | #define CDCE706_DIVIDER_DIVIDER_MASK 0x7f | ||
56 | #define CDCE706_DIVIDER_DIVIDER_MAX 0x7f | ||
57 | |||
58 | #define CDCE706_CLKOUT_DIVIDER_MASK 0x7 | ||
59 | #define CDCE706_CLKOUT_ENABLE_MASK 0x8 | ||
60 | |||
61 | static struct regmap_config cdce706_regmap_config = { | ||
62 | .reg_bits = 8, | ||
63 | .val_bits = 8, | ||
64 | .val_format_endian = REGMAP_ENDIAN_NATIVE, | ||
65 | }; | ||
66 | |||
67 | #define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw)) | ||
68 | |||
69 | struct cdce706_hw_data { | ||
70 | struct cdce706_dev_data *dev_data; | ||
71 | unsigned idx; | ||
72 | unsigned parent; | ||
73 | struct clk *clk; | ||
74 | struct clk_hw hw; | ||
75 | unsigned div; | ||
76 | unsigned mul; | ||
77 | unsigned mux; | ||
78 | }; | ||
79 | |||
80 | struct cdce706_dev_data { | ||
81 | struct i2c_client *client; | ||
82 | struct regmap *regmap; | ||
83 | struct clk_onecell_data onecell; | ||
84 | struct clk *clks[6]; | ||
85 | struct clk *clkin_clk[2]; | ||
86 | const char *clkin_name[2]; | ||
87 | struct cdce706_hw_data clkin[1]; | ||
88 | struct cdce706_hw_data pll[3]; | ||
89 | struct cdce706_hw_data divider[6]; | ||
90 | struct cdce706_hw_data clkout[6]; | ||
91 | }; | ||
92 | |||
93 | static const char * const cdce706_source_name[] = { | ||
94 | "clk_in0", "clk_in1", | ||
95 | }; | ||
96 | |||
97 | static const char *cdce706_clkin_name[] = { | ||
98 | "clk_in", | ||
99 | }; | ||
100 | |||
101 | static const char * const cdce706_pll_name[] = { | ||
102 | "pll1", "pll2", "pll3", | ||
103 | }; | ||
104 | |||
105 | static const char *cdce706_divider_parent_name[] = { | ||
106 | "clk_in", "pll1", "pll2", "pll2", "pll3", | ||
107 | }; | ||
108 | |||
109 | static const char *cdce706_divider_name[] = { | ||
110 | "p0", "p1", "p2", "p3", "p4", "p5", | ||
111 | }; | ||
112 | |||
113 | static const char * const cdce706_clkout_name[] = { | ||
114 | "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5", | ||
115 | }; | ||
116 | |||
117 | static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg, | ||
118 | unsigned *val) | ||
119 | { | ||
120 | int rc = regmap_read(dev_data->regmap, reg | 0x80, val); | ||
121 | |||
122 | if (rc < 0) | ||
123 | dev_err(&dev_data->client->dev, "error reading reg %u", reg); | ||
124 | return rc; | ||
125 | } | ||
126 | |||
127 | static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg, | ||
128 | unsigned val) | ||
129 | { | ||
130 | int rc = regmap_write(dev_data->regmap, reg | 0x80, val); | ||
131 | |||
132 | if (rc < 0) | ||
133 | dev_err(&dev_data->client->dev, "error writing reg %u", reg); | ||
134 | return rc; | ||
135 | } | ||
136 | |||
137 | static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg, | ||
138 | unsigned mask, unsigned val) | ||
139 | { | ||
140 | int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val); | ||
141 | |||
142 | if (rc < 0) | ||
143 | dev_err(&dev_data->client->dev, "error updating reg %u", reg); | ||
144 | return rc; | ||
145 | } | ||
146 | |||
147 | static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index) | ||
148 | { | ||
149 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
150 | |||
151 | hwd->parent = index; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static u8 cdce706_clkin_get_parent(struct clk_hw *hw) | ||
156 | { | ||
157 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
158 | |||
159 | return hwd->parent; | ||
160 | } | ||
161 | |||
162 | static const struct clk_ops cdce706_clkin_ops = { | ||
163 | .set_parent = cdce706_clkin_set_parent, | ||
164 | .get_parent = cdce706_clkin_get_parent, | ||
165 | }; | ||
166 | |||
167 | static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw, | ||
168 | unsigned long parent_rate) | ||
169 | { | ||
170 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
171 | |||
172 | dev_dbg(&hwd->dev_data->client->dev, | ||
173 | "%s, pll: %d, mux: %d, mul: %u, div: %u\n", | ||
174 | __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div); | ||
175 | |||
176 | if (!hwd->mux) { | ||
177 | if (hwd->div && hwd->mul) { | ||
178 | u64 res = (u64)parent_rate * hwd->mul; | ||
179 | |||
180 | do_div(res, hwd->div); | ||
181 | return res; | ||
182 | } | ||
183 | } else { | ||
184 | if (hwd->div) | ||
185 | return parent_rate / hwd->div; | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
191 | unsigned long *parent_rate) | ||
192 | { | ||
193 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
194 | unsigned long mul, div; | ||
195 | u64 res; | ||
196 | |||
197 | dev_dbg(&hwd->dev_data->client->dev, | ||
198 | "%s, rate: %lu, parent_rate: %lu\n", | ||
199 | __func__, rate, *parent_rate); | ||
200 | |||
201 | rational_best_approximation(rate, *parent_rate, | ||
202 | CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX, | ||
203 | &mul, &div); | ||
204 | hwd->mul = mul; | ||
205 | hwd->div = div; | ||
206 | |||
207 | dev_dbg(&hwd->dev_data->client->dev, | ||
208 | "%s, pll: %d, mul: %lu, div: %lu\n", | ||
209 | __func__, hwd->idx, mul, div); | ||
210 | |||
211 | res = (u64)*parent_rate * hwd->mul; | ||
212 | do_div(res, hwd->div); | ||
213 | return res; | ||
214 | } | ||
215 | |||
216 | static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate, | ||
217 | unsigned long parent_rate) | ||
218 | { | ||
219 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
220 | unsigned long mul = hwd->mul, div = hwd->div; | ||
221 | int err; | ||
222 | |||
223 | dev_dbg(&hwd->dev_data->client->dev, | ||
224 | "%s, pll: %d, mul: %lu, div: %lu\n", | ||
225 | __func__, hwd->idx, mul, div); | ||
226 | |||
227 | err = cdce706_reg_update(hwd->dev_data, | ||
228 | CDCE706_PLL_HI(hwd->idx), | ||
229 | CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK, | ||
230 | ((div >> 8) & CDCE706_PLL_HI_M_MASK) | | ||
231 | ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) & | ||
232 | CDCE706_PLL_HI_N_MASK)); | ||
233 | if (err < 0) | ||
234 | return err; | ||
235 | |||
236 | err = cdce706_reg_write(hwd->dev_data, | ||
237 | CDCE706_PLL_M_LOW(hwd->idx), | ||
238 | div & CDCE706_PLL_LOW_M_MASK); | ||
239 | if (err < 0) | ||
240 | return err; | ||
241 | |||
242 | err = cdce706_reg_write(hwd->dev_data, | ||
243 | CDCE706_PLL_N_LOW(hwd->idx), | ||
244 | mul & CDCE706_PLL_LOW_N_MASK); | ||
245 | if (err < 0) | ||
246 | return err; | ||
247 | |||
248 | err = cdce706_reg_update(hwd->dev_data, | ||
249 | CDCE706_PLL_FVCO, | ||
250 | CDCE706_PLL_FVCO_MASK(hwd->idx), | ||
251 | rate > CDCE706_PLL_FREQ_HI ? | ||
252 | CDCE706_PLL_FVCO_MASK(hwd->idx) : 0); | ||
253 | return err; | ||
254 | } | ||
255 | |||
256 | static const struct clk_ops cdce706_pll_ops = { | ||
257 | .recalc_rate = cdce706_pll_recalc_rate, | ||
258 | .round_rate = cdce706_pll_round_rate, | ||
259 | .set_rate = cdce706_pll_set_rate, | ||
260 | }; | ||
261 | |||
262 | static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index) | ||
263 | { | ||
264 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
265 | |||
266 | if (hwd->parent == index) | ||
267 | return 0; | ||
268 | hwd->parent = index; | ||
269 | return cdce706_reg_update(hwd->dev_data, | ||
270 | CDCE706_DIVIDER_PLL(hwd->idx), | ||
271 | CDCE706_DIVIDER_PLL_MASK(hwd->idx), | ||
272 | index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx)); | ||
273 | } | ||
274 | |||
275 | static u8 cdce706_divider_get_parent(struct clk_hw *hw) | ||
276 | { | ||
277 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
278 | |||
279 | return hwd->parent; | ||
280 | } | ||
281 | |||
282 | static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw, | ||
283 | unsigned long parent_rate) | ||
284 | { | ||
285 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
286 | |||
287 | dev_dbg(&hwd->dev_data->client->dev, | ||
288 | "%s, divider: %d, div: %u\n", | ||
289 | __func__, hwd->idx, hwd->div); | ||
290 | if (hwd->div) | ||
291 | return parent_rate / hwd->div; | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate, | ||
296 | unsigned long *parent_rate) | ||
297 | { | ||
298 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
299 | struct cdce706_dev_data *cdce = hwd->dev_data; | ||
300 | unsigned long mul, div; | ||
301 | |||
302 | dev_dbg(&hwd->dev_data->client->dev, | ||
303 | "%s, rate: %lu, parent_rate: %lu\n", | ||
304 | __func__, rate, *parent_rate); | ||
305 | |||
306 | rational_best_approximation(rate, *parent_rate, | ||
307 | 1, CDCE706_DIVIDER_DIVIDER_MAX, | ||
308 | &mul, &div); | ||
309 | if (!mul) | ||
310 | div = CDCE706_DIVIDER_DIVIDER_MAX; | ||
311 | |||
312 | if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { | ||
313 | unsigned long best_diff = rate; | ||
314 | unsigned long best_div = 0; | ||
315 | struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent]; | ||
316 | unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0; | ||
317 | |||
318 | for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff && | ||
319 | div <= CDCE706_PLL_FREQ_MAX / rate; ++div) { | ||
320 | unsigned long n, m; | ||
321 | unsigned long diff; | ||
322 | unsigned long div_rate; | ||
323 | u64 div_rate64; | ||
324 | |||
325 | if (rate * div < CDCE706_PLL_FREQ_MIN) | ||
326 | continue; | ||
327 | |||
328 | rational_best_approximation(rate * div, gp_rate, | ||
329 | CDCE706_PLL_N_MAX, | ||
330 | CDCE706_PLL_M_MAX, | ||
331 | &n, &m); | ||
332 | div_rate64 = (u64)gp_rate * n; | ||
333 | do_div(div_rate64, m); | ||
334 | do_div(div_rate64, div); | ||
335 | div_rate = div_rate64; | ||
336 | diff = max(div_rate, rate) - min(div_rate, rate); | ||
337 | |||
338 | if (diff < best_diff) { | ||
339 | best_diff = diff; | ||
340 | best_div = div; | ||
341 | dev_dbg(&hwd->dev_data->client->dev, | ||
342 | "%s, %lu * %lu / %lu / %lu = %lu\n", | ||
343 | __func__, gp_rate, n, m, div, div_rate); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | div = best_div; | ||
348 | |||
349 | dev_dbg(&hwd->dev_data->client->dev, | ||
350 | "%s, altering parent rate: %lu -> %lu\n", | ||
351 | __func__, *parent_rate, rate * div); | ||
352 | *parent_rate = rate * div; | ||
353 | } | ||
354 | hwd->div = div; | ||
355 | |||
356 | dev_dbg(&hwd->dev_data->client->dev, | ||
357 | "%s, divider: %d, div: %lu\n", | ||
358 | __func__, hwd->idx, div); | ||
359 | |||
360 | return *parent_rate / div; | ||
361 | } | ||
362 | |||
363 | static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate, | ||
364 | unsigned long parent_rate) | ||
365 | { | ||
366 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
367 | |||
368 | dev_dbg(&hwd->dev_data->client->dev, | ||
369 | "%s, divider: %d, div: %u\n", | ||
370 | __func__, hwd->idx, hwd->div); | ||
371 | |||
372 | return cdce706_reg_update(hwd->dev_data, | ||
373 | CDCE706_DIVIDER(hwd->idx), | ||
374 | CDCE706_DIVIDER_DIVIDER_MASK, | ||
375 | hwd->div); | ||
376 | } | ||
377 | |||
378 | static const struct clk_ops cdce706_divider_ops = { | ||
379 | .set_parent = cdce706_divider_set_parent, | ||
380 | .get_parent = cdce706_divider_get_parent, | ||
381 | .recalc_rate = cdce706_divider_recalc_rate, | ||
382 | .round_rate = cdce706_divider_round_rate, | ||
383 | .set_rate = cdce706_divider_set_rate, | ||
384 | }; | ||
385 | |||
386 | static int cdce706_clkout_prepare(struct clk_hw *hw) | ||
387 | { | ||
388 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
389 | |||
390 | return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx), | ||
391 | CDCE706_CLKOUT_ENABLE_MASK, | ||
392 | CDCE706_CLKOUT_ENABLE_MASK); | ||
393 | } | ||
394 | |||
395 | static void cdce706_clkout_unprepare(struct clk_hw *hw) | ||
396 | { | ||
397 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
398 | |||
399 | cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx), | ||
400 | CDCE706_CLKOUT_ENABLE_MASK, 0); | ||
401 | } | ||
402 | |||
403 | static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index) | ||
404 | { | ||
405 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
406 | |||
407 | if (hwd->parent == index) | ||
408 | return 0; | ||
409 | hwd->parent = index; | ||
410 | return cdce706_reg_update(hwd->dev_data, | ||
411 | CDCE706_CLKOUT(hwd->idx), | ||
412 | CDCE706_CLKOUT_ENABLE_MASK, index); | ||
413 | } | ||
414 | |||
415 | static u8 cdce706_clkout_get_parent(struct clk_hw *hw) | ||
416 | { | ||
417 | struct cdce706_hw_data *hwd = to_hw_data(hw); | ||
418 | |||
419 | return hwd->parent; | ||
420 | } | ||
421 | |||
422 | static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw, | ||
423 | unsigned long parent_rate) | ||
424 | { | ||
425 | return parent_rate; | ||
426 | } | ||
427 | |||
428 | static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate, | ||
429 | unsigned long *parent_rate) | ||
430 | { | ||
431 | *parent_rate = rate; | ||
432 | return rate; | ||
433 | } | ||
434 | |||
435 | static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate, | ||
436 | unsigned long parent_rate) | ||
437 | { | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static const struct clk_ops cdce706_clkout_ops = { | ||
442 | .prepare = cdce706_clkout_prepare, | ||
443 | .unprepare = cdce706_clkout_unprepare, | ||
444 | .set_parent = cdce706_clkout_set_parent, | ||
445 | .get_parent = cdce706_clkout_get_parent, | ||
446 | .recalc_rate = cdce706_clkout_recalc_rate, | ||
447 | .round_rate = cdce706_clkout_round_rate, | ||
448 | .set_rate = cdce706_clkout_set_rate, | ||
449 | }; | ||
450 | |||
451 | static int cdce706_register_hw(struct cdce706_dev_data *cdce, | ||
452 | struct cdce706_hw_data *hw, unsigned num_hw, | ||
453 | const char * const *clk_names, | ||
454 | struct clk_init_data *init) | ||
455 | { | ||
456 | unsigned i; | ||
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 | hw->clk = devm_clk_register(&cdce->client->dev, | ||
464 | &hw->hw); | ||
465 | if (IS_ERR(hw->clk)) { | ||
466 | dev_err(&cdce->client->dev, "Failed to register %s\n", | ||
467 | clk_names[i]); | ||
468 | return PTR_ERR(hw->clk); | ||
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(&cdce->client->dev, | ||
487 | cdce706_source_name[i]); | ||
488 | |||
489 | if (IS_ERR(parent)) { | ||
490 | cdce->clkin_name[i] = cdce706_source_name[i]; | ||
491 | } else { | ||
492 | cdce->clkin_name[i] = __clk_get_name(parent); | ||
493 | cdce->clkin_clk[i] = parent; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &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(cdce, CDCE706_CLKIN_CLOCK, &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, cdce->clkin, | ||
509 | ARRAY_SIZE(cdce->clkin), | ||
510 | cdce706_clkin_name, &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(cdce, CDCE706_PLL_MUX, &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(cdce, CDCE706_PLL_M_LOW(i), &m); | ||
533 | if (ret < 0) | ||
534 | return ret; | ||
535 | ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n); | ||
536 | if (ret < 0) | ||
537 | return ret; | ||
538 | ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &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, cdce->pll, | ||
551 | ARRAY_SIZE(cdce->pll), | ||
552 | cdce706_pll_name, &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(cdce, CDCE706_DIVIDER_PLL(i), &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(cdce, CDCE706_DIVIDER(i), &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, cdce->divider, | ||
587 | ARRAY_SIZE(cdce->divider), | ||
588 | cdce706_divider_name, &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(cdce, CDCE706_CLKOUT(i), &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 | ret = cdce706_register_hw(cdce, cdce->clkout, | ||
616 | ARRAY_SIZE(cdce->clkout), | ||
617 | cdce706_clkout_name, &init); | ||
618 | for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) | ||
619 | cdce->clks[i] = cdce->clkout[i].clk; | ||
620 | |||
621 | return ret; | ||
622 | } | ||
623 | |||
624 | static int cdce706_probe(struct i2c_client *client, | ||
625 | const struct i2c_device_id *id) | ||
626 | { | ||
627 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
628 | struct cdce706_dev_data *cdce; | ||
629 | int ret; | ||
630 | |||
631 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
632 | return -EIO; | ||
633 | |||
634 | cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL); | ||
635 | if (!cdce) | ||
636 | return -ENOMEM; | ||
637 | |||
638 | cdce->client = client; | ||
639 | cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config); | ||
640 | if (IS_ERR(cdce->regmap)) { | ||
641 | dev_err(&client->dev, "Failed to initialize regmap\n"); | ||
642 | return -EINVAL; | ||
643 | } | ||
644 | |||
645 | i2c_set_clientdata(client, cdce); | ||
646 | |||
647 | ret = cdce706_register_clkin(cdce); | ||
648 | if (ret < 0) | ||
649 | return ret; | ||
650 | ret = cdce706_register_plls(cdce); | ||
651 | if (ret < 0) | ||
652 | return ret; | ||
653 | ret = cdce706_register_dividers(cdce); | ||
654 | if (ret < 0) | ||
655 | return ret; | ||
656 | ret = cdce706_register_clkouts(cdce); | ||
657 | if (ret < 0) | ||
658 | return ret; | ||
659 | cdce->onecell.clks = cdce->clks; | ||
660 | cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks); | ||
661 | ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, | ||
662 | &cdce->onecell); | ||
663 | |||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | static int cdce706_remove(struct i2c_client *client) | ||
668 | { | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | |||
673 | #ifdef CONFIG_OF | ||
674 | static const struct of_device_id cdce706_dt_match[] = { | ||
675 | { .compatible = "ti,cdce706" }, | ||
676 | { }, | ||
677 | }; | ||
678 | MODULE_DEVICE_TABLE(of, cdce706_dt_match); | ||
679 | #endif | ||
680 | |||
681 | static const struct i2c_device_id cdce706_id[] = { | ||
682 | { "cdce706", 0 }, | ||
683 | { } | ||
684 | }; | ||
685 | MODULE_DEVICE_TABLE(i2c, cdce706_id); | ||
686 | |||
687 | static struct i2c_driver cdce706_i2c_driver = { | ||
688 | .driver = { | ||
689 | .name = "cdce706", | ||
690 | .of_match_table = of_match_ptr(cdce706_dt_match), | ||
691 | }, | ||
692 | .probe = cdce706_probe, | ||
693 | .remove = cdce706_remove, | ||
694 | .id_table = cdce706_id, | ||
695 | }; | ||
696 | module_i2c_driver(cdce706_i2c_driver); | ||
697 | |||
698 | MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>"); | ||
699 | MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver"); | ||
700 | MODULE_LICENSE("GPL"); | ||