2 * Copyright 2013 Freescale Semiconductor, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * clock driver for Freescale PowerPC corenet SoCs.
10 #include <linux/clk-provider.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/of_address.h>
15 #include <linux/of_platform.h>
17 #include <linux/slab.h>
25 #define PLL_KILL BIT(31)
26 #define CLKSEL_SHIFT 27
27 #define CLKSEL_ADJUST BIT(0)
28 #define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
30 static unsigned int clocks_per_pll
;
32 static int cmux_set_parent(struct clk_hw
*hw
, u8 idx
)
34 struct cmux_clk
*clk
= to_cmux_clk(hw
);
37 clksel
= ((idx
/ clocks_per_pll
) << 2) + idx
% clocks_per_pll
;
38 if (clk
->flags
& CLKSEL_ADJUST
)
40 clksel
= (clksel
& 0xf) << CLKSEL_SHIFT
;
41 iowrite32be(clksel
, clk
->reg
);
46 static u8
cmux_get_parent(struct clk_hw
*hw
)
48 struct cmux_clk
*clk
= to_cmux_clk(hw
);
51 clksel
= ioread32be(clk
->reg
);
52 clksel
= (clksel
>> CLKSEL_SHIFT
) & 0xf;
53 if (clk
->flags
& CLKSEL_ADJUST
)
55 clksel
= (clksel
>> 2) * clocks_per_pll
+ clksel
% 4;
60 const struct clk_ops cmux_ops
= {
61 .get_parent
= cmux_get_parent
,
62 .set_parent
= cmux_set_parent
,
65 static void __init
core_mux_init(struct device_node
*np
)
68 struct clk_init_data init
;
69 struct cmux_clk
*cmux_clk
;
70 struct device_node
*node
;
74 const char **parent_names
;
76 rc
= of_property_read_u32(np
, "reg", &offset
);
78 pr_err("%s: could not get reg property\n", np
->name
);
82 /* get the input clock source count */
83 count
= of_property_count_strings(np
, "clock-names");
85 pr_err("%s: get clock count error\n", np
->name
);
88 parent_names
= kzalloc((sizeof(char *) * count
), GFP_KERNEL
);
90 pr_err("%s: could not allocate parent_names\n", __func__
);
94 for (i
= 0; i
< count
; i
++)
95 parent_names
[i
] = of_clk_get_parent_name(np
, i
);
97 cmux_clk
= kzalloc(sizeof(struct cmux_clk
), GFP_KERNEL
);
99 pr_err("%s: could not allocate cmux_clk\n", __func__
);
102 cmux_clk
->reg
= of_iomap(np
, 0);
103 if (!cmux_clk
->reg
) {
104 pr_err("%s: could not map register\n", __func__
);
108 node
= of_find_compatible_node(NULL
, NULL
, "fsl,p4080-clockgen");
109 if (node
&& (offset
>= 0x80))
110 cmux_clk
->flags
= CLKSEL_ADJUST
;
112 rc
= of_property_read_string_index(np
, "clock-output-names",
115 pr_err("%s: read clock names error\n", np
->name
);
119 init
.name
= clk_name
;
120 init
.ops
= &cmux_ops
;
121 init
.parent_names
= parent_names
;
122 init
.num_parents
= count
;
124 cmux_clk
->hw
.init
= &init
;
126 clk
= clk_register(NULL
, &cmux_clk
->hw
);
128 pr_err("%s: could not register clock\n", clk_name
);
132 rc
= of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
134 pr_err("Could not register clock provider for node:%s\n",
143 /* free *_names because they are reallocated when registered */
147 static void __init
core_pll_init(struct device_node
*np
)
151 const char *clk_name
, *parent_name
;
152 struct clk_onecell_data
*onecell_data
;
153 struct clk
**subclks
;
156 base
= of_iomap(np
, 0);
158 pr_err("clk-ppc: iomap error\n");
162 /* get the multiple of PLL */
163 mult
= ioread32be(base
);
165 /* check if this PLL is disabled */
166 if (mult
& PLL_KILL
) {
167 pr_debug("PLL:%s is disabled\n", np
->name
);
170 mult
= (mult
>> 1) & 0x3f;
172 parent_name
= of_clk_get_parent_name(np
, 0);
174 pr_err("PLL: %s must have a parent\n", np
->name
);
178 count
= of_property_count_strings(np
, "clock-output-names");
179 if (count
< 0 || count
> 4) {
180 pr_err("%s: clock is not supported\n", np
->name
);
184 /* output clock number per PLL */
185 clocks_per_pll
= count
;
187 subclks
= kzalloc(sizeof(struct clk
*) * count
, GFP_KERNEL
);
189 pr_err("%s: could not allocate subclks\n", __func__
);
193 onecell_data
= kzalloc(sizeof(struct clk_onecell_data
), GFP_KERNEL
);
195 pr_err("%s: could not allocate onecell_data\n", __func__
);
199 for (i
= 0; i
< count
; i
++) {
200 rc
= of_property_read_string_index(np
, "clock-output-names",
203 pr_err("%s: could not get clock names\n", np
->name
);
208 * when count == 4, there are 4 output clocks:
209 * /1, /2, /3, /4 respectively
210 * when count < 4, there are at least 2 output clocks:
211 * /1, /2, (/4, if count == 3) respectively.
214 subclks
[i
] = clk_register_fixed_factor(NULL
, clk_name
,
215 parent_name
, 0, mult
, 1 + i
);
218 subclks
[i
] = clk_register_fixed_factor(NULL
, clk_name
,
219 parent_name
, 0, mult
, 1 << i
);
221 if (IS_ERR(subclks
[i
])) {
222 pr_err("%s: could not register clock\n", clk_name
);
227 onecell_data
->clks
= subclks
;
228 onecell_data
->clk_num
= count
;
230 rc
= of_clk_add_provider(np
, of_clk_src_onecell_get
, onecell_data
);
232 pr_err("Could not register clk provider for node:%s\n",
247 static void __init
sysclk_init(struct device_node
*node
)
250 const char *clk_name
= node
->name
;
251 struct device_node
*np
= of_get_parent(node
);
255 pr_err("ppc-clk: could not get parent node\n");
259 if (of_property_read_u32(np
, "clock-frequency", &rate
)) {
264 of_property_read_string(np
, "clock-output-names", &clk_name
);
266 clk
= clk_register_fixed_rate(NULL
, clk_name
, NULL
, CLK_IS_ROOT
, rate
);
268 of_clk_add_provider(np
, of_clk_src_simple_get
, clk
);
271 static const struct of_device_id clk_match
[] __initconst
= {
272 { .compatible
= "fsl,qoriq-sysclk-1.0", .data
= sysclk_init
, },
273 { .compatible
= "fsl,qoriq-sysclk-2.0", .data
= sysclk_init
, },
274 { .compatible
= "fsl,qoriq-core-pll-1.0", .data
= core_pll_init
, },
275 { .compatible
= "fsl,qoriq-core-pll-2.0", .data
= core_pll_init
, },
276 { .compatible
= "fsl,qoriq-core-mux-1.0", .data
= core_mux_init
, },
277 { .compatible
= "fsl,qoriq-core-mux-2.0", .data
= core_mux_init
, },
281 static int __init
ppc_corenet_clk_probe(struct platform_device
*pdev
)
283 of_clk_init(clk_match
);
288 static const struct of_device_id ppc_clk_ids
[] __initconst
= {
289 { .compatible
= "fsl,qoriq-clockgen-1.0", },
290 { .compatible
= "fsl,qoriq-clockgen-2.0", },
294 static struct platform_driver ppc_corenet_clk_driver __initdata
= {
296 .name
= "ppc_corenet_clock",
297 .owner
= THIS_MODULE
,
298 .of_match_table
= ppc_clk_ids
,
300 .probe
= ppc_corenet_clk_probe
,
303 static int __init
ppc_corenet_clk_init(void)
305 return platform_driver_register(&ppc_corenet_clk_driver
);
307 subsys_initcall(ppc_corenet_clk_init
);