1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * AXI clkgen driver
4 *
5 * Copyright 2012-2013 Analog Devices Inc.
6 * Author: Lars-Peter Clausen <lars@metafoo.de>
7 */
8
9 #include <linux/adi-axi-common.h>
10 #include <linux/bits.h>
11 #include <linux/clk.h>
12 #include <linux/clk-provider.h>
13 #include <linux/err.h>
14 #include <linux/io.h>
15 #include <linux/module.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/of.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20
21 #define AXI_CLKGEN_V2_REG_RESET 0x40
22 #define AXI_CLKGEN_V2_REG_CLKSEL 0x44
23 #define AXI_CLKGEN_V2_REG_DRP_CNTRL 0x70
24 #define AXI_CLKGEN_V2_REG_DRP_STATUS 0x74
25
26 #define AXI_CLKGEN_V2_RESET_MMCM_ENABLE BIT(1)
27 #define AXI_CLKGEN_V2_RESET_ENABLE BIT(0)
28
29 #define AXI_CLKGEN_V2_DRP_CNTRL_SEL BIT(29)
30 #define AXI_CLKGEN_V2_DRP_CNTRL_READ BIT(28)
31
32 #define AXI_CLKGEN_V2_DRP_STATUS_BUSY BIT(16)
33
34 #define ADI_CLKGEN_REG_FPGA_VOLTAGE 0x0140
35 #define ADI_CLKGEN_INFO_FPGA_VOLTAGE(val) ((val) & GENMASK(15, 0))
36
37 #define MMCM_REG_CLKOUT5_2 0x07
38 #define MMCM_REG_CLKOUT0_1 0x08
39 #define MMCM_REG_CLKOUT0_2 0x09
40 #define MMCM_REG_CLKOUT6_2 0x13
41 #define MMCM_REG_CLK_FB1 0x14
42 #define MMCM_REG_CLK_FB2 0x15
43 #define MMCM_REG_CLK_DIV 0x16
44 #define MMCM_REG_LOCK1 0x18
45 #define MMCM_REG_LOCK2 0x19
46 #define MMCM_REG_LOCK3 0x1a
47 #define MMCM_REG_POWER 0x28
48 #define MMCM_REG_FILTER1 0x4e
49 #define MMCM_REG_FILTER2 0x4f
50
51 #define MMCM_CLKOUT_NOCOUNT BIT(6)
52
53 #define MMCM_CLK_DIV_DIVIDE BIT(11)
54 #define MMCM_CLK_DIV_NOCOUNT BIT(12)
55
56 struct axi_clkgen_limits {
57 unsigned int fpfd_min;
58 unsigned int fpfd_max;
59 unsigned int fvco_min;
60 unsigned int fvco_max;
61 };
62
63 struct axi_clkgen {
64 void __iomem *base;
65 struct clk_hw clk_hw;
66 struct axi_clkgen_limits limits;
67 };
68
axi_clkgen_lookup_filter(unsigned int m)69 static uint32_t axi_clkgen_lookup_filter(unsigned int m)
70 {
71 switch (m) {
72 case 0:
73 return 0x01001990;
74 case 1:
75 return 0x01001190;
76 case 2:
77 return 0x01009890;
78 case 3:
79 return 0x01001890;
80 case 4:
81 return 0x01008890;
82 case 5 ... 8:
83 return 0x01009090;
84 case 9 ... 11:
85 return 0x01000890;
86 case 12:
87 return 0x08009090;
88 case 13 ... 22:
89 return 0x01001090;
90 case 23 ... 36:
91 return 0x01008090;
92 case 37 ... 46:
93 return 0x08001090;
94 default:
95 return 0x08008090;
96 }
97 }
98
99 static const u32 axi_clkgen_lock_table[] = {
100 0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
101 0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
102 0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
103 0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
104 0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
105 0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
106 0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
107 0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
108 0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
109 };
110
axi_clkgen_lookup_lock(unsigned int m)111 static u32 axi_clkgen_lookup_lock(unsigned int m)
112 {
113 if (m < ARRAY_SIZE(axi_clkgen_lock_table))
114 return axi_clkgen_lock_table[m];
115 return 0x1f1f00fa;
116 }
117
118 static const struct axi_clkgen_limits axi_clkgen_zynqmp_default_limits = {
119 .fpfd_min = 10000,
120 .fpfd_max = 450000,
121 .fvco_min = 800000,
122 .fvco_max = 1600000,
123 };
124
125 static const struct axi_clkgen_limits axi_clkgen_zynq_default_limits = {
126 .fpfd_min = 10000,
127 .fpfd_max = 450000,
128 .fvco_min = 600000,
129 .fvco_max = 1200000,
130 };
131
axi_clkgen_calc_params(const struct axi_clkgen_limits * limits,unsigned long fin,unsigned long fout,unsigned int * best_d,unsigned int * best_m,unsigned int * best_dout)132 static void axi_clkgen_calc_params(const struct axi_clkgen_limits *limits,
133 unsigned long fin, unsigned long fout,
134 unsigned int *best_d, unsigned int *best_m,
135 unsigned int *best_dout)
136 {
137 unsigned long d, d_min, d_max, _d_min, _d_max;
138 unsigned long m, m_min, m_max;
139 unsigned long f, dout, best_f, fvco;
140 unsigned long fract_shift = 0;
141 unsigned long fvco_min_fract, fvco_max_fract;
142
143 fin /= 1000;
144 fout /= 1000;
145
146 best_f = ULONG_MAX;
147 *best_d = 0;
148 *best_m = 0;
149 *best_dout = 0;
150
151 d_min = max(DIV_ROUND_UP(fin, limits->fpfd_max), 1);
152 d_max = min(fin / limits->fpfd_min, 80);
153
154 again:
155 fvco_min_fract = limits->fvco_min << fract_shift;
156 fvco_max_fract = limits->fvco_max << fract_shift;
157
158 m_min = max(DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
159 m_max = min(fvco_max_fract * d_max / fin, 64 << fract_shift);
160
161 for (m = m_min; m <= m_max; m++) {
162 _d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max_fract));
163 _d_max = min(d_max, fin * m / fvco_min_fract);
164
165 for (d = _d_min; d <= _d_max; d++) {
166 fvco = fin * m / d;
167
168 dout = DIV_ROUND_CLOSEST(fvco, fout);
169 dout = clamp_t(unsigned long, dout, 1, 128 << fract_shift);
170 f = fvco / dout;
171 if (abs(f - fout) < abs(best_f - fout)) {
172 best_f = f;
173 *best_d = d;
174 *best_m = m << (3 - fract_shift);
175 *best_dout = dout << (3 - fract_shift);
176 if (best_f == fout)
177 return;
178 }
179 }
180 }
181
182 /* Let's see if we find a better setting in fractional mode */
183 if (fract_shift == 0) {
184 fract_shift = 3;
185 goto again;
186 }
187 }
188
189 struct axi_clkgen_div_params {
190 unsigned int low;
191 unsigned int high;
192 unsigned int edge;
193 unsigned int nocount;
194 unsigned int frac_en;
195 unsigned int frac;
196 unsigned int frac_wf_f;
197 unsigned int frac_wf_r;
198 unsigned int frac_phase;
199 };
200
axi_clkgen_calc_clk_params(unsigned int divider,unsigned int frac_divider,struct axi_clkgen_div_params * params)201 static void axi_clkgen_calc_clk_params(unsigned int divider,
202 unsigned int frac_divider,
203 struct axi_clkgen_div_params *params)
204 {
205 memset(params, 0x0, sizeof(*params));
206
207 if (divider == 1) {
208 params->nocount = 1;
209 return;
210 }
211
212 if (frac_divider == 0) {
213 params->high = divider / 2;
214 params->edge = divider % 2;
215 params->low = divider - params->high;
216 } else {
217 params->frac_en = 1;
218 params->frac = frac_divider;
219
220 params->high = divider / 2;
221 params->edge = divider % 2;
222 params->low = params->high;
223
224 if (params->edge == 0) {
225 params->high--;
226 params->frac_wf_r = 1;
227 }
228
229 if (params->edge == 0 || frac_divider == 1)
230 params->low--;
231 if (((params->edge == 0) ^ (frac_divider == 1)) ||
232 (divider == 2 && frac_divider == 1))
233 params->frac_wf_f = 1;
234
235 params->frac_phase = params->edge * 4 + frac_divider / 2;
236 }
237 }
238
axi_clkgen_write(struct axi_clkgen * axi_clkgen,unsigned int reg,unsigned int val)239 static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
240 unsigned int reg, unsigned int val)
241 {
242 writel(val, axi_clkgen->base + reg);
243 }
244
axi_clkgen_read(struct axi_clkgen * axi_clkgen,unsigned int reg,unsigned int * val)245 static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
246 unsigned int reg, unsigned int *val)
247 {
248 *val = readl(axi_clkgen->base + reg);
249 }
250
axi_clkgen_wait_non_busy(struct axi_clkgen * axi_clkgen)251 static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
252 {
253 unsigned int timeout = 10000;
254 unsigned int val;
255
256 do {
257 axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
258 } while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
259
260 if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
261 return -EIO;
262
263 return val & 0xffff;
264 }
265
axi_clkgen_mmcm_read(struct axi_clkgen * axi_clkgen,unsigned int reg,unsigned int * val)266 static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
267 unsigned int reg, unsigned int *val)
268 {
269 unsigned int reg_val;
270 int ret;
271
272 ret = axi_clkgen_wait_non_busy(axi_clkgen);
273 if (ret < 0)
274 return ret;
275
276 reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
277 reg_val |= (reg << 16);
278
279 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
280
281 ret = axi_clkgen_wait_non_busy(axi_clkgen);
282 if (ret < 0)
283 return ret;
284
285 *val = ret;
286
287 return 0;
288 }
289
axi_clkgen_mmcm_write(struct axi_clkgen * axi_clkgen,unsigned int reg,unsigned int val,unsigned int mask)290 static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
291 unsigned int reg, unsigned int val,
292 unsigned int mask)
293 {
294 unsigned int reg_val = 0;
295 int ret;
296
297 ret = axi_clkgen_wait_non_busy(axi_clkgen);
298 if (ret < 0)
299 return ret;
300
301 if (mask != 0xffff) {
302 axi_clkgen_mmcm_read(axi_clkgen, reg, ®_val);
303 reg_val &= ~mask;
304 }
305
306 reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
307
308 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
309
310 return 0;
311 }
312
axi_clkgen_mmcm_enable(struct axi_clkgen * axi_clkgen,bool enable)313 static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen, bool enable)
314 {
315 unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
316
317 if (enable)
318 val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
319
320 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
321 }
322
clk_hw_to_axi_clkgen(struct clk_hw * clk_hw)323 static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
324 {
325 return container_of(clk_hw, struct axi_clkgen, clk_hw);
326 }
327
axi_clkgen_set_div(struct axi_clkgen * axi_clkgen,unsigned int reg1,unsigned int reg2,unsigned int reg3,struct axi_clkgen_div_params * params)328 static void axi_clkgen_set_div(struct axi_clkgen *axi_clkgen,
329 unsigned int reg1, unsigned int reg2,
330 unsigned int reg3,
331 struct axi_clkgen_div_params *params)
332 {
333 axi_clkgen_mmcm_write(axi_clkgen, reg1,
334 (params->high << 6) | params->low, 0xefff);
335 axi_clkgen_mmcm_write(axi_clkgen, reg2,
336 (params->frac << 12) | (params->frac_en << 11) |
337 (params->frac_wf_r << 10) | (params->edge << 7) |
338 (params->nocount << 6), 0x7fff);
339 if (reg3 != 0) {
340 axi_clkgen_mmcm_write(axi_clkgen, reg3,
341 (params->frac_phase << 11) | (params->frac_wf_f << 10),
342 0x3c00);
343 }
344 }
345
axi_clkgen_set_rate(struct clk_hw * clk_hw,unsigned long rate,unsigned long parent_rate)346 static int axi_clkgen_set_rate(struct clk_hw *clk_hw, unsigned long rate,
347 unsigned long parent_rate)
348 {
349 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
350 const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
351 unsigned int d, m, dout;
352 struct axi_clkgen_div_params params;
353 u32 power = 0, filter, lock;
354
355 if (parent_rate == 0 || rate == 0)
356 return -EINVAL;
357
358 axi_clkgen_calc_params(limits, parent_rate, rate, &d, &m, &dout);
359
360 if (d == 0 || dout == 0 || m == 0)
361 return -EINVAL;
362
363 if ((dout & 0x7) != 0 || (m & 0x7) != 0)
364 power |= 0x9800;
365
366 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_POWER, power, 0x9800);
367
368 filter = axi_clkgen_lookup_filter(m - 1);
369 lock = axi_clkgen_lookup_lock(m - 1);
370
371 axi_clkgen_calc_clk_params(dout >> 3, dout & 0x7, ¶ms);
372 axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLKOUT0_1, MMCM_REG_CLKOUT0_2,
373 MMCM_REG_CLKOUT5_2, ¶ms);
374
375 axi_clkgen_calc_clk_params(d, 0, ¶ms);
376 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
377 (params.edge << 13) | (params.nocount << 12) |
378 (params.high << 6) | params.low, 0x3fff);
379
380 axi_clkgen_calc_clk_params(m >> 3, m & 0x7, ¶ms);
381 axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLK_FB1, MMCM_REG_CLK_FB2,
382 MMCM_REG_CLKOUT6_2, ¶ms);
383
384 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
385 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
386 (((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
387 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
388 (((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
389 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
390 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
391
392 return 0;
393 }
394
axi_clkgen_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)395 static int axi_clkgen_determine_rate(struct clk_hw *hw,
396 struct clk_rate_request *req)
397 {
398 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(hw);
399 const struct axi_clkgen_limits *limits = &axi_clkgen->limits;
400 unsigned int d, m, dout;
401 unsigned long long tmp;
402
403 axi_clkgen_calc_params(limits, req->best_parent_rate, req->rate,
404 &d, &m, &dout);
405
406 if (d == 0 || dout == 0 || m == 0)
407 return -EINVAL;
408
409 tmp = (unsigned long long)req->best_parent_rate * m;
410 tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
411
412 req->rate = min_t(unsigned long long, tmp, LONG_MAX);
413 return 0;
414 }
415
axi_clkgen_get_div(struct axi_clkgen * axi_clkgen,unsigned int reg1,unsigned int reg2)416 static unsigned int axi_clkgen_get_div(struct axi_clkgen *axi_clkgen,
417 unsigned int reg1, unsigned int reg2)
418 {
419 unsigned int val1, val2;
420 unsigned int div;
421
422 axi_clkgen_mmcm_read(axi_clkgen, reg2, &val2);
423 if (val2 & MMCM_CLKOUT_NOCOUNT)
424 return 8;
425
426 axi_clkgen_mmcm_read(axi_clkgen, reg1, &val1);
427
428 div = (val1 & 0x3f) + ((val1 >> 6) & 0x3f);
429 div <<= 3;
430
431 if (val2 & MMCM_CLK_DIV_DIVIDE) {
432 if ((val2 & BIT(7)) && (val2 & 0x7000) != 0x1000)
433 div += 8;
434 else
435 div += 16;
436
437 div += (val2 >> 12) & 0x7;
438 }
439
440 return div;
441 }
442
axi_clkgen_recalc_rate(struct clk_hw * clk_hw,unsigned long parent_rate)443 static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
444 unsigned long parent_rate)
445 {
446 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
447 unsigned int d, m, dout;
448 unsigned long long tmp;
449 unsigned int val;
450
451 dout = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLKOUT0_1,
452 MMCM_REG_CLKOUT0_2);
453 m = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLK_FB1,
454 MMCM_REG_CLK_FB2);
455
456 axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &val);
457 if (val & MMCM_CLK_DIV_NOCOUNT)
458 d = 1;
459 else
460 d = (val & 0x3f) + ((val >> 6) & 0x3f);
461
462 if (d == 0 || dout == 0)
463 return 0;
464
465 tmp = (unsigned long long)parent_rate * m;
466 tmp = DIV_ROUND_CLOSEST_ULL(tmp, dout * d);
467
468 return min_t(unsigned long long, tmp, ULONG_MAX);
469 }
470
axi_clkgen_enable(struct clk_hw * clk_hw)471 static int axi_clkgen_enable(struct clk_hw *clk_hw)
472 {
473 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
474
475 axi_clkgen_mmcm_enable(axi_clkgen, true);
476
477 return 0;
478 }
479
axi_clkgen_disable(struct clk_hw * clk_hw)480 static void axi_clkgen_disable(struct clk_hw *clk_hw)
481 {
482 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
483
484 axi_clkgen_mmcm_enable(axi_clkgen, false);
485 }
486
axi_clkgen_set_parent(struct clk_hw * clk_hw,u8 index)487 static int axi_clkgen_set_parent(struct clk_hw *clk_hw, u8 index)
488 {
489 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
490
491 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, index);
492
493 return 0;
494 }
495
axi_clkgen_get_parent(struct clk_hw * clk_hw)496 static u8 axi_clkgen_get_parent(struct clk_hw *clk_hw)
497 {
498 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
499 unsigned int parent;
500
501 axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, &parent);
502
503 return parent;
504 }
505
axi_clkgen_setup_limits(struct axi_clkgen * axi_clkgen,struct device * dev)506 static int axi_clkgen_setup_limits(struct axi_clkgen *axi_clkgen,
507 struct device *dev)
508 {
509 unsigned int tech, family, speed_grade, reg_value;
510
511 axi_clkgen_read(axi_clkgen, ADI_AXI_REG_FPGA_INFO, ®_value);
512 tech = ADI_AXI_INFO_FPGA_TECH(reg_value);
513 family = ADI_AXI_INFO_FPGA_FAMILY(reg_value);
514 speed_grade = ADI_AXI_INFO_FPGA_SPEED_GRADE(reg_value);
515
516 axi_clkgen->limits.fpfd_min = 10000;
517 axi_clkgen->limits.fvco_min = 600000;
518
519 switch (speed_grade) {
520 case ADI_AXI_FPGA_SPEED_1 ... ADI_AXI_FPGA_SPEED_1LV:
521 axi_clkgen->limits.fvco_max = 1200000;
522 axi_clkgen->limits.fpfd_max = 450000;
523 break;
524 case ADI_AXI_FPGA_SPEED_2 ... ADI_AXI_FPGA_SPEED_2LV:
525 axi_clkgen->limits.fvco_max = 1440000;
526 axi_clkgen->limits.fpfd_max = 500000;
527 if (family == ADI_AXI_FPGA_FAMILY_KINTEX || family == ADI_AXI_FPGA_FAMILY_ARTIX) {
528 axi_clkgen_read(axi_clkgen, ADI_CLKGEN_REG_FPGA_VOLTAGE,
529 ®_value);
530 if (ADI_CLKGEN_INFO_FPGA_VOLTAGE(reg_value) < 950) {
531 axi_clkgen->limits.fvco_max = 1200000;
532 axi_clkgen->limits.fpfd_max = 450000;
533 }
534 }
535 break;
536 case ADI_AXI_FPGA_SPEED_3:
537 axi_clkgen->limits.fvco_max = 1600000;
538 axi_clkgen->limits.fpfd_max = 550000;
539 break;
540 default:
541 return dev_err_probe(dev, -ENODEV, "Unknown speed grade %d\n",
542 speed_grade);
543 }
544
545 /* Overwrite vco limits for ultrascale+ */
546 if (tech == ADI_AXI_FPGA_TECH_ULTRASCALE_PLUS) {
547 axi_clkgen->limits.fvco_max = 1600000;
548 axi_clkgen->limits.fvco_min = 800000;
549 }
550
551 return 0;
552 }
553
554 static const struct clk_ops axi_clkgen_ops = {
555 .recalc_rate = axi_clkgen_recalc_rate,
556 .determine_rate = axi_clkgen_determine_rate,
557 .set_rate = axi_clkgen_set_rate,
558 .enable = axi_clkgen_enable,
559 .disable = axi_clkgen_disable,
560 .set_parent = axi_clkgen_set_parent,
561 .get_parent = axi_clkgen_get_parent,
562 };
563
axi_clkgen_probe(struct platform_device * pdev)564 static int axi_clkgen_probe(struct platform_device *pdev)
565 {
566 const struct axi_clkgen_limits *dflt_limits;
567 struct axi_clkgen *axi_clkgen;
568 unsigned int pcore_version;
569 struct clk_init_data init;
570 const char *parent_names[2];
571 const char *clk_name;
572 struct clk *axi_clk;
573 unsigned int i;
574 int ret;
575
576 dflt_limits = device_get_match_data(&pdev->dev);
577 if (!dflt_limits)
578 return -ENODEV;
579
580 axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
581 if (!axi_clkgen)
582 return -ENOMEM;
583
584 axi_clkgen->base = devm_platform_ioremap_resource(pdev, 0);
585 if (IS_ERR(axi_clkgen->base))
586 return PTR_ERR(axi_clkgen->base);
587
588 init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
589
590 axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
591 if (!IS_ERR(axi_clk)) {
592 if (init.num_parents < 2 || init.num_parents > 3)
593 return -EINVAL;
594
595 init.num_parents -= 1;
596 } else {
597 /*
598 * Legacy... So that old DTs which do not have clock-names still
599 * work. In this case we don't explicitly enable the AXI bus
600 * clock.
601 */
602 if (PTR_ERR(axi_clk) != -ENOENT)
603 return PTR_ERR(axi_clk);
604 if (init.num_parents < 1 || init.num_parents > 2)
605 return -EINVAL;
606 }
607
608 for (i = 0; i < init.num_parents; i++) {
609 parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);
610 if (!parent_names[i])
611 return -EINVAL;
612 }
613
614 axi_clkgen_read(axi_clkgen, ADI_AXI_REG_VERSION, &pcore_version);
615
616 if (ADI_AXI_PCORE_VER_MAJOR(pcore_version) > 0x04) {
617 ret = axi_clkgen_setup_limits(axi_clkgen, &pdev->dev);
618 if (ret)
619 return ret;
620 } else {
621 memcpy(&axi_clkgen->limits, dflt_limits,
622 sizeof(axi_clkgen->limits));
623 }
624
625 clk_name = pdev->dev.of_node->name;
626 of_property_read_string(pdev->dev.of_node, "clock-output-names",
627 &clk_name);
628
629 init.name = clk_name;
630 init.ops = &axi_clkgen_ops;
631 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
632 init.parent_names = parent_names;
633
634 axi_clkgen_mmcm_enable(axi_clkgen, false);
635
636 axi_clkgen->clk_hw.init = &init;
637 ret = devm_clk_hw_register(&pdev->dev, &axi_clkgen->clk_hw);
638 if (ret)
639 return ret;
640
641 return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
642 &axi_clkgen->clk_hw);
643 }
644
645 static const struct of_device_id axi_clkgen_ids[] = {
646 {
647 .compatible = "adi,zynqmp-axi-clkgen-2.00.a",
648 .data = &axi_clkgen_zynqmp_default_limits,
649 },
650 {
651 .compatible = "adi,axi-clkgen-2.00.a",
652 .data = &axi_clkgen_zynq_default_limits,
653 },
654 { }
655 };
656 MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
657
658 static struct platform_driver axi_clkgen_driver = {
659 .driver = {
660 .name = "adi-axi-clkgen",
661 .of_match_table = axi_clkgen_ids,
662 },
663 .probe = axi_clkgen_probe,
664 };
665 module_platform_driver(axi_clkgen_driver);
666
667 MODULE_LICENSE("GPL v2");
668 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
669 MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
670