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_get_num_parents(hw
->clk
);
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
;
63 parent
= clk_get_parent_by_index(hw
->clk
, i
);
64 parent_rate
= __clk_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
= __clk_get_hw(parent
);
103 req
->best_parent_rate
= parent_rate
;
104 best_rate
= tmp_rate
;
108 req
->rate
= best_rate
;
113 static int ar100_set_parent(struct clk_hw
*hw
, u8 index
)
115 struct ar100_clk
*clk
= to_ar100_clk(hw
);
116 u32 val
= readl(clk
->reg
);
118 if (index
>= SUN6I_AR100_MAX_PARENTS
)
121 val
&= ~(SUN6I_AR100_MUX_MASK
<< SUN6I_AR100_MUX_SHIFT
);
122 val
|= (index
<< SUN6I_AR100_MUX_SHIFT
);
123 writel(val
, clk
->reg
);
128 static u8
ar100_get_parent(struct clk_hw
*hw
)
130 struct ar100_clk
*clk
= to_ar100_clk(hw
);
131 return (readl(clk
->reg
) >> SUN6I_AR100_MUX_SHIFT
) &
132 SUN6I_AR100_MUX_MASK
;
135 static int ar100_set_rate(struct clk_hw
*hw
, unsigned long rate
,
136 unsigned long parent_rate
)
138 unsigned long div
= parent_rate
/ rate
;
139 struct ar100_clk
*clk
= to_ar100_clk(hw
);
140 u32 val
= readl(clk
->reg
);
143 if (parent_rate
% rate
)
146 shift
= ffs(div
) - 1;
147 if (shift
> SUN6I_AR100_SHIFT_MAX
)
148 shift
= SUN6I_AR100_SHIFT_MAX
;
152 if (div
> SUN6I_AR100_DIV_MAX
)
155 val
&= ~((SUN6I_AR100_SHIFT_MASK
<< SUN6I_AR100_SHIFT_SHIFT
) |
156 (SUN6I_AR100_DIV_MASK
<< SUN6I_AR100_DIV_SHIFT
));
157 val
|= (shift
<< SUN6I_AR100_SHIFT_SHIFT
) |
158 (div
<< SUN6I_AR100_DIV_SHIFT
);
159 writel(val
, clk
->reg
);
164 static struct clk_ops ar100_ops
= {
165 .recalc_rate
= ar100_recalc_rate
,
166 .determine_rate
= ar100_determine_rate
,
167 .set_parent
= ar100_set_parent
,
168 .get_parent
= ar100_get_parent
,
169 .set_rate
= ar100_set_rate
,
172 static int sun6i_a31_ar100_clk_probe(struct platform_device
*pdev
)
174 const char *parents
[SUN6I_AR100_MAX_PARENTS
];
175 struct device_node
*np
= pdev
->dev
.of_node
;
176 const char *clk_name
= np
->name
;
177 struct clk_init_data init
;
178 struct ar100_clk
*ar100
;
184 ar100
= devm_kzalloc(&pdev
->dev
, sizeof(*ar100
), GFP_KERNEL
);
188 r
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
189 ar100
->reg
= devm_ioremap_resource(&pdev
->dev
, r
);
190 if (IS_ERR(ar100
->reg
))
191 return PTR_ERR(ar100
->reg
);
193 nparents
= of_clk_get_parent_count(np
);
194 if (nparents
> SUN6I_AR100_MAX_PARENTS
)
195 nparents
= SUN6I_AR100_MAX_PARENTS
;
197 for (i
= 0; i
< nparents
; i
++)
198 parents
[i
] = of_clk_get_parent_name(np
, i
);
200 of_property_read_string(np
, "clock-output-names", &clk_name
);
202 init
.name
= clk_name
;
203 init
.ops
= &ar100_ops
;
204 init
.parent_names
= parents
;
205 init
.num_parents
= nparents
;
208 ar100
->hw
.init
= &init
;
210 clk
= clk_register(&pdev
->dev
, &ar100
->hw
);
214 return of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
217 static const struct of_device_id sun6i_a31_ar100_clk_dt_ids
[] = {
218 { .compatible
= "allwinner,sun6i-a31-ar100-clk" },
222 static struct platform_driver sun6i_a31_ar100_clk_driver
= {
224 .name
= "sun6i-a31-ar100-clk",
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");