2 * clkgen-mux.c: ST GEN-MUX Clock driver
4 * Copyright (C) 2014 STMicroelectronics (R&D) Limited
6 * Authors: Stephen Gallimore <stephen.gallimore@st.com>
7 * Pankaj Dev <pankaj.dev@st.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
16 #include <linux/slab.h>
17 #include <linux/of_address.h>
18 #include <linux/clk-provider.h>
20 static DEFINE_SPINLOCK(clkgena_divmux_lock
);
21 static DEFINE_SPINLOCK(clkgenf_lock
);
23 static const char ** __init
clkgen_mux_get_parents(struct device_node
*np
,
29 nparents
= of_count_phandle_with_args(np
, "clocks", "#clock-cells");
30 if (WARN_ON(nparents
<= 0))
31 return ERR_PTR(-EINVAL
);
33 parents
= kzalloc(nparents
* sizeof(const char *), GFP_KERNEL
);
35 return ERR_PTR(-ENOMEM
);
37 for (i
= 0; i
< nparents
; i
++)
38 parents
[i
] = of_clk_get_parent_name(np
, i
);
40 *num_parents
= nparents
;
45 * DOC: Clock mux with a programmable divider on each of its three inputs.
46 * The mux has an input setting which effectively gates its output.
48 * Traits of this clock:
49 * prepare - clk_(un)prepare only ensures parent is (un)prepared
50 * enable - clk_enable and clk_disable are functional & control gating
51 * rate - set rate is supported
52 * parent - set/get parent
57 struct clkgena_divmux
{
59 /* Subclassed mux and divider structures */
61 struct clk_divider div
[NUM_INPUTS
];
62 /* Enable/running feedback register bits for each input */
63 void __iomem
*feedback_reg
[NUM_INPUTS
];
69 #define to_clkgena_divmux(_hw) container_of(_hw, struct clkgena_divmux, hw)
71 struct clkgena_divmux_data
{
76 int div_offsets
[NUM_INPUTS
];
77 int fb_offsets
[NUM_INPUTS
];
81 #define CKGAX_CLKOPSRC_SWITCH_OFF 0x3
83 static int clkgena_divmux_is_running(struct clkgena_divmux
*mux
)
85 u32 regval
= readl(mux
->feedback_reg
[mux
->muxsel
]);
86 u32 running
= regval
& BIT(mux
->feedback_bit_idx
);
90 static int clkgena_divmux_enable(struct clk_hw
*hw
)
92 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
93 struct clk_hw
*mux_hw
= &genamux
->mux
.hw
;
94 unsigned long timeout
;
97 mux_hw
->clk
= hw
->clk
;
99 ret
= clk_mux_ops
.set_parent(mux_hw
, genamux
->muxsel
);
103 timeout
= jiffies
+ msecs_to_jiffies(10);
105 while (!clkgena_divmux_is_running(genamux
)) {
106 if (time_after(jiffies
, timeout
))
114 static void clkgena_divmux_disable(struct clk_hw
*hw
)
116 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
117 struct clk_hw
*mux_hw
= &genamux
->mux
.hw
;
119 mux_hw
->clk
= hw
->clk
;
121 clk_mux_ops
.set_parent(mux_hw
, CKGAX_CLKOPSRC_SWITCH_OFF
);
124 static int clkgena_divmux_is_enabled(struct clk_hw
*hw
)
126 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
127 struct clk_hw
*mux_hw
= &genamux
->mux
.hw
;
129 mux_hw
->clk
= hw
->clk
;
131 return (s8
)clk_mux_ops
.get_parent(mux_hw
) > 0;
134 u8
clkgena_divmux_get_parent(struct clk_hw
*hw
)
136 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
137 struct clk_hw
*mux_hw
= &genamux
->mux
.hw
;
139 mux_hw
->clk
= hw
->clk
;
141 genamux
->muxsel
= clk_mux_ops
.get_parent(mux_hw
);
142 if ((s8
)genamux
->muxsel
< 0) {
143 pr_debug("%s: %s: Invalid parent, setting to default.\n",
144 __func__
, __clk_get_name(hw
->clk
));
148 return genamux
->muxsel
;
151 static int clkgena_divmux_set_parent(struct clk_hw
*hw
, u8 index
)
153 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
155 if (index
>= CKGAX_CLKOPSRC_SWITCH_OFF
)
158 genamux
->muxsel
= index
;
161 * If the mux is already enabled, call enable directly to set the
162 * new mux position and wait for it to start running again. Otherwise
165 if (clkgena_divmux_is_enabled(hw
))
166 clkgena_divmux_enable(hw
);
171 unsigned long clkgena_divmux_recalc_rate(struct clk_hw
*hw
,
172 unsigned long parent_rate
)
174 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
175 struct clk_hw
*div_hw
= &genamux
->div
[genamux
->muxsel
].hw
;
177 div_hw
->clk
= hw
->clk
;
179 return clk_divider_ops
.recalc_rate(div_hw
, parent_rate
);
182 static int clkgena_divmux_set_rate(struct clk_hw
*hw
, unsigned long rate
,
183 unsigned long parent_rate
)
185 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
186 struct clk_hw
*div_hw
= &genamux
->div
[genamux
->muxsel
].hw
;
188 div_hw
->clk
= hw
->clk
;
190 return clk_divider_ops
.set_rate(div_hw
, rate
, parent_rate
);
193 static long clkgena_divmux_round_rate(struct clk_hw
*hw
, unsigned long rate
,
194 unsigned long *prate
)
196 struct clkgena_divmux
*genamux
= to_clkgena_divmux(hw
);
197 struct clk_hw
*div_hw
= &genamux
->div
[genamux
->muxsel
].hw
;
199 div_hw
->clk
= hw
->clk
;
201 return clk_divider_ops
.round_rate(div_hw
, rate
, prate
);
204 static const struct clk_ops clkgena_divmux_ops
= {
205 .enable
= clkgena_divmux_enable
,
206 .disable
= clkgena_divmux_disable
,
207 .is_enabled
= clkgena_divmux_is_enabled
,
208 .get_parent
= clkgena_divmux_get_parent
,
209 .set_parent
= clkgena_divmux_set_parent
,
210 .round_rate
= clkgena_divmux_round_rate
,
211 .recalc_rate
= clkgena_divmux_recalc_rate
,
212 .set_rate
= clkgena_divmux_set_rate
,
216 * clk_register_genamux - register a genamux clock with the clock framework
218 struct clk
*clk_register_genamux(const char *name
,
219 const char **parent_names
, u8 num_parents
,
221 const struct clkgena_divmux_data
*muxdata
,
225 * Fixed constants across all ClockgenA variants
227 const int mux_width
= 2;
228 const int divider_width
= 5;
229 struct clkgena_divmux
*genamux
;
231 struct clk_init_data init
;
234 genamux
= kzalloc(sizeof(*genamux
), GFP_KERNEL
);
236 return ERR_PTR(-ENOMEM
);
239 init
.ops
= &clkgena_divmux_ops
;
240 init
.flags
= CLK_IS_BASIC
;
241 init
.parent_names
= parent_names
;
242 init
.num_parents
= num_parents
;
244 genamux
->mux
.lock
= &clkgena_divmux_lock
;
245 genamux
->mux
.mask
= BIT(mux_width
) - 1;
246 genamux
->mux
.shift
= muxdata
->mux_start_bit
+ (idx
* mux_width
);
247 if (genamux
->mux
.shift
> 31) {
249 * We have spilled into the second mux register so
250 * adjust the register address and the bit shift accordingly
252 genamux
->mux
.reg
= reg
+ muxdata
->mux_offset2
;
253 genamux
->mux
.shift
-= 32;
255 genamux
->mux
.reg
= reg
+ muxdata
->mux_offset
;
258 for (i
= 0; i
< NUM_INPUTS
; i
++) {
260 * Divider config for each input
262 void __iomem
*divbase
= reg
+ muxdata
->div_offsets
[i
];
263 genamux
->div
[i
].width
= divider_width
;
264 genamux
->div
[i
].reg
= divbase
+ (idx
* sizeof(u32
));
267 * Mux enabled/running feedback register for each input.
269 genamux
->feedback_reg
[i
] = reg
+ muxdata
->fb_offsets
[i
];
272 genamux
->feedback_bit_idx
= muxdata
->fb_start_bit_idx
+ idx
;
273 genamux
->hw
.init
= &init
;
275 clk
= clk_register(NULL
, &genamux
->hw
);
281 pr_debug("%s: parent %s rate %lu\n",
283 __clk_get_name(clk_get_parent(clk
)),
289 static struct clkgena_divmux_data st_divmux_c65hs
= {
293 .div_offsets
= { 0x800, 0x900, 0xb00 },
294 .fb_offsets
= { 0x18, 0x1c, 0x20 },
295 .fb_start_bit_idx
= 0,
298 static struct clkgena_divmux_data st_divmux_c65ls
= {
303 .div_offsets
= { 0x810, 0xa10, 0xb10 },
304 .fb_offsets
= { 0x18, 0x1c, 0x20 },
305 .fb_start_bit_idx
= 4,
308 static struct clkgena_divmux_data st_divmux_c32odf0
= {
312 .div_offsets
= { 0x800, 0x900, 0xa60 },
313 .fb_offsets
= { 0x2c, 0x24, 0x28 },
314 .fb_start_bit_idx
= 0,
317 static struct clkgena_divmux_data st_divmux_c32odf1
= {
321 .div_offsets
= { 0x820, 0x980, 0xa80 },
322 .fb_offsets
= { 0x2c, 0x24, 0x28 },
323 .fb_start_bit_idx
= 8,
326 static struct clkgena_divmux_data st_divmux_c32odf2
= {
330 .div_offsets
= { 0x840, 0xa20, 0xb10 },
331 .fb_offsets
= { 0x2c, 0x24, 0x28 },
332 .fb_start_bit_idx
= 16,
335 static struct clkgena_divmux_data st_divmux_c32odf3
= {
339 .div_offsets
= { 0x860, 0xa40, 0xb30 },
340 .fb_offsets
= { 0x2c, 0x24, 0x28 },
341 .fb_start_bit_idx
= 24,
344 static struct of_device_id clkgena_divmux_of_match
[] = {
346 .compatible
= "st,clkgena-divmux-c65-hs",
347 .data
= &st_divmux_c65hs
,
350 .compatible
= "st,clkgena-divmux-c65-ls",
351 .data
= &st_divmux_c65ls
,
354 .compatible
= "st,clkgena-divmux-c32-odf0",
355 .data
= &st_divmux_c32odf0
,
358 .compatible
= "st,clkgena-divmux-c32-odf1",
359 .data
= &st_divmux_c32odf1
,
362 .compatible
= "st,clkgena-divmux-c32-odf2",
363 .data
= &st_divmux_c32odf2
,
366 .compatible
= "st,clkgena-divmux-c32-odf3",
367 .data
= &st_divmux_c32odf3
,
372 static void __iomem
* __init
clkgen_get_register_base(
373 struct device_node
*np
)
375 struct device_node
*pnode
;
376 void __iomem
*reg
= NULL
;
378 pnode
= of_get_parent(np
);
382 reg
= of_iomap(pnode
, 0);
388 void __init
st_of_clkgena_divmux_setup(struct device_node
*np
)
390 const struct of_device_id
*match
;
391 const struct clkgena_divmux_data
*data
;
392 struct clk_onecell_data
*clk_data
;
394 const char **parents
;
395 int num_parents
= 0, i
;
397 match
= of_match_node(clkgena_divmux_of_match
, np
);
401 data
= (struct clkgena_divmux_data
*)match
->data
;
403 reg
= clkgen_get_register_base(np
);
407 parents
= clkgen_mux_get_parents(np
, &num_parents
);
411 clk_data
= kzalloc(sizeof(*clk_data
), GFP_KERNEL
);
415 clk_data
->clk_num
= data
->num_outputs
;
416 clk_data
->clks
= kzalloc(clk_data
->clk_num
* sizeof(struct clk
*),
422 for (i
= 0; i
< clk_data
->clk_num
; i
++) {
424 const char *clk_name
;
426 if (of_property_read_string_index(np
, "clock-output-names",
431 * If we read an empty clock name then the output is unused
433 if (*clk_name
== '\0')
436 clk
= clk_register_genamux(clk_name
, parents
, num_parents
,
442 clk_data
->clks
[i
] = clk
;
447 of_clk_add_provider(np
, of_clk_src_onecell_get
, clk_data
);
451 kfree(clk_data
->clks
);
456 CLK_OF_DECLARE(clkgenadivmux
, "st,clkgena-divmux", st_of_clkgena_divmux_setup
);
458 struct clkgena_prediv_data
{
461 struct clk_div_table
*table
;
464 static struct clk_div_table prediv_table16
[] = {
465 { .val
= 0, .div
= 1 },
466 { .val
= 1, .div
= 16 },
470 static struct clkgena_prediv_data prediv_c65_data
= {
473 .table
= prediv_table16
,
476 static struct clkgena_prediv_data prediv_c32_data
= {
479 .table
= prediv_table16
,
482 static struct of_device_id clkgena_prediv_of_match
[] = {
483 { .compatible
= "st,clkgena-prediv-c65", .data
= &prediv_c65_data
},
484 { .compatible
= "st,clkgena-prediv-c32", .data
= &prediv_c32_data
},
488 void __init
st_of_clkgena_prediv_setup(struct device_node
*np
)
490 const struct of_device_id
*match
;
492 const char *parent_name
, *clk_name
;
494 struct clkgena_prediv_data
*data
;
496 match
= of_match_node(clkgena_prediv_of_match
, np
);
498 pr_err("%s: No matching data\n", __func__
);
502 data
= (struct clkgena_prediv_data
*)match
->data
;
504 reg
= clkgen_get_register_base(np
);
508 parent_name
= of_clk_get_parent_name(np
, 0);
512 if (of_property_read_string_index(np
, "clock-output-names",
516 clk
= clk_register_divider_table(NULL
, clk_name
, parent_name
, 0,
517 reg
+ data
->offset
, data
->shift
, 1,
518 0, data
->table
, NULL
);
522 of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
523 pr_debug("%s: parent %s rate %u\n",
525 __clk_get_name(clk_get_parent(clk
)),
526 (unsigned int)clk_get_rate(clk
));
530 CLK_OF_DECLARE(clkgenaprediv
, "st,clkgena-prediv", st_of_clkgena_prediv_setup
);
532 struct clkgen_mux_data
{
537 unsigned long clk_flags
;
541 static struct clkgen_mux_data clkgen_mux_c_vcc_hd_416
= {
547 static struct clkgen_mux_data clkgen_mux_f_vcc_fvdp_416
= {
553 static struct clkgen_mux_data clkgen_mux_f_vcc_hva_416
= {
559 static struct clkgen_mux_data clkgen_mux_f_vcc_hd_416
= {
563 .lock
= &clkgenf_lock
,
566 static struct clkgen_mux_data clkgen_mux_c_vcc_sd_416
= {
570 .lock
= &clkgenf_lock
,
573 static struct clkgen_mux_data stih415_a9_mux_data
= {
578 static struct clkgen_mux_data stih416_a9_mux_data
= {
583 static struct clkgen_mux_data stih407_a9_mux_data
= {
589 static struct of_device_id mux_of_match
[] = {
591 .compatible
= "st,stih416-clkgenc-vcc-hd",
592 .data
= &clkgen_mux_c_vcc_hd_416
,
595 .compatible
= "st,stih416-clkgenf-vcc-fvdp",
596 .data
= &clkgen_mux_f_vcc_fvdp_416
,
599 .compatible
= "st,stih416-clkgenf-vcc-hva",
600 .data
= &clkgen_mux_f_vcc_hva_416
,
603 .compatible
= "st,stih416-clkgenf-vcc-hd",
604 .data
= &clkgen_mux_f_vcc_hd_416
,
607 .compatible
= "st,stih416-clkgenf-vcc-sd",
608 .data
= &clkgen_mux_c_vcc_sd_416
,
611 .compatible
= "st,stih415-clkgen-a9-mux",
612 .data
= &stih415_a9_mux_data
,
615 .compatible
= "st,stih416-clkgen-a9-mux",
616 .data
= &stih416_a9_mux_data
,
619 .compatible
= "st,stih407-clkgen-a9-mux",
620 .data
= &stih407_a9_mux_data
,
625 void __init
st_of_clkgen_mux_setup(struct device_node
*np
)
627 const struct of_device_id
*match
;
630 const char **parents
;
632 struct clkgen_mux_data
*data
;
634 match
= of_match_node(mux_of_match
, np
);
636 pr_err("%s: No matching data\n", __func__
);
640 data
= (struct clkgen_mux_data
*)match
->data
;
642 reg
= of_iomap(np
, 0);
644 pr_err("%s: Failed to get base address\n", __func__
);
648 parents
= clkgen_mux_get_parents(np
, &num_parents
);
649 if (IS_ERR(parents
)) {
650 pr_err("%s: Failed to get parents (%ld)\n",
651 __func__
, PTR_ERR(parents
));
655 clk
= clk_register_mux(NULL
, np
->name
, parents
, num_parents
,
656 data
->clk_flags
| CLK_SET_RATE_PARENT
,
658 data
->shift
, data
->width
, data
->mux_flags
,
663 pr_debug("%s: parent %s rate %u\n",
665 __clk_get_name(clk_get_parent(clk
)),
666 (unsigned int)clk_get_rate(clk
));
668 of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
675 CLK_OF_DECLARE(clkgen_mux
, "st,clkgen-mux", st_of_clkgen_mux_setup
);
677 #define VCC_MAX_CHANNELS 16
679 #define VCC_GATE_OFFSET 0x0
680 #define VCC_MUX_OFFSET 0x4
681 #define VCC_DIV_OFFSET 0x8
683 struct clkgen_vcc_data
{
685 unsigned long clk_flags
;
688 static struct clkgen_vcc_data st_clkgenc_vcc_416
= {
689 .clk_flags
= CLK_SET_RATE_PARENT
,
692 static struct clkgen_vcc_data st_clkgenf_vcc_416
= {
693 .lock
= &clkgenf_lock
,
696 static struct of_device_id vcc_of_match
[] = {
697 { .compatible
= "st,stih416-clkgenc", .data
= &st_clkgenc_vcc_416
},
698 { .compatible
= "st,stih416-clkgenf", .data
= &st_clkgenf_vcc_416
},
702 void __init
st_of_clkgen_vcc_setup(struct device_node
*np
)
704 const struct of_device_id
*match
;
706 const char **parents
;
708 struct clk_onecell_data
*clk_data
;
709 struct clkgen_vcc_data
*data
;
711 match
= of_match_node(vcc_of_match
, np
);
714 data
= (struct clkgen_vcc_data
*)match
->data
;
716 reg
= of_iomap(np
, 0);
720 parents
= clkgen_mux_get_parents(np
, &num_parents
);
724 clk_data
= kzalloc(sizeof(*clk_data
), GFP_KERNEL
);
728 clk_data
->clk_num
= VCC_MAX_CHANNELS
;
729 clk_data
->clks
= kzalloc(clk_data
->clk_num
* sizeof(struct clk
*),
735 for (i
= 0; i
< clk_data
->clk_num
; i
++) {
737 const char *clk_name
;
738 struct clk_gate
*gate
;
739 struct clk_divider
*div
;
742 if (of_property_read_string_index(np
, "clock-output-names",
747 * If we read an empty clock name then the output is unused
749 if (*clk_name
== '\0')
752 gate
= kzalloc(sizeof(struct clk_gate
), GFP_KERNEL
);
756 div
= kzalloc(sizeof(struct clk_divider
), GFP_KERNEL
);
762 mux
= kzalloc(sizeof(struct clk_mux
), GFP_KERNEL
);
769 gate
->reg
= reg
+ VCC_GATE_OFFSET
;
771 gate
->flags
= CLK_GATE_SET_TO_DISABLE
;
772 gate
->lock
= data
->lock
;
774 div
->reg
= reg
+ VCC_DIV_OFFSET
;
777 div
->flags
= CLK_DIVIDER_POWER_OF_TWO
|
778 CLK_DIVIDER_ROUND_CLOSEST
;
780 mux
->reg
= reg
+ VCC_MUX_OFFSET
;
784 clk
= clk_register_composite(NULL
, clk_name
, parents
,
786 &mux
->hw
, &clk_mux_ops
,
787 &div
->hw
, &clk_divider_ops
,
788 &gate
->hw
, &clk_gate_ops
,
797 pr_debug("%s: parent %s rate %u\n",
799 __clk_get_name(clk_get_parent(clk
)),
800 (unsigned int)clk_get_rate(clk
));
802 clk_data
->clks
[i
] = clk
;
807 of_clk_add_provider(np
, of_clk_src_onecell_get
, clk_data
);
811 for (i
= 0; i
< clk_data
->clk_num
; i
++) {
812 struct clk_composite
*composite
;
814 if (!clk_data
->clks
[i
])
817 composite
= container_of(__clk_get_hw(clk_data
->clks
[i
]),
818 struct clk_composite
, hw
);
819 kfree(container_of(composite
->gate_hw
, struct clk_gate
, hw
));
820 kfree(container_of(composite
->rate_hw
, struct clk_divider
, hw
));
821 kfree(container_of(composite
->mux_hw
, struct clk_mux
, hw
));
825 kfree(clk_data
->clks
);
830 CLK_OF_DECLARE(clkgen_vcc
, "st,clkgen-vcc", st_of_clkgen_vcc_setup
);