4 * Copyright 2012-2013 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
7 * Licensed under the GPL-2.
11 #include <linux/platform_device.h>
12 #include <linux/clk-provider.h>
13 #include <linux/slab.h>
16 #include <linux/module.h>
17 #include <linux/err.h>
19 #define AXI_CLKGEN_V1_REG_UPDATE_ENABLE 0x04
20 #define AXI_CLKGEN_V1_REG_CLK_OUT1 0x08
21 #define AXI_CLKGEN_V1_REG_CLK_OUT2 0x0c
22 #define AXI_CLKGEN_V1_REG_CLK_DIV 0x10
23 #define AXI_CLKGEN_V1_REG_CLK_FB1 0x14
24 #define AXI_CLKGEN_V1_REG_CLK_FB2 0x18
25 #define AXI_CLKGEN_V1_REG_LOCK1 0x1c
26 #define AXI_CLKGEN_V1_REG_LOCK2 0x20
27 #define AXI_CLKGEN_V1_REG_LOCK3 0x24
28 #define AXI_CLKGEN_V1_REG_FILTER1 0x28
29 #define AXI_CLKGEN_V1_REG_FILTER2 0x2c
31 #define AXI_CLKGEN_V2_REG_RESET 0x40
32 #define AXI_CLKGEN_V2_REG_DRP_CNTRL 0x70
33 #define AXI_CLKGEN_V2_REG_DRP_STATUS 0x74
35 #define AXI_CLKGEN_V2_RESET_MMCM_ENABLE BIT(1)
36 #define AXI_CLKGEN_V2_RESET_ENABLE BIT(0)
38 #define AXI_CLKGEN_V2_DRP_CNTRL_SEL BIT(29)
39 #define AXI_CLKGEN_V2_DRP_CNTRL_READ BIT(28)
41 #define AXI_CLKGEN_V2_DRP_STATUS_BUSY BIT(16)
43 #define MMCM_REG_CLKOUT0_1 0x08
44 #define MMCM_REG_CLKOUT0_2 0x09
45 #define MMCM_REG_CLK_FB1 0x14
46 #define MMCM_REG_CLK_FB2 0x15
47 #define MMCM_REG_CLK_DIV 0x16
48 #define MMCM_REG_LOCK1 0x18
49 #define MMCM_REG_LOCK2 0x19
50 #define MMCM_REG_LOCK3 0x1a
51 #define MMCM_REG_FILTER1 0x4e
52 #define MMCM_REG_FILTER2 0x4f
56 struct axi_clkgen_mmcm_ops {
57 void (*enable)(struct axi_clkgen *axi_clkgen, bool enable);
58 int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg,
59 unsigned int val, unsigned int mask);
60 int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg,
66 const struct axi_clkgen_mmcm_ops *mmcm_ops;
70 static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
73 axi_clkgen->mmcm_ops->enable(axi_clkgen, enable);
76 static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
77 unsigned int reg, unsigned int val, unsigned int mask)
79 return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask);
82 static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
83 unsigned int reg, unsigned int *val)
85 return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val);
88 static uint32_t axi_clkgen_lookup_filter(unsigned int m)
118 static const uint32_t axi_clkgen_lock_table[] = {
119 0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
120 0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
121 0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
122 0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
123 0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
124 0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
125 0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
126 0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
127 0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
130 static uint32_t axi_clkgen_lookup_lock(unsigned int m)
132 if (m < ARRAY_SIZE(axi_clkgen_lock_table))
133 return axi_clkgen_lock_table[m];
137 static const unsigned int fpfd_min = 10000;
138 static const unsigned int fpfd_max = 300000;
139 static const unsigned int fvco_min = 600000;
140 static const unsigned int fvco_max = 1200000;
142 static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
143 unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
145 unsigned long d, d_min, d_max, _d_min, _d_max;
146 unsigned long m, m_min, m_max;
147 unsigned long f, dout, best_f, fvco;
157 d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
158 d_max = min_t(unsigned long, fin / fpfd_min, 80);
160 m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
161 m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
163 for (m = m_min; m <= m_max; m++) {
164 _d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
165 _d_max = min(d_max, fin * m / fvco_min);
167 for (d = _d_min; d <= _d_max; d++) {
170 dout = DIV_ROUND_CLOSEST(fvco, fout);
171 dout = clamp_t(unsigned long, dout, 1, 128);
173 if (abs(f - fout) < abs(best_f - fout)) {
185 static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
186 unsigned int *high, unsigned int *edge, unsigned int *nocount)
195 *low = divider - *high;
198 static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
199 unsigned int reg, unsigned int val)
201 writel(val, axi_clkgen->base + reg);
204 static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
205 unsigned int reg, unsigned int *val)
207 *val = readl(axi_clkgen->base + reg);
210 static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg)
213 case MMCM_REG_CLKOUT0_1:
214 return AXI_CLKGEN_V1_REG_CLK_OUT1;
215 case MMCM_REG_CLKOUT0_2:
216 return AXI_CLKGEN_V1_REG_CLK_OUT2;
217 case MMCM_REG_CLK_FB1:
218 return AXI_CLKGEN_V1_REG_CLK_FB1;
219 case MMCM_REG_CLK_FB2:
220 return AXI_CLKGEN_V1_REG_CLK_FB2;
221 case MMCM_REG_CLK_DIV:
222 return AXI_CLKGEN_V1_REG_CLK_DIV;
224 return AXI_CLKGEN_V1_REG_LOCK1;
226 return AXI_CLKGEN_V1_REG_LOCK2;
228 return AXI_CLKGEN_V1_REG_LOCK3;
229 case MMCM_REG_FILTER1:
230 return AXI_CLKGEN_V1_REG_FILTER1;
231 case MMCM_REG_FILTER2:
232 return AXI_CLKGEN_V1_REG_FILTER2;
238 static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen,
239 unsigned int reg, unsigned int val, unsigned int mask)
241 reg = axi_clkgen_v1_map_mmcm_reg(reg);
245 axi_clkgen_write(axi_clkgen, reg, val);
250 static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen,
251 unsigned int reg, unsigned int *val)
253 reg = axi_clkgen_v1_map_mmcm_reg(reg);
257 axi_clkgen_read(axi_clkgen, reg, val);
262 static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen,
265 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable);
268 static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = {
269 .write = axi_clkgen_v1_mmcm_write,
270 .read = axi_clkgen_v1_mmcm_read,
271 .enable = axi_clkgen_v1_mmcm_enable,
274 static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
276 unsigned int timeout = 10000;
280 axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_STATUS, &val);
281 } while ((val & AXI_CLKGEN_V2_DRP_STATUS_BUSY) && --timeout);
283 if (val & AXI_CLKGEN_V2_DRP_STATUS_BUSY)
289 static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen,
290 unsigned int reg, unsigned int *val)
292 unsigned int reg_val;
295 ret = axi_clkgen_wait_non_busy(axi_clkgen);
299 reg_val = AXI_CLKGEN_V2_DRP_CNTRL_SEL | AXI_CLKGEN_V2_DRP_CNTRL_READ;
300 reg_val |= (reg << 16);
302 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
304 ret = axi_clkgen_wait_non_busy(axi_clkgen);
313 static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
314 unsigned int reg, unsigned int val, unsigned int mask)
316 unsigned int reg_val = 0;
319 ret = axi_clkgen_wait_non_busy(axi_clkgen);
323 if (mask != 0xffff) {
324 axi_clkgen_v2_mmcm_read(axi_clkgen, reg, ®_val);
328 reg_val |= AXI_CLKGEN_V2_DRP_CNTRL_SEL | (reg << 16) | (val & mask);
330 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_DRP_CNTRL, reg_val);
335 static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen,
338 unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
341 val |= AXI_CLKGEN_V2_RESET_MMCM_ENABLE;
343 axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
346 static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = {
347 .write = axi_clkgen_v2_mmcm_write,
348 .read = axi_clkgen_v2_mmcm_read,
349 .enable = axi_clkgen_v2_mmcm_enable,
352 static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
354 return container_of(clk_hw, struct axi_clkgen, clk_hw);
357 static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
358 unsigned long rate, unsigned long parent_rate)
360 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
361 unsigned int d, m, dout;
362 unsigned int nocount;
369 if (parent_rate == 0 || rate == 0)
372 axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
374 if (d == 0 || dout == 0 || m == 0)
377 filter = axi_clkgen_lookup_filter(m - 1);
378 lock = axi_clkgen_lookup_lock(m - 1);
380 axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
381 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1,
382 (high << 6) | low, 0xefff);
383 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2,
384 (edge << 7) | (nocount << 6), 0x03ff);
386 axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
387 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
388 (edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff);
390 axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
391 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1,
392 (high << 6) | low, 0xefff);
393 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2,
394 (edge << 7) | (nocount << 6), 0x03ff);
396 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
397 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
398 (((lock >> 16) & 0x1f) << 10) | 0x1, 0x7fff);
399 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK3,
400 (((lock >> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
401 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER1, filter >> 16, 0x9900);
402 axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_FILTER2, filter, 0x9900);
407 static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
408 unsigned long *parent_rate)
410 unsigned int d, m, dout;
412 axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
414 if (d == 0 || dout == 0 || m == 0)
417 return *parent_rate / d * m / dout;
420 static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
421 unsigned long parent_rate)
423 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
424 unsigned int d, m, dout;
426 unsigned long long tmp;
428 axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®);
429 dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
430 axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®);
431 d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
432 axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®);
433 m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
435 if (d == 0 || dout == 0)
438 tmp = (unsigned long long)(parent_rate / d) * m;
447 static int axi_clkgen_enable(struct clk_hw *clk_hw)
449 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
451 axi_clkgen_mmcm_enable(axi_clkgen, true);
456 static void axi_clkgen_disable(struct clk_hw *clk_hw)
458 struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
460 axi_clkgen_mmcm_enable(axi_clkgen, false);
463 static const struct clk_ops axi_clkgen_ops = {
464 .recalc_rate = axi_clkgen_recalc_rate,
465 .round_rate = axi_clkgen_round_rate,
466 .set_rate = axi_clkgen_set_rate,
467 .enable = axi_clkgen_enable,
468 .disable = axi_clkgen_disable,
471 static const struct of_device_id axi_clkgen_ids[] = {
473 .compatible = "adi,axi-clkgen-1.00.a",
474 .data = &axi_clkgen_v1_mmcm_ops
476 .compatible = "adi,axi-clkgen-2.00.a",
477 .data = &axi_clkgen_v2_mmcm_ops,
481 MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
483 static int axi_clkgen_probe(struct platform_device *pdev)
485 const struct of_device_id *id;
486 struct axi_clkgen *axi_clkgen;
487 struct clk_init_data init;
488 const char *parent_name;
489 const char *clk_name;
490 struct resource *mem;
493 if (!pdev->dev.of_node)
496 id = of_match_node(axi_clkgen_ids, pdev->dev.of_node);
500 axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
504 axi_clkgen->mmcm_ops = id->data;
506 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
507 axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
508 if (IS_ERR(axi_clkgen->base))
509 return PTR_ERR(axi_clkgen->base);
511 parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
515 clk_name = pdev->dev.of_node->name;
516 of_property_read_string(pdev->dev.of_node, "clock-output-names",
519 init.name = clk_name;
520 init.ops = &axi_clkgen_ops;
521 init.flags = CLK_SET_RATE_GATE;
522 init.parent_names = &parent_name;
523 init.num_parents = 1;
525 axi_clkgen_mmcm_enable(axi_clkgen, false);
527 axi_clkgen->clk_hw.init = &init;
528 clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
532 return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
536 static int axi_clkgen_remove(struct platform_device *pdev)
538 of_clk_del_provider(pdev->dev.of_node);
543 static struct platform_driver axi_clkgen_driver = {
545 .name = "adi-axi-clkgen",
546 .of_match_table = axi_clkgen_ids,
548 .probe = axi_clkgen_probe,
549 .remove = axi_clkgen_remove,
551 module_platform_driver(axi_clkgen_driver);
553 MODULE_LICENSE("GPL v2");
554 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
555 MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");