1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
6 #include <linux/clk-provider.h>
7 #include <linux/clkdev.h>
8 #include <linux/clk/at91_pmc.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/regmap.h>
15 #define SAM9X5_USB_DIV_SHIFT 8
16 #define SAM9X5_USB_MAX_DIV 0xf
18 #define RM9200_USB_DIV_SHIFT 28
19 #define RM9200_USB_DIV_TAB_SIZE 4
21 #define SAM9X5_USBS_MASK GENMASK(0, 0)
22 #define SAM9X60_USBS_MASK GENMASK(1, 0)
24 struct at91sam9x5_clk_usb
{
26 struct regmap
*regmap
;
30 #define to_at91sam9x5_clk_usb(hw) \
31 container_of(hw, struct at91sam9x5_clk_usb, hw)
33 struct at91rm9200_clk_usb
{
35 struct regmap
*regmap
;
39 #define to_at91rm9200_clk_usb(hw) \
40 container_of(hw, struct at91rm9200_clk_usb, hw)
42 static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw
*hw
,
43 unsigned long parent_rate
)
45 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
49 regmap_read(usb
->regmap
, AT91_PMC_USB
, &usbr
);
50 usbdiv
= (usbr
& AT91_PMC_OHCIUSBDIV
) >> SAM9X5_USB_DIV_SHIFT
;
52 return DIV_ROUND_CLOSEST(parent_rate
, (usbdiv
+ 1));
55 static int at91sam9x5_clk_usb_determine_rate(struct clk_hw
*hw
,
56 struct clk_rate_request
*req
)
58 struct clk_hw
*parent
;
59 long best_rate
= -EINVAL
;
60 unsigned long tmp_rate
;
65 for (i
= 0; i
< clk_hw_get_num_parents(hw
); i
++) {
68 parent
= clk_hw_get_parent_by_index(hw
, i
);
72 for (div
= 1; div
< SAM9X5_USB_MAX_DIV
+ 2; div
++) {
73 unsigned long tmp_parent_rate
;
75 tmp_parent_rate
= req
->rate
* div
;
76 tmp_parent_rate
= clk_hw_round_rate(parent
,
78 tmp_rate
= DIV_ROUND_CLOSEST(tmp_parent_rate
, div
);
79 if (tmp_rate
< req
->rate
)
80 tmp_diff
= req
->rate
- tmp_rate
;
82 tmp_diff
= tmp_rate
- req
->rate
;
84 if (best_diff
< 0 || best_diff
> tmp_diff
) {
87 req
->best_parent_rate
= tmp_parent_rate
;
88 req
->best_parent_hw
= parent
;
91 if (!best_diff
|| tmp_rate
< req
->rate
)
102 req
->rate
= best_rate
;
106 static int at91sam9x5_clk_usb_set_parent(struct clk_hw
*hw
, u8 index
)
108 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
113 regmap_update_bits(usb
->regmap
, AT91_PMC_USB
, usb
->usbs_mask
, index
);
118 static u8
at91sam9x5_clk_usb_get_parent(struct clk_hw
*hw
)
120 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
123 regmap_read(usb
->regmap
, AT91_PMC_USB
, &usbr
);
125 return usbr
& usb
->usbs_mask
;
128 static int at91sam9x5_clk_usb_set_rate(struct clk_hw
*hw
, unsigned long rate
,
129 unsigned long parent_rate
)
131 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
137 div
= DIV_ROUND_CLOSEST(parent_rate
, rate
);
138 if (div
> SAM9X5_USB_MAX_DIV
+ 1 || !div
)
141 regmap_update_bits(usb
->regmap
, AT91_PMC_USB
, AT91_PMC_OHCIUSBDIV
,
142 (div
- 1) << SAM9X5_USB_DIV_SHIFT
);
147 static const struct clk_ops at91sam9x5_usb_ops
= {
148 .recalc_rate
= at91sam9x5_clk_usb_recalc_rate
,
149 .determine_rate
= at91sam9x5_clk_usb_determine_rate
,
150 .get_parent
= at91sam9x5_clk_usb_get_parent
,
151 .set_parent
= at91sam9x5_clk_usb_set_parent
,
152 .set_rate
= at91sam9x5_clk_usb_set_rate
,
155 static int at91sam9n12_clk_usb_enable(struct clk_hw
*hw
)
157 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
159 regmap_update_bits(usb
->regmap
, AT91_PMC_USB
, AT91_PMC_USBS
,
165 static void at91sam9n12_clk_usb_disable(struct clk_hw
*hw
)
167 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
169 regmap_update_bits(usb
->regmap
, AT91_PMC_USB
, AT91_PMC_USBS
, 0);
172 static int at91sam9n12_clk_usb_is_enabled(struct clk_hw
*hw
)
174 struct at91sam9x5_clk_usb
*usb
= to_at91sam9x5_clk_usb(hw
);
177 regmap_read(usb
->regmap
, AT91_PMC_USB
, &usbr
);
179 return usbr
& AT91_PMC_USBS
;
182 static const struct clk_ops at91sam9n12_usb_ops
= {
183 .enable
= at91sam9n12_clk_usb_enable
,
184 .disable
= at91sam9n12_clk_usb_disable
,
185 .is_enabled
= at91sam9n12_clk_usb_is_enabled
,
186 .recalc_rate
= at91sam9x5_clk_usb_recalc_rate
,
187 .determine_rate
= at91sam9x5_clk_usb_determine_rate
,
188 .set_rate
= at91sam9x5_clk_usb_set_rate
,
191 static struct clk_hw
* __init
192 _at91sam9x5_clk_register_usb(struct regmap
*regmap
, const char *name
,
193 const char **parent_names
, u8 num_parents
,
196 struct at91sam9x5_clk_usb
*usb
;
198 struct clk_init_data init
;
201 usb
= kzalloc(sizeof(*usb
), GFP_KERNEL
);
203 return ERR_PTR(-ENOMEM
);
206 init
.ops
= &at91sam9x5_usb_ops
;
207 init
.parent_names
= parent_names
;
208 init
.num_parents
= num_parents
;
209 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_PARENT_GATE
|
212 usb
->hw
.init
= &init
;
213 usb
->regmap
= regmap
;
214 usb
->usbs_mask
= SAM9X5_USBS_MASK
;
217 ret
= clk_hw_register(NULL
, &usb
->hw
);
226 struct clk_hw
* __init
227 at91sam9x5_clk_register_usb(struct regmap
*regmap
, const char *name
,
228 const char **parent_names
, u8 num_parents
)
230 return _at91sam9x5_clk_register_usb(regmap
, name
, parent_names
,
231 num_parents
, SAM9X5_USBS_MASK
);
234 struct clk_hw
* __init
235 sam9x60_clk_register_usb(struct regmap
*regmap
, const char *name
,
236 const char **parent_names
, u8 num_parents
)
238 return _at91sam9x5_clk_register_usb(regmap
, name
, parent_names
,
239 num_parents
, SAM9X60_USBS_MASK
);
242 struct clk_hw
* __init
243 at91sam9n12_clk_register_usb(struct regmap
*regmap
, const char *name
,
244 const char *parent_name
)
246 struct at91sam9x5_clk_usb
*usb
;
248 struct clk_init_data init
;
251 usb
= kzalloc(sizeof(*usb
), GFP_KERNEL
);
253 return ERR_PTR(-ENOMEM
);
256 init
.ops
= &at91sam9n12_usb_ops
;
257 init
.parent_names
= &parent_name
;
258 init
.num_parents
= 1;
259 init
.flags
= CLK_SET_RATE_GATE
| CLK_SET_RATE_PARENT
;
261 usb
->hw
.init
= &init
;
262 usb
->regmap
= regmap
;
265 ret
= clk_hw_register(NULL
, &usb
->hw
);
274 static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw
*hw
,
275 unsigned long parent_rate
)
277 struct at91rm9200_clk_usb
*usb
= to_at91rm9200_clk_usb(hw
);
281 regmap_read(usb
->regmap
, AT91_CKGR_PLLBR
, &pllbr
);
283 usbdiv
= (pllbr
& AT91_PMC_USBDIV
) >> RM9200_USB_DIV_SHIFT
;
284 if (usb
->divisors
[usbdiv
])
285 return parent_rate
/ usb
->divisors
[usbdiv
];
290 static long at91rm9200_clk_usb_round_rate(struct clk_hw
*hw
, unsigned long rate
,
291 unsigned long *parent_rate
)
293 struct at91rm9200_clk_usb
*usb
= to_at91rm9200_clk_usb(hw
);
294 struct clk_hw
*parent
= clk_hw_get_parent(hw
);
295 unsigned long bestrate
= 0;
297 unsigned long tmprate
;
301 for (i
= 0; i
< RM9200_USB_DIV_TAB_SIZE
; i
++) {
302 unsigned long tmp_parent_rate
;
304 if (!usb
->divisors
[i
])
307 tmp_parent_rate
= rate
* usb
->divisors
[i
];
308 tmp_parent_rate
= clk_hw_round_rate(parent
, tmp_parent_rate
);
309 tmprate
= DIV_ROUND_CLOSEST(tmp_parent_rate
, usb
->divisors
[i
]);
311 tmpdiff
= rate
- tmprate
;
313 tmpdiff
= tmprate
- rate
;
315 if (bestdiff
< 0 || bestdiff
> tmpdiff
) {
318 *parent_rate
= tmp_parent_rate
;
328 static int at91rm9200_clk_usb_set_rate(struct clk_hw
*hw
, unsigned long rate
,
329 unsigned long parent_rate
)
332 struct at91rm9200_clk_usb
*usb
= to_at91rm9200_clk_usb(hw
);
338 div
= DIV_ROUND_CLOSEST(parent_rate
, rate
);
340 for (i
= 0; i
< RM9200_USB_DIV_TAB_SIZE
; i
++) {
341 if (usb
->divisors
[i
] == div
) {
342 regmap_update_bits(usb
->regmap
, AT91_CKGR_PLLBR
,
344 i
<< RM9200_USB_DIV_SHIFT
);
353 static const struct clk_ops at91rm9200_usb_ops
= {
354 .recalc_rate
= at91rm9200_clk_usb_recalc_rate
,
355 .round_rate
= at91rm9200_clk_usb_round_rate
,
356 .set_rate
= at91rm9200_clk_usb_set_rate
,
359 struct clk_hw
* __init
360 at91rm9200_clk_register_usb(struct regmap
*regmap
, const char *name
,
361 const char *parent_name
, const u32
*divisors
)
363 struct at91rm9200_clk_usb
*usb
;
365 struct clk_init_data init
;
368 usb
= kzalloc(sizeof(*usb
), GFP_KERNEL
);
370 return ERR_PTR(-ENOMEM
);
373 init
.ops
= &at91rm9200_usb_ops
;
374 init
.parent_names
= &parent_name
;
375 init
.num_parents
= 1;
376 init
.flags
= CLK_SET_RATE_PARENT
;
378 usb
->hw
.init
= &init
;
379 usb
->regmap
= regmap
;
380 memcpy(usb
->divisors
, divisors
, sizeof(usb
->divisors
));
383 ret
= clk_hw_register(NULL
, &usb
->hw
);