1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Socionext Inc.
4 * Copyright (C) 2016 Linaro Ltd.
7 #include <linux/clk-provider.h>
10 #include <linux/iopoll.h>
11 #include <linux/of_address.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
16 #define M10V_CLKSEL1 0x0
17 #define CLKSEL(n) (((n) - 1) * 4 + M10V_CLKSEL1)
19 #define M10V_PLL1 "pll1"
20 #define M10V_PLL1DIV2 "pll1-2"
21 #define M10V_PLL2 "pll2"
22 #define M10V_PLL2DIV2 "pll2-2"
23 #define M10V_PLL6 "pll6"
24 #define M10V_PLL6DIV2 "pll6-2"
25 #define M10V_PLL6DIV3 "pll6-3"
26 #define M10V_PLL7 "pll7"
27 #define M10V_PLL7DIV2 "pll7-2"
28 #define M10V_PLL7DIV5 "pll7-5"
29 #define M10V_PLL9 "pll9"
30 #define M10V_PLL10 "pll10"
31 #define M10V_PLL10DIV2 "pll10-2"
32 #define M10V_PLL11 "pll11"
34 #define M10V_SPI_PARENT0 "spi-parent0"
35 #define M10V_SPI_PARENT1 "spi-parent1"
36 #define M10V_SPI_PARENT2 "spi-parent2"
37 #define M10V_UHS1CLK2_PARENT0 "uhs1clk2-parent0"
38 #define M10V_UHS1CLK2_PARENT1 "uhs1clk2-parent1"
39 #define M10V_UHS1CLK2_PARENT2 "uhs1clk2-parent2"
40 #define M10V_UHS1CLK1_PARENT0 "uhs1clk1-parent0"
41 #define M10V_UHS1CLK1_PARENT1 "uhs1clk1-parent1"
42 #define M10V_NFCLK_PARENT0 "nfclk-parent0"
43 #define M10V_NFCLK_PARENT1 "nfclk-parent1"
44 #define M10V_NFCLK_PARENT2 "nfclk-parent2"
45 #define M10V_NFCLK_PARENT3 "nfclk-parent3"
46 #define M10V_NFCLK_PARENT4 "nfclk-parent4"
47 #define M10V_NFCLK_PARENT5 "nfclk-parent5"
50 #define M10V_UPOLL_RATE 1
51 #define M10V_UTIMEOUT 250
53 #define M10V_EMMCCLK_ID 0
54 #define M10V_ACLK_ID 1
55 #define M10V_HCLK_ID 2
56 #define M10V_PCLK_ID 3
57 #define M10V_RCLK_ID 4
58 #define M10V_SPICLK_ID 5
59 #define M10V_NFCLK_ID 6
60 #define M10V_UHS1CLK2_ID 7
61 #define M10V_NUM_CLKS 8
63 #define to_m10v_div(_hw) container_of(_hw, struct m10v_clk_divider, hw)
65 static struct clk_hw_onecell_data
*m10v_clk_data
;
67 static DEFINE_SPINLOCK(m10v_crglock
);
69 struct m10v_clk_div_factors
{
71 const char *parent_name
;
75 const struct clk_div_table
*table
;
76 unsigned long div_flags
;
80 struct m10v_clk_div_fixed_data
{
82 const char *parent_name
;
88 struct m10v_clk_mux_factors
{
90 const char * const *parent_names
;
96 unsigned long mux_flags
;
100 static const struct clk_div_table emmcclk_table
[] = {
101 { .val
= 0, .div
= 8 },
102 { .val
= 1, .div
= 9 },
103 { .val
= 2, .div
= 10 },
104 { .val
= 3, .div
= 15 },
108 static const struct clk_div_table mclk400_table
[] = {
109 { .val
= 1, .div
= 2 },
110 { .val
= 3, .div
= 4 },
114 static const struct clk_div_table mclk200_table
[] = {
115 { .val
= 3, .div
= 4 },
116 { .val
= 7, .div
= 8 },
120 static const struct clk_div_table aclk400_table
[] = {
121 { .val
= 1, .div
= 2 },
122 { .val
= 3, .div
= 4 },
126 static const struct clk_div_table aclk300_table
[] = {
127 { .val
= 0, .div
= 2 },
128 { .val
= 1, .div
= 3 },
132 static const struct clk_div_table aclk_table
[] = {
133 { .val
= 3, .div
= 4 },
134 { .val
= 7, .div
= 8 },
138 static const struct clk_div_table aclkexs_table
[] = {
139 { .val
= 3, .div
= 4 },
140 { .val
= 4, .div
= 5 },
141 { .val
= 5, .div
= 6 },
142 { .val
= 7, .div
= 8 },
146 static const struct clk_div_table hclk_table
[] = {
147 { .val
= 7, .div
= 8 },
148 { .val
= 15, .div
= 16 },
152 static const struct clk_div_table hclkbmh_table
[] = {
153 { .val
= 3, .div
= 4 },
154 { .val
= 7, .div
= 8 },
158 static const struct clk_div_table pclk_table
[] = {
159 { .val
= 15, .div
= 16 },
160 { .val
= 31, .div
= 32 },
164 static const struct clk_div_table rclk_table
[] = {
165 { .val
= 0, .div
= 8 },
166 { .val
= 1, .div
= 16 },
167 { .val
= 2, .div
= 24 },
168 { .val
= 3, .div
= 32 },
172 static const struct clk_div_table uhs1clk0_table
[] = {
173 { .val
= 0, .div
= 2 },
174 { .val
= 1, .div
= 3 },
175 { .val
= 2, .div
= 4 },
176 { .val
= 3, .div
= 8 },
177 { .val
= 4, .div
= 16 },
181 static const struct clk_div_table uhs2clk_table
[] = {
182 { .val
= 0, .div
= 9 },
183 { .val
= 1, .div
= 10 },
184 { .val
= 2, .div
= 11 },
185 { .val
= 3, .div
= 12 },
186 { .val
= 4, .div
= 13 },
187 { .val
= 5, .div
= 14 },
188 { .val
= 6, .div
= 16 },
189 { .val
= 7, .div
= 18 },
193 static u32 spi_mux_table
[] = {0, 1, 2};
194 static const char * const spi_mux_names
[] = {
195 M10V_SPI_PARENT0
, M10V_SPI_PARENT1
, M10V_SPI_PARENT2
198 static u32 uhs1clk2_mux_table
[] = {2, 3, 4, 8};
199 static const char * const uhs1clk2_mux_names
[] = {
200 M10V_UHS1CLK2_PARENT0
, M10V_UHS1CLK2_PARENT1
,
201 M10V_UHS1CLK2_PARENT2
, M10V_PLL6DIV2
204 static u32 uhs1clk1_mux_table
[] = {3, 4, 8};
205 static const char * const uhs1clk1_mux_names
[] = {
206 M10V_UHS1CLK1_PARENT0
, M10V_UHS1CLK1_PARENT1
, M10V_PLL6DIV2
209 static u32 nfclk_mux_table
[] = {0, 1, 2, 3, 4, 8};
210 static const char * const nfclk_mux_names
[] = {
211 M10V_NFCLK_PARENT0
, M10V_NFCLK_PARENT1
, M10V_NFCLK_PARENT2
,
212 M10V_NFCLK_PARENT3
, M10V_NFCLK_PARENT4
, M10V_NFCLK_PARENT5
215 static const struct m10v_clk_div_fixed_data m10v_pll_fixed_data
[] = {
216 {M10V_PLL1
, NULL
, 1, 40, -1},
217 {M10V_PLL2
, NULL
, 1, 30, -1},
218 {M10V_PLL6
, NULL
, 1, 35, -1},
219 {M10V_PLL7
, NULL
, 1, 40, -1},
220 {M10V_PLL9
, NULL
, 1, 33, -1},
221 {M10V_PLL10
, NULL
, 5, 108, -1},
222 {M10V_PLL10DIV2
, M10V_PLL10
, 2, 1, -1},
223 {M10V_PLL11
, NULL
, 2, 75, -1},
226 static const struct m10v_clk_div_fixed_data m10v_div_fixed_data
[] = {
227 {"usb2", NULL
, 2, 1, -1},
228 {"pcisuppclk", NULL
, 20, 1, -1},
229 {M10V_PLL1DIV2
, M10V_PLL1
, 2, 1, -1},
230 {M10V_PLL2DIV2
, M10V_PLL2
, 2, 1, -1},
231 {M10V_PLL6DIV2
, M10V_PLL6
, 2, 1, -1},
232 {M10V_PLL6DIV3
, M10V_PLL6
, 3, 1, -1},
233 {M10V_PLL7DIV2
, M10V_PLL7
, 2, 1, -1},
234 {M10V_PLL7DIV5
, M10V_PLL7
, 5, 1, -1},
235 {"ca7wd", M10V_PLL2DIV2
, 12, 1, -1},
236 {"pclkca7wd", M10V_PLL1DIV2
, 16, 1, -1},
237 {M10V_SPI_PARENT0
, M10V_PLL10DIV2
, 2, 1, -1},
238 {M10V_SPI_PARENT1
, M10V_PLL10DIV2
, 4, 1, -1},
239 {M10V_SPI_PARENT2
, M10V_PLL7DIV2
, 8, 1, -1},
240 {M10V_UHS1CLK2_PARENT0
, M10V_PLL7
, 4, 1, -1},
241 {M10V_UHS1CLK2_PARENT1
, M10V_PLL7
, 8, 1, -1},
242 {M10V_UHS1CLK2_PARENT2
, M10V_PLL7
, 16, 1, -1},
243 {M10V_UHS1CLK1_PARENT0
, M10V_PLL7
, 8, 1, -1},
244 {M10V_UHS1CLK1_PARENT1
, M10V_PLL7
, 16, 1, -1},
245 {M10V_NFCLK_PARENT0
, M10V_PLL7DIV2
, 8, 1, -1},
246 {M10V_NFCLK_PARENT1
, M10V_PLL7DIV2
, 10, 1, -1},
247 {M10V_NFCLK_PARENT2
, M10V_PLL7DIV2
, 13, 1, -1},
248 {M10V_NFCLK_PARENT3
, M10V_PLL7DIV2
, 16, 1, -1},
249 {M10V_NFCLK_PARENT4
, M10V_PLL7DIV2
, 40, 1, -1},
250 {M10V_NFCLK_PARENT5
, M10V_PLL7DIV5
, 10, 1, -1},
253 static const struct m10v_clk_div_factors m10v_div_factor_data
[] = {
254 {"emmc", M10V_PLL11
, CLKSEL(1), 28, 3, emmcclk_table
, 0,
256 {"mclk400", M10V_PLL1DIV2
, CLKSEL(10), 7, 3, mclk400_table
, 0, -1},
257 {"mclk200", M10V_PLL1DIV2
, CLKSEL(10), 3, 4, mclk200_table
, 0, -1},
258 {"aclk400", M10V_PLL1DIV2
, CLKSEL(10), 0, 3, aclk400_table
, 0, -1},
259 {"aclk300", M10V_PLL2DIV2
, CLKSEL(12), 0, 2, aclk300_table
, 0, -1},
260 {"aclk", M10V_PLL1DIV2
, CLKSEL(9), 20, 4, aclk_table
, 0, M10V_ACLK_ID
},
261 {"aclkexs", M10V_PLL1DIV2
, CLKSEL(9), 16, 4, aclkexs_table
, 0, -1},
262 {"hclk", M10V_PLL1DIV2
, CLKSEL(9), 7, 5, hclk_table
, 0, M10V_HCLK_ID
},
263 {"hclkbmh", M10V_PLL1DIV2
, CLKSEL(9), 12, 4, hclkbmh_table
, 0, -1},
264 {"pclk", M10V_PLL1DIV2
, CLKSEL(9), 0, 7, pclk_table
, 0, M10V_PCLK_ID
},
265 {"uhs1clk0", M10V_PLL7
, CLKSEL(1), 3, 5, uhs1clk0_table
, 0, -1},
266 {"uhs2clk", M10V_PLL6DIV3
, CLKSEL(1), 18, 4, uhs2clk_table
, 0, -1},
269 static const struct m10v_clk_mux_factors m10v_mux_factor_data
[] = {
270 {"spi", spi_mux_names
, ARRAY_SIZE(spi_mux_names
),
271 CLKSEL(8), 3, 7, spi_mux_table
, 0, M10V_SPICLK_ID
},
272 {"uhs1clk2", uhs1clk2_mux_names
, ARRAY_SIZE(uhs1clk2_mux_names
),
273 CLKSEL(1), 13, 31, uhs1clk2_mux_table
, 0, M10V_UHS1CLK2_ID
},
274 {"uhs1clk1", uhs1clk1_mux_names
, ARRAY_SIZE(uhs1clk1_mux_names
),
275 CLKSEL(1), 8, 31, uhs1clk1_mux_table
, 0, -1},
276 {"nfclk", nfclk_mux_names
, ARRAY_SIZE(nfclk_mux_names
),
277 CLKSEL(1), 22, 127, nfclk_mux_table
, 0, M10V_NFCLK_ID
},
280 static u8
m10v_mux_get_parent(struct clk_hw
*hw
)
282 struct clk_mux
*mux
= to_clk_mux(hw
);
285 val
= readl(mux
->reg
) >> mux
->shift
;
288 return clk_mux_val_to_index(hw
, mux
->table
, mux
->flags
, val
);
291 static int m10v_mux_set_parent(struct clk_hw
*hw
, u8 index
)
293 struct clk_mux
*mux
= to_clk_mux(hw
);
294 u32 val
= clk_mux_index_to_val(mux
->table
, mux
->flags
, index
);
295 unsigned long flags
= 0;
297 u32 write_en
= BIT(fls(mux
->mask
) - 1);
300 spin_lock_irqsave(mux
->lock
, flags
);
302 __acquire(mux
->lock
);
304 reg
= readl(mux
->reg
);
305 reg
&= ~(mux
->mask
<< mux
->shift
);
307 val
= (val
| write_en
) << mux
->shift
;
309 writel(reg
, mux
->reg
);
312 spin_unlock_irqrestore(mux
->lock
, flags
);
314 __release(mux
->lock
);
319 static const struct clk_ops m10v_mux_ops
= {
320 .get_parent
= m10v_mux_get_parent
,
321 .set_parent
= m10v_mux_set_parent
,
322 .determine_rate
= __clk_mux_determine_rate
,
325 static struct clk_hw
*m10v_clk_hw_register_mux(struct device
*dev
,
326 const char *name
, const char * const *parent_names
,
327 u8 num_parents
, unsigned long flags
, void __iomem
*reg
,
328 u8 shift
, u32 mask
, u8 clk_mux_flags
, u32
*table
,
333 struct clk_init_data init
;
336 mux
= kzalloc(sizeof(*mux
), GFP_KERNEL
);
338 return ERR_PTR(-ENOMEM
);
341 init
.ops
= &m10v_mux_ops
;
343 init
.parent_names
= parent_names
;
344 init
.num_parents
= num_parents
;
349 mux
->flags
= clk_mux_flags
;
352 mux
->hw
.init
= &init
;
355 ret
= clk_hw_register(dev
, hw
);
365 struct m10v_clk_divider
{
371 const struct clk_div_table
*table
;
373 void __iomem
*write_valid_reg
;
376 static unsigned long m10v_clk_divider_recalc_rate(struct clk_hw
*hw
,
377 unsigned long parent_rate
)
379 struct m10v_clk_divider
*divider
= to_m10v_div(hw
);
382 val
= readl(divider
->reg
) >> divider
->shift
;
383 val
&= clk_div_mask(divider
->width
);
385 return divider_recalc_rate(hw
, parent_rate
, val
, divider
->table
,
386 divider
->flags
, divider
->width
);
389 static long m10v_clk_divider_round_rate(struct clk_hw
*hw
, unsigned long rate
,
390 unsigned long *prate
)
392 struct m10v_clk_divider
*divider
= to_m10v_div(hw
);
394 /* if read only, just return current value */
395 if (divider
->flags
& CLK_DIVIDER_READ_ONLY
) {
398 val
= readl(divider
->reg
) >> divider
->shift
;
399 val
&= clk_div_mask(divider
->width
);
401 return divider_ro_round_rate(hw
, rate
, prate
, divider
->table
,
402 divider
->width
, divider
->flags
,
406 return divider_round_rate(hw
, rate
, prate
, divider
->table
,
407 divider
->width
, divider
->flags
);
410 static int m10v_clk_divider_set_rate(struct clk_hw
*hw
, unsigned long rate
,
411 unsigned long parent_rate
)
413 struct m10v_clk_divider
*divider
= to_m10v_div(hw
);
415 unsigned long flags
= 0;
417 u32 write_en
= BIT(divider
->width
- 1);
419 value
= divider_get_val(rate
, parent_rate
, divider
->table
,
420 divider
->width
, divider
->flags
);
425 spin_lock_irqsave(divider
->lock
, flags
);
427 __acquire(divider
->lock
);
429 val
= readl(divider
->reg
);
430 val
&= ~(clk_div_mask(divider
->width
) << divider
->shift
);
432 val
|= ((u32
)value
| write_en
) << divider
->shift
;
433 writel(val
, divider
->reg
);
435 if (divider
->write_valid_reg
) {
436 writel(M10V_DCHREQ
, divider
->write_valid_reg
);
437 if (readl_poll_timeout(divider
->write_valid_reg
, val
,
438 !val
, M10V_UPOLL_RATE
, M10V_UTIMEOUT
))
439 pr_err("%s:%s couldn't stabilize\n",
440 __func__
, divider
->hw
.init
->name
);
444 spin_unlock_irqrestore(divider
->lock
, flags
);
446 __release(divider
->lock
);
451 static const struct clk_ops m10v_clk_divider_ops
= {
452 .recalc_rate
= m10v_clk_divider_recalc_rate
,
453 .round_rate
= m10v_clk_divider_round_rate
,
454 .set_rate
= m10v_clk_divider_set_rate
,
457 static struct clk_hw
*m10v_clk_hw_register_divider(struct device
*dev
,
458 const char *name
, const char *parent_name
, unsigned long flags
,
459 void __iomem
*reg
, u8 shift
, u8 width
,
460 u8 clk_divider_flags
, const struct clk_div_table
*table
,
461 spinlock_t
*lock
, void __iomem
*write_valid_reg
)
463 struct m10v_clk_divider
*div
;
465 struct clk_init_data init
;
468 div
= kzalloc(sizeof(*div
), GFP_KERNEL
);
470 return ERR_PTR(-ENOMEM
);
473 init
.ops
= &m10v_clk_divider_ops
;
475 init
.parent_names
= &parent_name
;
476 init
.num_parents
= 1;
481 div
->flags
= clk_divider_flags
;
483 div
->hw
.init
= &init
;
485 div
->write_valid_reg
= write_valid_reg
;
487 /* register the clock */
489 ret
= clk_hw_register(dev
, hw
);
498 static void m10v_reg_div_pre(const struct m10v_clk_div_factors
*factors
,
499 struct clk_hw_onecell_data
*clk_data
,
503 void __iomem
*write_valid_reg
;
506 * The registers on CLKSEL(9) or CLKSEL(10) need additional
507 * writing to become valid.
509 if ((factors
->offset
== CLKSEL(9)) || (factors
->offset
== CLKSEL(10)))
510 write_valid_reg
= base
+ CLKSEL(11);
512 write_valid_reg
= NULL
;
514 hw
= m10v_clk_hw_register_divider(NULL
, factors
->name
,
515 factors
->parent_name
,
517 base
+ factors
->offset
,
519 factors
->width
, factors
->div_flags
,
521 &m10v_crglock
, write_valid_reg
);
523 if (factors
->onecell_idx
>= 0)
524 clk_data
->hws
[factors
->onecell_idx
] = hw
;
527 static void m10v_reg_fixed_pre(const struct m10v_clk_div_fixed_data
*factors
,
528 struct clk_hw_onecell_data
*clk_data
,
529 const char *parent_name
)
532 const char *pn
= factors
->parent_name
?
533 factors
->parent_name
: parent_name
;
535 hw
= clk_hw_register_fixed_factor(NULL
, factors
->name
, pn
, 0,
536 factors
->mult
, factors
->div
);
538 if (factors
->onecell_idx
>= 0)
539 clk_data
->hws
[factors
->onecell_idx
] = hw
;
542 static void m10v_reg_mux_pre(const struct m10v_clk_mux_factors
*factors
,
543 struct clk_hw_onecell_data
*clk_data
,
548 hw
= m10v_clk_hw_register_mux(NULL
, factors
->name
,
549 factors
->parent_names
,
550 factors
->num_parents
,
552 base
+ factors
->offset
, factors
->shift
,
553 factors
->mask
, factors
->mux_flags
,
554 factors
->table
, &m10v_crglock
);
556 if (factors
->onecell_idx
>= 0)
557 clk_data
->hws
[factors
->onecell_idx
] = hw
;
560 static int m10v_clk_probe(struct platform_device
*pdev
)
563 struct resource
*res
;
564 struct device
*dev
= &pdev
->dev
;
565 struct device_node
*np
= dev
->of_node
;
567 const char *parent_name
;
569 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
570 base
= devm_ioremap_resource(dev
, res
);
572 return PTR_ERR(base
);
574 parent_name
= of_clk_get_parent_name(np
, 0);
576 for (id
= 0; id
< ARRAY_SIZE(m10v_div_factor_data
); ++id
)
577 m10v_reg_div_pre(&m10v_div_factor_data
[id
],
578 m10v_clk_data
, base
);
580 for (id
= 0; id
< ARRAY_SIZE(m10v_div_fixed_data
); ++id
)
581 m10v_reg_fixed_pre(&m10v_div_fixed_data
[id
],
582 m10v_clk_data
, parent_name
);
584 for (id
= 0; id
< ARRAY_SIZE(m10v_mux_factor_data
); ++id
)
585 m10v_reg_mux_pre(&m10v_mux_factor_data
[id
],
586 m10v_clk_data
, base
);
588 for (id
= 0; id
< M10V_NUM_CLKS
; id
++) {
589 if (IS_ERR(m10v_clk_data
->hws
[id
]))
590 return PTR_ERR(m10v_clk_data
->hws
[id
]);
596 static const struct of_device_id m10v_clk_dt_ids
[] = {
597 { .compatible
= "socionext,milbeaut-m10v-ccu", },
601 static struct platform_driver m10v_clk_driver
= {
602 .probe
= m10v_clk_probe
,
605 .of_match_table
= m10v_clk_dt_ids
,
608 builtin_platform_driver(m10v_clk_driver
);
610 static void __init
m10v_cc_init(struct device_node
*np
)
614 const char *parent_name
;
617 m10v_clk_data
= kzalloc(struct_size(m10v_clk_data
, hws
,
624 base
= of_iomap(np
, 0);
626 kfree(m10v_clk_data
);
630 parent_name
= of_clk_get_parent_name(np
, 0);
632 kfree(m10v_clk_data
);
638 * This way all clocks fetched before the platform device probes,
639 * except those we assign here for early use, will be deferred.
641 for (id
= 0; id
< M10V_NUM_CLKS
; id
++)
642 m10v_clk_data
->hws
[id
] = ERR_PTR(-EPROBE_DEFER
);
645 * PLLs are set by bootloader so this driver registers them as the
648 for (id
= 0; id
< ARRAY_SIZE(m10v_pll_fixed_data
); ++id
)
649 m10v_reg_fixed_pre(&m10v_pll_fixed_data
[id
],
650 m10v_clk_data
, parent_name
);
653 * timer consumes "rclk" so it needs to register here.
655 hw
= m10v_clk_hw_register_divider(NULL
, "rclk", M10V_PLL10DIV2
, 0,
656 base
+ CLKSEL(1), 0, 3, 0, rclk_table
,
657 &m10v_crglock
, NULL
);
658 m10v_clk_data
->hws
[M10V_RCLK_ID
] = hw
;
660 m10v_clk_data
->num
= M10V_NUM_CLKS
;
661 of_clk_add_hw_provider(np
, of_clk_hw_onecell_get
, m10v_clk_data
);
663 CLK_OF_DECLARE_DRIVER(m10v_cc
, "socionext,milbeaut-m10v-ccu", m10v_cc_init
);