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/clk.h>
14 #include <linux/slab.h>
17 #include <linux/module.h>
18 #include <linux/err.h>
20 #define AXI_CLKGEN_V1_REG_UPDATE_ENABLE 0x04
21 #define AXI_CLKGEN_V1_REG_CLK_OUT1 0x08
22 #define AXI_CLKGEN_V1_REG_CLK_OUT2 0x0c
23 #define AXI_CLKGEN_V1_REG_CLK_DIV 0x10
24 #define AXI_CLKGEN_V1_REG_CLK_FB1 0x14
25 #define AXI_CLKGEN_V1_REG_CLK_FB2 0x18
26 #define AXI_CLKGEN_V1_REG_LOCK1 0x1c
27 #define AXI_CLKGEN_V1_REG_LOCK2 0x20
28 #define AXI_CLKGEN_V1_REG_LOCK3 0x24
29 #define AXI_CLKGEN_V1_REG_FILTER1 0x28
30 #define AXI_CLKGEN_V1_REG_FILTER2 0x2c
32 #define AXI_CLKGEN_V2_REG_RESET 0x40
33 #define AXI_CLKGEN_V2_REG_DRP_CNTRL 0x70
34 #define AXI_CLKGEN_V2_REG_DRP_STATUS 0x74
36 #define AXI_CLKGEN_V2_RESET_MMCM_ENABLE BIT(1)
37 #define AXI_CLKGEN_V2_RESET_ENABLE BIT(0)
39 #define AXI_CLKGEN_V2_DRP_CNTRL_SEL BIT(29)
40 #define AXI_CLKGEN_V2_DRP_CNTRL_READ BIT(28)
42 #define AXI_CLKGEN_V2_DRP_STATUS_BUSY BIT(16)
44 #define MMCM_REG_CLKOUT0_1 0x08
45 #define MMCM_REG_CLKOUT0_2 0x09
46 #define MMCM_REG_CLK_FB1 0x14
47 #define MMCM_REG_CLK_FB2 0x15
48 #define MMCM_REG_CLK_DIV 0x16
49 #define MMCM_REG_LOCK1 0x18
50 #define MMCM_REG_LOCK2 0x19
51 #define MMCM_REG_LOCK3 0x1a
52 #define MMCM_REG_FILTER1 0x4e
53 #define MMCM_REG_FILTER2 0x4f
57 struct axi_clkgen_mmcm_ops
{
58 void (*enable
)(struct axi_clkgen
*axi_clkgen
, bool enable
);
59 int (*write
)(struct axi_clkgen
*axi_clkgen
, unsigned int reg
,
60 unsigned int val
, unsigned int mask
);
61 int (*read
)(struct axi_clkgen
*axi_clkgen
, unsigned int reg
,
67 const struct axi_clkgen_mmcm_ops
*mmcm_ops
;
71 static void axi_clkgen_mmcm_enable(struct axi_clkgen
*axi_clkgen
,
74 axi_clkgen
->mmcm_ops
->enable(axi_clkgen
, enable
);
77 static int axi_clkgen_mmcm_write(struct axi_clkgen
*axi_clkgen
,
78 unsigned int reg
, unsigned int val
, unsigned int mask
)
80 return axi_clkgen
->mmcm_ops
->write(axi_clkgen
, reg
, val
, mask
);
83 static int axi_clkgen_mmcm_read(struct axi_clkgen
*axi_clkgen
,
84 unsigned int reg
, unsigned int *val
)
86 return axi_clkgen
->mmcm_ops
->read(axi_clkgen
, reg
, val
);
89 static uint32_t axi_clkgen_lookup_filter(unsigned int m
)
119 static const uint32_t axi_clkgen_lock_table
[] = {
120 0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
121 0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
122 0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
123 0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
124 0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
125 0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
126 0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
127 0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
128 0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
131 static uint32_t axi_clkgen_lookup_lock(unsigned int m
)
133 if (m
< ARRAY_SIZE(axi_clkgen_lock_table
))
134 return axi_clkgen_lock_table
[m
];
138 static const unsigned int fpfd_min
= 10000;
139 static const unsigned int fpfd_max
= 300000;
140 static const unsigned int fvco_min
= 600000;
141 static const unsigned int fvco_max
= 1200000;
143 static void axi_clkgen_calc_params(unsigned long fin
, unsigned long fout
,
144 unsigned int *best_d
, unsigned int *best_m
, unsigned int *best_dout
)
146 unsigned long d
, d_min
, d_max
, _d_min
, _d_max
;
147 unsigned long m
, m_min
, m_max
;
148 unsigned long f
, dout
, best_f
, fvco
;
158 d_min
= max_t(unsigned long, DIV_ROUND_UP(fin
, fpfd_max
), 1);
159 d_max
= min_t(unsigned long, fin
/ fpfd_min
, 80);
161 m_min
= max_t(unsigned long, DIV_ROUND_UP(fvco_min
, fin
) * d_min
, 1);
162 m_max
= min_t(unsigned long, fvco_max
* d_max
/ fin
, 64);
164 for (m
= m_min
; m
<= m_max
; m
++) {
165 _d_min
= max(d_min
, DIV_ROUND_UP(fin
* m
, fvco_max
));
166 _d_max
= min(d_max
, fin
* m
/ fvco_min
);
168 for (d
= _d_min
; d
<= _d_max
; d
++) {
171 dout
= DIV_ROUND_CLOSEST(fvco
, fout
);
172 dout
= clamp_t(unsigned long, dout
, 1, 128);
174 if (abs(f
- fout
) < abs(best_f
- fout
)) {
186 static void axi_clkgen_calc_clk_params(unsigned int divider
, unsigned int *low
,
187 unsigned int *high
, unsigned int *edge
, unsigned int *nocount
)
196 *low
= divider
- *high
;
199 static void axi_clkgen_write(struct axi_clkgen
*axi_clkgen
,
200 unsigned int reg
, unsigned int val
)
202 writel(val
, axi_clkgen
->base
+ reg
);
205 static void axi_clkgen_read(struct axi_clkgen
*axi_clkgen
,
206 unsigned int reg
, unsigned int *val
)
208 *val
= readl(axi_clkgen
->base
+ reg
);
211 static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg
)
214 case MMCM_REG_CLKOUT0_1
:
215 return AXI_CLKGEN_V1_REG_CLK_OUT1
;
216 case MMCM_REG_CLKOUT0_2
:
217 return AXI_CLKGEN_V1_REG_CLK_OUT2
;
218 case MMCM_REG_CLK_FB1
:
219 return AXI_CLKGEN_V1_REG_CLK_FB1
;
220 case MMCM_REG_CLK_FB2
:
221 return AXI_CLKGEN_V1_REG_CLK_FB2
;
222 case MMCM_REG_CLK_DIV
:
223 return AXI_CLKGEN_V1_REG_CLK_DIV
;
225 return AXI_CLKGEN_V1_REG_LOCK1
;
227 return AXI_CLKGEN_V1_REG_LOCK2
;
229 return AXI_CLKGEN_V1_REG_LOCK3
;
230 case MMCM_REG_FILTER1
:
231 return AXI_CLKGEN_V1_REG_FILTER1
;
232 case MMCM_REG_FILTER2
:
233 return AXI_CLKGEN_V1_REG_FILTER2
;
239 static int axi_clkgen_v1_mmcm_write(struct axi_clkgen
*axi_clkgen
,
240 unsigned int reg
, unsigned int val
, unsigned int mask
)
242 reg
= axi_clkgen_v1_map_mmcm_reg(reg
);
246 axi_clkgen_write(axi_clkgen
, reg
, val
);
251 static int axi_clkgen_v1_mmcm_read(struct axi_clkgen
*axi_clkgen
,
252 unsigned int reg
, unsigned int *val
)
254 reg
= axi_clkgen_v1_map_mmcm_reg(reg
);
258 axi_clkgen_read(axi_clkgen
, reg
, val
);
263 static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen
*axi_clkgen
,
266 axi_clkgen_write(axi_clkgen
, AXI_CLKGEN_V1_REG_UPDATE_ENABLE
, enable
);
269 static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops
= {
270 .write
= axi_clkgen_v1_mmcm_write
,
271 .read
= axi_clkgen_v1_mmcm_read
,
272 .enable
= axi_clkgen_v1_mmcm_enable
,
275 static int axi_clkgen_wait_non_busy(struct axi_clkgen
*axi_clkgen
)
277 unsigned int timeout
= 10000;
281 axi_clkgen_read(axi_clkgen
, AXI_CLKGEN_V2_REG_DRP_STATUS
, &val
);
282 } while ((val
& AXI_CLKGEN_V2_DRP_STATUS_BUSY
) && --timeout
);
284 if (val
& AXI_CLKGEN_V2_DRP_STATUS_BUSY
)
290 static int axi_clkgen_v2_mmcm_read(struct axi_clkgen
*axi_clkgen
,
291 unsigned int reg
, unsigned int *val
)
293 unsigned int reg_val
;
296 ret
= axi_clkgen_wait_non_busy(axi_clkgen
);
300 reg_val
= AXI_CLKGEN_V2_DRP_CNTRL_SEL
| AXI_CLKGEN_V2_DRP_CNTRL_READ
;
301 reg_val
|= (reg
<< 16);
303 axi_clkgen_write(axi_clkgen
, AXI_CLKGEN_V2_REG_DRP_CNTRL
, reg_val
);
305 ret
= axi_clkgen_wait_non_busy(axi_clkgen
);
314 static int axi_clkgen_v2_mmcm_write(struct axi_clkgen
*axi_clkgen
,
315 unsigned int reg
, unsigned int val
, unsigned int mask
)
317 unsigned int reg_val
= 0;
320 ret
= axi_clkgen_wait_non_busy(axi_clkgen
);
324 if (mask
!= 0xffff) {
325 axi_clkgen_v2_mmcm_read(axi_clkgen
, reg
, ®_val
);
329 reg_val
|= AXI_CLKGEN_V2_DRP_CNTRL_SEL
| (reg
<< 16) | (val
& mask
);
331 axi_clkgen_write(axi_clkgen
, AXI_CLKGEN_V2_REG_DRP_CNTRL
, reg_val
);
336 static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen
*axi_clkgen
,
339 unsigned int val
= AXI_CLKGEN_V2_RESET_ENABLE
;
342 val
|= AXI_CLKGEN_V2_RESET_MMCM_ENABLE
;
344 axi_clkgen_write(axi_clkgen
, AXI_CLKGEN_V2_REG_RESET
, val
);
347 static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops
= {
348 .write
= axi_clkgen_v2_mmcm_write
,
349 .read
= axi_clkgen_v2_mmcm_read
,
350 .enable
= axi_clkgen_v2_mmcm_enable
,
353 static struct axi_clkgen
*clk_hw_to_axi_clkgen(struct clk_hw
*clk_hw
)
355 return container_of(clk_hw
, struct axi_clkgen
, clk_hw
);
358 static int axi_clkgen_set_rate(struct clk_hw
*clk_hw
,
359 unsigned long rate
, unsigned long parent_rate
)
361 struct axi_clkgen
*axi_clkgen
= clk_hw_to_axi_clkgen(clk_hw
);
362 unsigned int d
, m
, dout
;
363 unsigned int nocount
;
370 if (parent_rate
== 0 || rate
== 0)
373 axi_clkgen_calc_params(parent_rate
, rate
, &d
, &m
, &dout
);
375 if (d
== 0 || dout
== 0 || m
== 0)
378 filter
= axi_clkgen_lookup_filter(m
- 1);
379 lock
= axi_clkgen_lookup_lock(m
- 1);
381 axi_clkgen_calc_clk_params(dout
, &low
, &high
, &edge
, &nocount
);
382 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_CLKOUT0_1
,
383 (high
<< 6) | low
, 0xefff);
384 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_CLKOUT0_2
,
385 (edge
<< 7) | (nocount
<< 6), 0x03ff);
387 axi_clkgen_calc_clk_params(d
, &low
, &high
, &edge
, &nocount
);
388 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_CLK_DIV
,
389 (edge
<< 13) | (nocount
<< 12) | (high
<< 6) | low
, 0x3fff);
391 axi_clkgen_calc_clk_params(m
, &low
, &high
, &edge
, &nocount
);
392 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_CLK_FB1
,
393 (high
<< 6) | low
, 0xefff);
394 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_CLK_FB2
,
395 (edge
<< 7) | (nocount
<< 6), 0x03ff);
397 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_LOCK1
, lock
& 0x3ff, 0x3ff);
398 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_LOCK2
,
399 (((lock
>> 16) & 0x1f) << 10) | 0x1, 0x7fff);
400 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_LOCK3
,
401 (((lock
>> 24) & 0x1f) << 10) | 0x3e9, 0x7fff);
402 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_FILTER1
, filter
>> 16, 0x9900);
403 axi_clkgen_mmcm_write(axi_clkgen
, MMCM_REG_FILTER2
, filter
, 0x9900);
408 static long axi_clkgen_round_rate(struct clk_hw
*hw
, unsigned long rate
,
409 unsigned long *parent_rate
)
411 unsigned int d
, m
, dout
;
413 axi_clkgen_calc_params(*parent_rate
, rate
, &d
, &m
, &dout
);
415 if (d
== 0 || dout
== 0 || m
== 0)
418 return *parent_rate
/ d
* m
/ dout
;
421 static unsigned long axi_clkgen_recalc_rate(struct clk_hw
*clk_hw
,
422 unsigned long parent_rate
)
424 struct axi_clkgen
*axi_clkgen
= clk_hw_to_axi_clkgen(clk_hw
);
425 unsigned int d
, m
, dout
;
427 unsigned long long tmp
;
429 axi_clkgen_mmcm_read(axi_clkgen
, MMCM_REG_CLKOUT0_1
, ®
);
430 dout
= (reg
& 0x3f) + ((reg
>> 6) & 0x3f);
431 axi_clkgen_mmcm_read(axi_clkgen
, MMCM_REG_CLK_DIV
, ®
);
432 d
= (reg
& 0x3f) + ((reg
>> 6) & 0x3f);
433 axi_clkgen_mmcm_read(axi_clkgen
, MMCM_REG_CLK_FB1
, ®
);
434 m
= (reg
& 0x3f) + ((reg
>> 6) & 0x3f);
436 if (d
== 0 || dout
== 0)
439 tmp
= (unsigned long long)(parent_rate
/ d
) * m
;
448 static int axi_clkgen_enable(struct clk_hw
*clk_hw
)
450 struct axi_clkgen
*axi_clkgen
= clk_hw_to_axi_clkgen(clk_hw
);
452 axi_clkgen_mmcm_enable(axi_clkgen
, true);
457 static void axi_clkgen_disable(struct clk_hw
*clk_hw
)
459 struct axi_clkgen
*axi_clkgen
= clk_hw_to_axi_clkgen(clk_hw
);
461 axi_clkgen_mmcm_enable(axi_clkgen
, false);
464 static const struct clk_ops axi_clkgen_ops
= {
465 .recalc_rate
= axi_clkgen_recalc_rate
,
466 .round_rate
= axi_clkgen_round_rate
,
467 .set_rate
= axi_clkgen_set_rate
,
468 .enable
= axi_clkgen_enable
,
469 .disable
= axi_clkgen_disable
,
472 static const struct of_device_id axi_clkgen_ids
[] = {
474 .compatible
= "adi,axi-clkgen-1.00.a",
475 .data
= &axi_clkgen_v1_mmcm_ops
477 .compatible
= "adi,axi-clkgen-2.00.a",
478 .data
= &axi_clkgen_v2_mmcm_ops
,
482 MODULE_DEVICE_TABLE(of
, axi_clkgen_ids
);
484 static int axi_clkgen_probe(struct platform_device
*pdev
)
486 const struct of_device_id
*id
;
487 struct axi_clkgen
*axi_clkgen
;
488 struct clk_init_data init
;
489 const char *parent_name
;
490 const char *clk_name
;
491 struct resource
*mem
;
494 if (!pdev
->dev
.of_node
)
497 id
= of_match_node(axi_clkgen_ids
, pdev
->dev
.of_node
);
501 axi_clkgen
= devm_kzalloc(&pdev
->dev
, sizeof(*axi_clkgen
), GFP_KERNEL
);
505 axi_clkgen
->mmcm_ops
= id
->data
;
507 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
508 axi_clkgen
->base
= devm_ioremap_resource(&pdev
->dev
, mem
);
509 if (IS_ERR(axi_clkgen
->base
))
510 return PTR_ERR(axi_clkgen
->base
);
512 parent_name
= of_clk_get_parent_name(pdev
->dev
.of_node
, 0);
516 clk_name
= pdev
->dev
.of_node
->name
;
517 of_property_read_string(pdev
->dev
.of_node
, "clock-output-names",
520 init
.name
= clk_name
;
521 init
.ops
= &axi_clkgen_ops
;
522 init
.flags
= CLK_SET_RATE_GATE
;
523 init
.parent_names
= &parent_name
;
524 init
.num_parents
= 1;
526 axi_clkgen_mmcm_enable(axi_clkgen
, false);
528 axi_clkgen
->clk_hw
.init
= &init
;
529 clk
= devm_clk_register(&pdev
->dev
, &axi_clkgen
->clk_hw
);
533 return of_clk_add_provider(pdev
->dev
.of_node
, of_clk_src_simple_get
,
537 static int axi_clkgen_remove(struct platform_device
*pdev
)
539 of_clk_del_provider(pdev
->dev
.of_node
);
544 static struct platform_driver axi_clkgen_driver
= {
546 .name
= "adi-axi-clkgen",
547 .of_match_table
= axi_clkgen_ids
,
549 .probe
= axi_clkgen_probe
,
550 .remove
= axi_clkgen_remove
,
552 module_platform_driver(axi_clkgen_driver
);
554 MODULE_LICENSE("GPL v2");
555 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
556 MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");