aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk-qoriq.c
diff options
context:
space:
mode:
authorTang Yuantian <Yuantian.Tang@freescale.com>2015-01-15 01:03:41 -0500
committerMichael Turquette <mturquette@linaro.org>2015-01-20 13:09:12 -0500
commit93a17c058f610398739c8b930ff3c83a0c0b0120 (patch)
treebdfabfc3da30d61591792629b621a495d488395a /drivers/clk/clk-qoriq.c
parent57bfd7ee6fa9811481e6d67ff18aa90951dd974e (diff)
clk: ppc-corenet: rename driver to clk-qoriq
Freescale introduced new ARM-based socs which using the compatible clock IP block with PowerPC-based socs'. So this driver can be used on both platforms. Updated relevant descriptions and renamed this driver to better represent its meaning and keep the function of driver untouched. Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com> Signed-off-by: Michael Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/clk-qoriq.c')
-rw-r--r--drivers/clk/clk-qoriq.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
new file mode 100644
index 000000000000..f9b7eb43ac69
--- /dev/null
+++ b/drivers/clk/clk-qoriq.c
@@ -0,0 +1,283 @@
1/*
2 * Copyright 2013 Freescale Semiconductor, Inc.
3 *
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.
7 *
8 * clock driver for Freescale QorIQ SoCs.
9 */
10#include <linux/clk-provider.h>
11#include <linux/io.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of_address.h>
15#include <linux/of_platform.h>
16#include <linux/of.h>
17#include <linux/slab.h>
18
19struct cmux_clk {
20 struct clk_hw hw;
21 void __iomem *reg;
22 unsigned int clk_per_pll;
23 u32 flags;
24};
25
26#define PLL_KILL BIT(31)
27#define CLKSEL_SHIFT 27
28#define CLKSEL_ADJUST BIT(0)
29#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
30
31static int cmux_set_parent(struct clk_hw *hw, u8 idx)
32{
33 struct cmux_clk *clk = to_cmux_clk(hw);
34 u32 clksel;
35
36 clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
37 if (clk->flags & CLKSEL_ADJUST)
38 clksel += 8;
39 clksel = (clksel & 0xf) << CLKSEL_SHIFT;
40 iowrite32be(clksel, clk->reg);
41
42 return 0;
43}
44
45static u8 cmux_get_parent(struct clk_hw *hw)
46{
47 struct cmux_clk *clk = to_cmux_clk(hw);
48 u32 clksel;
49
50 clksel = ioread32be(clk->reg);
51 clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
52 if (clk->flags & CLKSEL_ADJUST)
53 clksel -= 8;
54 clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
55
56 return clksel;
57}
58
59const struct clk_ops cmux_ops = {
60 .get_parent = cmux_get_parent,
61 .set_parent = cmux_set_parent,
62};
63
64static void __init core_mux_init(struct device_node *np)
65{
66 struct clk *clk;
67 struct clk_init_data init;
68 struct cmux_clk *cmux_clk;
69 struct device_node *node;
70 int rc, count, i;
71 u32 offset;
72 const char *clk_name;
73 const char **parent_names;
74 struct of_phandle_args clkspec;
75
76 rc = of_property_read_u32(np, "reg", &offset);
77 if (rc) {
78 pr_err("%s: could not get reg property\n", np->name);
79 return;
80 }
81
82 /* get the input clock source count */
83 count = of_property_count_strings(np, "clock-names");
84 if (count < 0) {
85 pr_err("%s: get clock count error\n", np->name);
86 return;
87 }
88 parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
89 if (!parent_names) {
90 pr_err("%s: could not allocate parent_names\n", __func__);
91 return;
92 }
93
94 for (i = 0; i < count; i++)
95 parent_names[i] = of_clk_get_parent_name(np, i);
96
97 cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
98 if (!cmux_clk) {
99 pr_err("%s: could not allocate cmux_clk\n", __func__);
100 goto err_name;
101 }
102 cmux_clk->reg = of_iomap(np, 0);
103 if (!cmux_clk->reg) {
104 pr_err("%s: could not map register\n", __func__);
105 goto err_clk;
106 }
107
108 rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
109 &clkspec);
110 if (rc) {
111 pr_err("%s: parse clock node error\n", __func__);
112 goto err_clk;
113 }
114
115 cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
116 "clock-output-names");
117 of_node_put(clkspec.np);
118
119 node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
120 if (node && (offset >= 0x80))
121 cmux_clk->flags = CLKSEL_ADJUST;
122
123 rc = of_property_read_string_index(np, "clock-output-names",
124 0, &clk_name);
125 if (rc) {
126 pr_err("%s: read clock names error\n", np->name);
127 goto err_clk;
128 }
129
130 init.name = clk_name;
131 init.ops = &cmux_ops;
132 init.parent_names = parent_names;
133 init.num_parents = count;
134 init.flags = 0;
135 cmux_clk->hw.init = &init;
136
137 clk = clk_register(NULL, &cmux_clk->hw);
138 if (IS_ERR(clk)) {
139 pr_err("%s: could not register clock\n", clk_name);
140 goto err_clk;
141 }
142
143 rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
144 if (rc) {
145 pr_err("Could not register clock provider for node:%s\n",
146 np->name);
147 goto err_clk;
148 }
149 goto err_name;
150
151err_clk:
152 kfree(cmux_clk);
153err_name:
154 /* free *_names because they are reallocated when registered */
155 kfree(parent_names);
156}
157
158static void __init core_pll_init(struct device_node *np)
159{
160 u32 mult;
161 int i, rc, count;
162 const char *clk_name, *parent_name;
163 struct clk_onecell_data *onecell_data;
164 struct clk **subclks;
165 void __iomem *base;
166
167 base = of_iomap(np, 0);
168 if (!base) {
169 pr_err("clk-qoriq: iomap error\n");
170 return;
171 }
172
173 /* get the multiple of PLL */
174 mult = ioread32be(base);
175
176 /* check if this PLL is disabled */
177 if (mult & PLL_KILL) {
178 pr_debug("PLL:%s is disabled\n", np->name);
179 goto err_map;
180 }
181 mult = (mult >> 1) & 0x3f;
182
183 parent_name = of_clk_get_parent_name(np, 0);
184 if (!parent_name) {
185 pr_err("PLL: %s must have a parent\n", np->name);
186 goto err_map;
187 }
188
189 count = of_property_count_strings(np, "clock-output-names");
190 if (count < 0 || count > 4) {
191 pr_err("%s: clock is not supported\n", np->name);
192 goto err_map;
193 }
194
195 subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
196 if (!subclks) {
197 pr_err("%s: could not allocate subclks\n", __func__);
198 goto err_map;
199 }
200
201 onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
202 if (!onecell_data) {
203 pr_err("%s: could not allocate onecell_data\n", __func__);
204 goto err_clks;
205 }
206
207 for (i = 0; i < count; i++) {
208 rc = of_property_read_string_index(np, "clock-output-names",
209 i, &clk_name);
210 if (rc) {
211 pr_err("%s: could not get clock names\n", np->name);
212 goto err_cell;
213 }
214
215 /*
216 * when count == 4, there are 4 output clocks:
217 * /1, /2, /3, /4 respectively
218 * when count < 4, there are at least 2 output clocks:
219 * /1, /2, (/4, if count == 3) respectively.
220 */
221 if (count == 4)
222 subclks[i] = clk_register_fixed_factor(NULL, clk_name,
223 parent_name, 0, mult, 1 + i);
224 else
225
226 subclks[i] = clk_register_fixed_factor(NULL, clk_name,
227 parent_name, 0, mult, 1 << i);
228
229 if (IS_ERR(subclks[i])) {
230 pr_err("%s: could not register clock\n", clk_name);
231 goto err_cell;
232 }
233 }
234
235 onecell_data->clks = subclks;
236 onecell_data->clk_num = count;
237
238 rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
239 if (rc) {
240 pr_err("Could not register clk provider for node:%s\n",
241 np->name);
242 goto err_cell;
243 }
244
245 iounmap(base);
246 return;
247err_cell:
248 kfree(onecell_data);
249err_clks:
250 kfree(subclks);
251err_map:
252 iounmap(base);
253}
254
255static void __init sysclk_init(struct device_node *node)
256{
257 struct clk *clk;
258 const char *clk_name = node->name;
259 struct device_node *np = of_get_parent(node);
260 u32 rate;
261
262 if (!np) {
263 pr_err("qoriq-clk: could not get parent node\n");
264 return;
265 }
266
267 if (of_property_read_u32(np, "clock-frequency", &rate)) {
268 of_node_put(node);
269 return;
270 }
271
272 of_property_read_string(np, "clock-output-names", &clk_name);
273
274 clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
275 if (!IS_ERR(clk))
276 of_clk_add_provider(np, of_clk_src_simple_get, clk);
277}
278CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
279CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
280CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
281CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
282CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
283CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);