Commit | Line | Data |
---|---|---|
f94859c2 LP |
1 | /* |
2 | * R-Car MSTP clocks | |
3 | * | |
4 | * Copyright (C) 2013 Ideas On Board SPRL | |
752b5ed5 | 5 | * Copyright (C) 2015 Glider bvba |
f94859c2 LP |
6 | * |
7 | * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | |
8 | * | |
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; version 2 of the License. | |
12 | */ | |
13 | ||
752b5ed5 | 14 | #include <linux/clk.h> |
f94859c2 LP |
15 | #include <linux/clk-provider.h> |
16 | #include <linux/clkdev.h> | |
09c32427 | 17 | #include <linux/clk/renesas.h> |
752b5ed5 | 18 | #include <linux/device.h> |
f94859c2 LP |
19 | #include <linux/io.h> |
20 | #include <linux/of.h> | |
21 | #include <linux/of_address.h> | |
752b5ed5 GU |
22 | #include <linux/pm_clock.h> |
23 | #include <linux/pm_domain.h> | |
f94859c2 LP |
24 | #include <linux/spinlock.h> |
25 | ||
26 | /* | |
27 | * MSTP clocks. We can't use standard gate clocks as we need to poll on the | |
28 | * status register when enabling the clock. | |
29 | */ | |
30 | ||
31 | #define MSTP_MAX_CLOCKS 32 | |
32 | ||
33 | /** | |
34 | * struct mstp_clock_group - MSTP gating clocks group | |
35 | * | |
36 | * @data: clocks in this group | |
37 | * @smstpcr: module stop control register | |
38 | * @mstpsr: module stop status register (optional) | |
39 | * @lock: protects writes to SMSTPCR | |
40 | */ | |
41 | struct mstp_clock_group { | |
42 | struct clk_onecell_data data; | |
43 | void __iomem *smstpcr; | |
44 | void __iomem *mstpsr; | |
45 | spinlock_t lock; | |
46 | }; | |
47 | ||
48 | /** | |
49 | * struct mstp_clock - MSTP gating clock | |
50 | * @hw: handle between common and hardware-specific interfaces | |
51 | * @bit_index: control bit index | |
52 | * @group: MSTP clocks group | |
53 | */ | |
54 | struct mstp_clock { | |
55 | struct clk_hw hw; | |
56 | u32 bit_index; | |
57 | struct mstp_clock_group *group; | |
58 | }; | |
59 | ||
60 | #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) | |
61 | ||
62 | static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) | |
63 | { | |
64 | struct mstp_clock *clock = to_mstp_clock(hw); | |
65 | struct mstp_clock_group *group = clock->group; | |
66 | u32 bitmask = BIT(clock->bit_index); | |
67 | unsigned long flags; | |
68 | unsigned int i; | |
69 | u32 value; | |
70 | ||
71 | spin_lock_irqsave(&group->lock, flags); | |
72 | ||
73 | value = clk_readl(group->smstpcr); | |
74 | if (enable) | |
75 | value &= ~bitmask; | |
76 | else | |
77 | value |= bitmask; | |
78 | clk_writel(value, group->smstpcr); | |
79 | ||
80 | spin_unlock_irqrestore(&group->lock, flags); | |
81 | ||
82 | if (!enable || !group->mstpsr) | |
83 | return 0; | |
84 | ||
85 | for (i = 1000; i > 0; --i) { | |
86 | if (!(clk_readl(group->mstpsr) & bitmask)) | |
87 | break; | |
88 | cpu_relax(); | |
89 | } | |
90 | ||
91 | if (!i) { | |
92 | pr_err("%s: failed to enable %p[%d]\n", __func__, | |
93 | group->smstpcr, clock->bit_index); | |
94 | return -ETIMEDOUT; | |
95 | } | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | static int cpg_mstp_clock_enable(struct clk_hw *hw) | |
101 | { | |
102 | return cpg_mstp_clock_endisable(hw, true); | |
103 | } | |
104 | ||
105 | static void cpg_mstp_clock_disable(struct clk_hw *hw) | |
106 | { | |
107 | cpg_mstp_clock_endisable(hw, false); | |
108 | } | |
109 | ||
110 | static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) | |
111 | { | |
112 | struct mstp_clock *clock = to_mstp_clock(hw); | |
113 | struct mstp_clock_group *group = clock->group; | |
114 | u32 value; | |
115 | ||
116 | if (group->mstpsr) | |
117 | value = clk_readl(group->mstpsr); | |
118 | else | |
119 | value = clk_readl(group->smstpcr); | |
120 | ||
bb178da7 | 121 | return !(value & BIT(clock->bit_index)); |
f94859c2 LP |
122 | } |
123 | ||
124 | static const struct clk_ops cpg_mstp_clock_ops = { | |
125 | .enable = cpg_mstp_clock_enable, | |
126 | .disable = cpg_mstp_clock_disable, | |
127 | .is_enabled = cpg_mstp_clock_is_enabled, | |
128 | }; | |
129 | ||
130 | static struct clk * __init | |
131 | cpg_mstp_clock_register(const char *name, const char *parent_name, | |
132 | unsigned int index, struct mstp_clock_group *group) | |
133 | { | |
134 | struct clk_init_data init; | |
135 | struct mstp_clock *clock; | |
136 | struct clk *clk; | |
137 | ||
138 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); | |
139 | if (!clock) { | |
140 | pr_err("%s: failed to allocate MSTP clock.\n", __func__); | |
141 | return ERR_PTR(-ENOMEM); | |
142 | } | |
143 | ||
144 | init.name = name; | |
145 | init.ops = &cpg_mstp_clock_ops; | |
e44df332 | 146 | init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; |
f94859c2 LP |
147 | init.parent_names = &parent_name; |
148 | init.num_parents = 1; | |
149 | ||
150 | clock->bit_index = index; | |
151 | clock->group = group; | |
152 | clock->hw.init = &init; | |
153 | ||
154 | clk = clk_register(NULL, &clock->hw); | |
155 | ||
156 | if (IS_ERR(clk)) | |
157 | kfree(clock); | |
158 | ||
159 | return clk; | |
160 | } | |
161 | ||
162 | static void __init cpg_mstp_clocks_init(struct device_node *np) | |
163 | { | |
164 | struct mstp_clock_group *group; | |
8e33f91a | 165 | const char *idxname; |
f94859c2 LP |
166 | struct clk **clks; |
167 | unsigned int i; | |
168 | ||
169 | group = kzalloc(sizeof(*group), GFP_KERNEL); | |
209f4fed | 170 | clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL); |
f94859c2 LP |
171 | if (group == NULL || clks == NULL) { |
172 | kfree(group); | |
173 | kfree(clks); | |
174 | pr_err("%s: failed to allocate group\n", __func__); | |
175 | return; | |
176 | } | |
177 | ||
178 | spin_lock_init(&group->lock); | |
179 | group->data.clks = clks; | |
180 | ||
181 | group->smstpcr = of_iomap(np, 0); | |
182 | group->mstpsr = of_iomap(np, 1); | |
183 | ||
184 | if (group->smstpcr == NULL) { | |
185 | pr_err("%s: failed to remap SMSTPCR\n", __func__); | |
186 | kfree(group); | |
187 | kfree(clks); | |
188 | return; | |
189 | } | |
190 | ||
209f4fed VB |
191 | for (i = 0; i < MSTP_MAX_CLOCKS; ++i) |
192 | clks[i] = ERR_PTR(-ENOENT); | |
193 | ||
8e33f91a BD |
194 | if (of_find_property(np, "clock-indices", &i)) |
195 | idxname = "clock-indices"; | |
196 | else | |
197 | idxname = "renesas,clock-indices"; | |
198 | ||
f94859c2 LP |
199 | for (i = 0; i < MSTP_MAX_CLOCKS; ++i) { |
200 | const char *parent_name; | |
201 | const char *name; | |
202 | u32 clkidx; | |
203 | int ret; | |
204 | ||
205 | /* Skip clocks with no name. */ | |
206 | ret = of_property_read_string_index(np, "clock-output-names", | |
207 | i, &name); | |
208 | if (ret < 0 || strlen(name) == 0) | |
209 | continue; | |
210 | ||
211 | parent_name = of_clk_get_parent_name(np, i); | |
8e33f91a | 212 | ret = of_property_read_u32_index(np, idxname, i, &clkidx); |
f94859c2 LP |
213 | if (parent_name == NULL || ret < 0) |
214 | break; | |
215 | ||
216 | if (clkidx >= MSTP_MAX_CLOCKS) { | |
08ebdf80 | 217 | pr_err("%s: invalid clock %s %s index %u\n", |
f94859c2 LP |
218 | __func__, np->name, name, clkidx); |
219 | continue; | |
220 | } | |
221 | ||
6413b090 VB |
222 | clks[clkidx] = cpg_mstp_clock_register(name, parent_name, |
223 | clkidx, group); | |
f94859c2 | 224 | if (!IS_ERR(clks[clkidx])) { |
209f4fed VB |
225 | group->data.clk_num = max(group->data.clk_num, |
226 | clkidx + 1); | |
f94859c2 LP |
227 | /* |
228 | * Register a clkdev to let board code retrieve the | |
229 | * clock by name and register aliases for non-DT | |
230 | * devices. | |
231 | * | |
232 | * FIXME: Remove this when all devices that require a | |
233 | * clock will be instantiated from DT. | |
234 | */ | |
235 | clk_register_clkdev(clks[clkidx], name, NULL); | |
236 | } else { | |
237 | pr_err("%s: failed to register %s %s clock (%ld)\n", | |
238 | __func__, np->name, name, PTR_ERR(clks[clkidx])); | |
239 | } | |
240 | } | |
241 | ||
242 | of_clk_add_provider(np, of_clk_src_onecell_get, &group->data); | |
243 | } | |
244 | CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); | |
752b5ed5 | 245 | |
12a56817 | 246 | int cpg_mstp_attach_dev(struct generic_pm_domain *unused, struct device *dev) |
752b5ed5 GU |
247 | { |
248 | struct device_node *np = dev->of_node; | |
249 | struct of_phandle_args clkspec; | |
250 | struct clk *clk; | |
251 | int i = 0; | |
252 | int error; | |
253 | ||
254 | while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, | |
255 | &clkspec)) { | |
256 | if (of_device_is_compatible(clkspec.np, | |
257 | "renesas,cpg-mstp-clocks")) | |
258 | goto found; | |
259 | ||
e233d74c GU |
260 | /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */ |
261 | if (!strcmp(clkspec.np->name, "zb_clk")) | |
262 | goto found; | |
263 | ||
752b5ed5 GU |
264 | of_node_put(clkspec.np); |
265 | i++; | |
266 | } | |
267 | ||
268 | return 0; | |
269 | ||
270 | found: | |
271 | clk = of_clk_get_from_provider(&clkspec); | |
272 | of_node_put(clkspec.np); | |
273 | ||
274 | if (IS_ERR(clk)) | |
275 | return PTR_ERR(clk); | |
276 | ||
277 | error = pm_clk_create(dev); | |
278 | if (error) { | |
279 | dev_err(dev, "pm_clk_create failed %d\n", error); | |
280 | goto fail_put; | |
281 | } | |
282 | ||
283 | error = pm_clk_add_clk(dev, clk); | |
284 | if (error) { | |
285 | dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error); | |
286 | goto fail_destroy; | |
287 | } | |
288 | ||
289 | return 0; | |
290 | ||
291 | fail_destroy: | |
292 | pm_clk_destroy(dev); | |
293 | fail_put: | |
294 | clk_put(clk); | |
295 | return error; | |
296 | } | |
297 | ||
12a56817 | 298 | void cpg_mstp_detach_dev(struct generic_pm_domain *unused, struct device *dev) |
752b5ed5 GU |
299 | { |
300 | if (!list_empty(&dev->power.subsys_data->clock_list)) | |
301 | pm_clk_destroy(dev); | |
302 | } | |
303 | ||
304 | void __init cpg_mstp_add_clk_domain(struct device_node *np) | |
305 | { | |
306 | struct generic_pm_domain *pd; | |
307 | u32 ncells; | |
308 | ||
309 | if (of_property_read_u32(np, "#power-domain-cells", &ncells)) { | |
310 | pr_warn("%s lacks #power-domain-cells\n", np->full_name); | |
311 | return; | |
312 | } | |
313 | ||
314 | pd = kzalloc(sizeof(*pd), GFP_KERNEL); | |
315 | if (!pd) | |
316 | return; | |
317 | ||
318 | pd->name = np->name; | |
319 | ||
320 | pd->flags = GENPD_FLAG_PM_CLK; | |
321 | pm_genpd_init(pd, &simple_qos_governor, false); | |
322 | pd->attach_dev = cpg_mstp_attach_dev; | |
323 | pd->detach_dev = cpg_mstp_detach_dev; | |
324 | ||
325 | of_genpd_add_provider_simple(np, pd); | |
326 | } |