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 int ar100_determine_rate(struct clk_hw
*hw
,
48 struct clk_rate_request
*req
)
50 int nparents
= clk_hw_get_num_parents(hw
);
51 long best_rate
= -EINVAL
;
54 req
->best_parent_hw
= NULL
;
56 for (i
= 0; i
< nparents
; i
++) {
57 unsigned long parent_rate
;
58 unsigned long tmp_rate
;
59 struct clk_hw
*parent
;
63 parent
= clk_hw_get_parent_by_index(hw
, i
);
64 parent_rate
= clk_hw_get_rate(parent
);
65 div
= DIV_ROUND_UP(parent_rate
, req
->rate
);
68 * The AR100 clk contains 2 divisors:
69 * - one power of 2 divisor
70 * - one regular divisor
72 * First check if we can safely shift (or divide by a power
73 * of 2) without losing precision on the requested rate.
76 if (shift
> SUN6I_AR100_SHIFT_MAX
)
77 shift
= SUN6I_AR100_SHIFT_MAX
;
82 * Then if the divisor is still bigger than what the HW
83 * actually supports, use a bigger shift (or power of 2
84 * divider) value and accept to lose some precision.
86 while (div
> SUN6I_AR100_DIV_MAX
) {
89 if (shift
> SUN6I_AR100_SHIFT_MAX
)
94 * If the shift value (or power of 2 divider) is bigger
95 * than what the HW actually support, skip this parent.
97 if (shift
> SUN6I_AR100_SHIFT_MAX
)
100 tmp_rate
= (parent_rate
>> shift
) / div
;
101 if (!req
->best_parent_hw
|| tmp_rate
> best_rate
) {
102 req
->best_parent_hw
= parent
;
103 req
->best_parent_rate
= parent_rate
;
104 best_rate
= tmp_rate
;
111 req
->rate
= best_rate
;
116 static int ar100_set_parent(struct clk_hw
*hw
, u8 index
)
118 struct ar100_clk
*clk
= to_ar100_clk(hw
);
119 u32 val
= readl(clk
->reg
);
121 if (index
>= SUN6I_AR100_MAX_PARENTS
)
124 val
&= ~(SUN6I_AR100_MUX_MASK
<< SUN6I_AR100_MUX_SHIFT
);
125 val
|= (index
<< SUN6I_AR100_MUX_SHIFT
);
126 writel(val
, clk
->reg
);
131 static u8
ar100_get_parent(struct clk_hw
*hw
)
133 struct ar100_clk
*clk
= to_ar100_clk(hw
);
134 return (readl(clk
->reg
) >> SUN6I_AR100_MUX_SHIFT
) &
135 SUN6I_AR100_MUX_MASK
;
138 static int ar100_set_rate(struct clk_hw
*hw
, unsigned long rate
,
139 unsigned long parent_rate
)
141 unsigned long div
= parent_rate
/ rate
;
142 struct ar100_clk
*clk
= to_ar100_clk(hw
);
143 u32 val
= readl(clk
->reg
);
146 if (parent_rate
% rate
)
149 shift
= ffs(div
) - 1;
150 if (shift
> SUN6I_AR100_SHIFT_MAX
)
151 shift
= SUN6I_AR100_SHIFT_MAX
;
155 if (div
> SUN6I_AR100_DIV_MAX
)
158 val
&= ~((SUN6I_AR100_SHIFT_MASK
<< SUN6I_AR100_SHIFT_SHIFT
) |
159 (SUN6I_AR100_DIV_MASK
<< SUN6I_AR100_DIV_SHIFT
));
160 val
|= (shift
<< SUN6I_AR100_SHIFT_SHIFT
) |
161 (div
<< SUN6I_AR100_DIV_SHIFT
);
162 writel(val
, clk
->reg
);
167 static struct clk_ops ar100_ops
= {
168 .recalc_rate
= ar100_recalc_rate
,
169 .determine_rate
= ar100_determine_rate
,
170 .set_parent
= ar100_set_parent
,
171 .get_parent
= ar100_get_parent
,
172 .set_rate
= ar100_set_rate
,
175 static int sun6i_a31_ar100_clk_probe(struct platform_device
*pdev
)
177 const char *parents
[SUN6I_AR100_MAX_PARENTS
];
178 struct device_node
*np
= pdev
->dev
.of_node
;
179 const char *clk_name
= np
->name
;
180 struct clk_init_data init
;
181 struct ar100_clk
*ar100
;
186 ar100
= devm_kzalloc(&pdev
->dev
, sizeof(*ar100
), GFP_KERNEL
);
190 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
191 ar100
->reg
= devm_ioremap_resource(&pdev
->dev
, r
);
192 if (IS_ERR(ar100
->reg
))
193 return PTR_ERR(ar100
->reg
);
195 nparents
= of_clk_get_parent_count(np
);
196 if (nparents
> SUN6I_AR100_MAX_PARENTS
)
197 nparents
= SUN6I_AR100_MAX_PARENTS
;
199 of_clk_parent_fill(np
, parents
, nparents
);
201 of_property_read_string(np
, "clock-output-names", &clk_name
);
203 init
.name
= clk_name
;
204 init
.ops
= &ar100_ops
;
205 init
.parent_names
= parents
;
206 init
.num_parents
= nparents
;
209 ar100
->hw
.init
= &init
;
211 clk
= clk_register(&pdev
->dev
, &ar100
->hw
);
215 return of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
218 static const struct of_device_id sun6i_a31_ar100_clk_dt_ids
[] = {
219 { .compatible
= "allwinner,sun6i-a31-ar100-clk" },
222 MODULE_DEVICE_TABLE(of
, sun6i_a31_ar100_clk_dt_ids
);
224 static struct platform_driver sun6i_a31_ar100_clk_driver
= {
226 .name
= "sun6i-a31-ar100-clk",
227 .of_match_table
= sun6i_a31_ar100_clk_dt_ids
,
229 .probe
= sun6i_a31_ar100_clk_probe
,
231 module_platform_driver(sun6i_a31_ar100_clk_driver
);
233 MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
234 MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
235 MODULE_LICENSE("GPL v2");