2 * Copyright (C) 2014 Free Electrons
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
7 * Allwinner A31 AR100 clock driver
11 #include <linux/clk-provider.h>
12 #include <linux/module.h>
14 #include <linux/platform_device.h>
16 #define SUN6I_AR100_MAX_PARENTS 4
17 #define SUN6I_AR100_SHIFT_MASK 0x3
18 #define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK
19 #define SUN6I_AR100_SHIFT_SHIFT 4
20 #define SUN6I_AR100_DIV_MASK 0x1f
21 #define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1)
22 #define SUN6I_AR100_DIV_SHIFT 8
23 #define SUN6I_AR100_MUX_MASK 0x3
24 #define SUN6I_AR100_MUX_SHIFT 16
31 static inline struct ar100_clk
*to_ar100_clk(struct clk_hw
*hw
)
33 return container_of(hw
, struct ar100_clk
, hw
);
36 static unsigned long ar100_recalc_rate(struct clk_hw
*hw
,
37 unsigned long parent_rate
)
39 struct ar100_clk
*clk
= to_ar100_clk(hw
);
40 u32 val
= readl(clk
->reg
);
41 int shift
= (val
>> SUN6I_AR100_SHIFT_SHIFT
) & SUN6I_AR100_SHIFT_MASK
;
42 int div
= (val
>> SUN6I_AR100_DIV_SHIFT
) & SUN6I_AR100_DIV_MASK
;
44 return (parent_rate
>> shift
) / (div
+ 1);
47 static long ar100_determine_rate(struct clk_hw
*hw
, unsigned long rate
,
48 unsigned long *best_parent_rate
,
49 struct clk
**best_parent_clk
)
51 int nparents
= __clk_get_num_parents(hw
->clk
);
52 long best_rate
= -EINVAL
;
55 *best_parent_clk
= NULL
;
57 for (i
= 0; i
< nparents
; i
++) {
58 unsigned long parent_rate
;
59 unsigned long tmp_rate
;
64 parent
= clk_get_parent_by_index(hw
->clk
, i
);
65 parent_rate
= __clk_get_rate(parent
);
66 div
= DIV_ROUND_UP(parent_rate
, rate
);
69 * The AR100 clk contains 2 divisors:
70 * - one power of 2 divisor
71 * - one regular divisor
73 * First check if we can safely shift (or divide by a power
74 * of 2) without losing precision on the requested rate.
77 if (shift
> SUN6I_AR100_SHIFT_MAX
)
78 shift
= SUN6I_AR100_SHIFT_MAX
;
83 * Then if the divisor is still bigger than what the HW
84 * actually supports, use a bigger shift (or power of 2
85 * divider) value and accept to lose some precision.
87 while (div
> SUN6I_AR100_DIV_MAX
) {
90 if (shift
> SUN6I_AR100_SHIFT_MAX
)
95 * If the shift value (or power of 2 divider) is bigger
96 * than what the HW actually support, skip this parent.
98 if (shift
> SUN6I_AR100_SHIFT_MAX
)
101 tmp_rate
= (parent_rate
>> shift
) / div
;
102 if (!*best_parent_clk
|| tmp_rate
> best_rate
) {
103 *best_parent_clk
= parent
;
104 *best_parent_rate
= parent_rate
;
105 best_rate
= tmp_rate
;
112 static int ar100_set_parent(struct clk_hw
*hw
, u8 index
)
114 struct ar100_clk
*clk
= to_ar100_clk(hw
);
115 u32 val
= readl(clk
->reg
);
117 if (index
>= SUN6I_AR100_MAX_PARENTS
)
120 val
&= ~(SUN6I_AR100_MUX_MASK
<< SUN6I_AR100_MUX_SHIFT
);
121 val
|= (index
<< SUN6I_AR100_MUX_SHIFT
);
122 writel(val
, clk
->reg
);
127 static u8
ar100_get_parent(struct clk_hw
*hw
)
129 struct ar100_clk
*clk
= to_ar100_clk(hw
);
130 return (readl(clk
->reg
) >> SUN6I_AR100_MUX_SHIFT
) &
131 SUN6I_AR100_MUX_MASK
;
134 static int ar100_set_rate(struct clk_hw
*hw
, unsigned long rate
,
135 unsigned long parent_rate
)
137 unsigned long div
= parent_rate
/ rate
;
138 struct ar100_clk
*clk
= to_ar100_clk(hw
);
139 u32 val
= readl(clk
->reg
);
142 if (parent_rate
% rate
)
145 shift
= ffs(div
) - 1;
146 if (shift
> SUN6I_AR100_SHIFT_MAX
)
147 shift
= SUN6I_AR100_SHIFT_MAX
;
151 if (div
> SUN6I_AR100_DIV_MAX
)
154 val
&= ~((SUN6I_AR100_SHIFT_MASK
<< SUN6I_AR100_SHIFT_SHIFT
) |
155 (SUN6I_AR100_DIV_MASK
<< SUN6I_AR100_DIV_SHIFT
));
156 val
|= (shift
<< SUN6I_AR100_SHIFT_SHIFT
) |
157 (div
<< SUN6I_AR100_DIV_SHIFT
);
158 writel(val
, clk
->reg
);
163 struct clk_ops ar100_ops
= {
164 .recalc_rate
= ar100_recalc_rate
,
165 .determine_rate
= ar100_determine_rate
,
166 .set_parent
= ar100_set_parent
,
167 .get_parent
= ar100_get_parent
,
168 .set_rate
= ar100_set_rate
,
171 static int sun6i_a31_ar100_clk_probe(struct platform_device
*pdev
)
173 const char *parents
[SUN6I_AR100_MAX_PARENTS
];
174 struct device_node
*np
= pdev
->dev
.of_node
;
175 const char *clk_name
= np
->name
;
176 struct clk_init_data init
;
177 struct ar100_clk
*ar100
;
183 ar100
= devm_kzalloc(&pdev
->dev
, sizeof(*ar100
), GFP_KERNEL
);
187 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
188 ar100
->reg
= devm_ioremap_resource(&pdev
->dev
, r
);
189 if (IS_ERR(ar100
->reg
))
190 return PTR_ERR(ar100
->reg
);
192 nparents
= of_clk_get_parent_count(np
);
193 if (nparents
> SUN6I_AR100_MAX_PARENTS
)
194 nparents
= SUN6I_AR100_MAX_PARENTS
;
196 for (i
= 0; i
< nparents
; i
++)
197 parents
[i
] = of_clk_get_parent_name(np
, i
);
199 of_property_read_string(np
, "clock-output-names", &clk_name
);
201 init
.name
= clk_name
;
202 init
.ops
= &ar100_ops
;
203 init
.parent_names
= parents
;
204 init
.num_parents
= nparents
;
207 ar100
->hw
.init
= &init
;
209 clk
= clk_register(&pdev
->dev
, &ar100
->hw
);
213 return of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
216 const struct of_device_id sun6i_a31_ar100_clk_dt_ids
[] = {
217 { .compatible
= "allwinner,sun6i-a31-ar100-clk" },
221 static struct platform_driver sun6i_a31_ar100_clk_driver
= {
223 .name
= "sun6i-a31-ar100-clk",
224 .owner
= THIS_MODULE
,
225 .of_match_table
= sun6i_a31_ar100_clk_dt_ids
,
227 .probe
= sun6i_a31_ar100_clk_probe
,
229 module_platform_driver(sun6i_a31_ar100_clk_driver
);
231 MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
232 MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
233 MODULE_LICENSE("GPL v2");