Commit | Line | Data |
---|---|---|
c6ed4d73 DL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Clock driver for TI Davinci PSC controllers | |
4 | * | |
5 | * Copyright (C) 2017 David Lechner <david@lechnology.com> | |
6 | * | |
7 | * Based on: drivers/clk/keystone/gate.c | |
8 | * Copyright (C) 2013 Texas Instruments. | |
9 | * Murali Karicheri <m-karicheri2@ti.com> | |
10 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | |
11 | * | |
12 | * And: arch/arm/mach-davinci/psc.c | |
13 | * Copyright (C) 2006 Texas Instruments. | |
14 | */ | |
15 | ||
16 | #include <linux/clk-provider.h> | |
17 | #include <linux/clk.h> | |
043eaa70 | 18 | #include <linux/clk/davinci.h> |
c6ed4d73 DL |
19 | #include <linux/clkdev.h> |
20 | #include <linux/err.h> | |
21 | #include <linux/of_address.h> | |
22 | #include <linux/of_device.h> | |
23 | #include <linux/of.h> | |
24 | #include <linux/platform_device.h> | |
25 | #include <linux/pm_clock.h> | |
26 | #include <linux/pm_domain.h> | |
27 | #include <linux/regmap.h> | |
28 | #include <linux/reset-controller.h> | |
29 | #include <linux/slab.h> | |
30 | #include <linux/types.h> | |
31 | ||
32 | #include "psc.h" | |
33 | ||
34 | /* PSC register offsets */ | |
35 | #define EPCPR 0x070 | |
36 | #define PTCMD 0x120 | |
37 | #define PTSTAT 0x128 | |
38 | #define PDSTAT(n) (0x200 + 4 * (n)) | |
39 | #define PDCTL(n) (0x300 + 4 * (n)) | |
40 | #define MDSTAT(n) (0x800 + 4 * (n)) | |
41 | #define MDCTL(n) (0xa00 + 4 * (n)) | |
42 | ||
43 | /* PSC module states */ | |
44 | enum davinci_lpsc_state { | |
45 | LPSC_STATE_SWRSTDISABLE = 0, | |
46 | LPSC_STATE_SYNCRST = 1, | |
47 | LPSC_STATE_DISABLE = 2, | |
48 | LPSC_STATE_ENABLE = 3, | |
49 | }; | |
50 | ||
51 | #define MDSTAT_STATE_MASK GENMASK(5, 0) | |
52 | #define MDSTAT_MCKOUT BIT(12) | |
53 | #define PDSTAT_STATE_MASK GENMASK(4, 0) | |
54 | #define MDCTL_FORCE BIT(31) | |
55 | #define MDCTL_LRESET BIT(8) | |
56 | #define PDCTL_EPCGOOD BIT(8) | |
57 | #define PDCTL_NEXT BIT(0) | |
58 | ||
59 | struct davinci_psc_data { | |
60 | struct clk_onecell_data clk_data; | |
61 | struct genpd_onecell_data pm_data; | |
62 | struct reset_controller_dev rcdev; | |
63 | }; | |
64 | ||
65 | /** | |
66 | * struct davinci_lpsc_clk - LPSC clock structure | |
043eaa70 | 67 | * @dev: the device that provides this LPSC or NULL |
c6ed4d73 DL |
68 | * @hw: clk_hw for the LPSC |
69 | * @pm_domain: power domain for the LPSC | |
70 | * @genpd_clk: clock reference owned by @pm_domain | |
71 | * @regmap: PSC MMIO region | |
72 | * @md: Module domain (LPSC module id) | |
73 | * @pd: Power domain | |
74 | * @flags: LPSC_* quirk flags | |
75 | */ | |
76 | struct davinci_lpsc_clk { | |
77 | struct device *dev; | |
78 | struct clk_hw hw; | |
79 | struct generic_pm_domain pm_domain; | |
80 | struct clk *genpd_clk; | |
81 | struct regmap *regmap; | |
82 | u32 md; | |
83 | u32 pd; | |
84 | u32 flags; | |
85 | }; | |
86 | ||
87 | #define to_davinci_psc_data(x) container_of(x, struct davinci_psc_data, x) | |
88 | #define to_davinci_lpsc_clk(x) container_of(x, struct davinci_lpsc_clk, x) | |
89 | ||
90 | /** | |
91 | * best_dev_name - get the "best" device name. | |
92 | * @dev: the device | |
93 | * | |
94 | * Returns the device tree compatible name if the device has a DT node, | |
95 | * otherwise return the device name. This is mainly needed because clkdev | |
96 | * lookups are limited to 20 chars for dev_id and when using device tree, | |
97 | * dev_name(dev) is much longer than that. | |
98 | */ | |
99 | static inline const char *best_dev_name(struct device *dev) | |
100 | { | |
101 | const char *compatible; | |
102 | ||
103 | if (!of_property_read_string(dev->of_node, "compatible", &compatible)) | |
104 | return compatible; | |
105 | ||
106 | return dev_name(dev); | |
107 | } | |
108 | ||
109 | static void davinci_lpsc_config(struct davinci_lpsc_clk *lpsc, | |
110 | enum davinci_lpsc_state next_state) | |
111 | { | |
112 | u32 epcpr, pdstat, mdstat, ptstat; | |
113 | ||
114 | regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDSTAT_STATE_MASK, | |
115 | next_state); | |
116 | ||
117 | if (lpsc->flags & LPSC_FORCE) | |
118 | regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_FORCE, | |
119 | MDCTL_FORCE); | |
120 | ||
121 | regmap_read(lpsc->regmap, PDSTAT(lpsc->pd), &pdstat); | |
122 | if ((pdstat & PDSTAT_STATE_MASK) == 0) { | |
123 | regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_NEXT, | |
124 | PDCTL_NEXT); | |
125 | ||
126 | regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd)); | |
127 | ||
128 | regmap_read_poll_timeout(lpsc->regmap, EPCPR, epcpr, | |
129 | epcpr & BIT(lpsc->pd), 0, 0); | |
130 | ||
131 | regmap_write_bits(lpsc->regmap, PDCTL(lpsc->pd), PDCTL_EPCGOOD, | |
132 | PDCTL_EPCGOOD); | |
133 | } else { | |
134 | regmap_write(lpsc->regmap, PTCMD, BIT(lpsc->pd)); | |
135 | } | |
136 | ||
137 | regmap_read_poll_timeout(lpsc->regmap, PTSTAT, ptstat, | |
138 | !(ptstat & BIT(lpsc->pd)), 0, 0); | |
139 | ||
140 | regmap_read_poll_timeout(lpsc->regmap, MDSTAT(lpsc->md), mdstat, | |
141 | (mdstat & MDSTAT_STATE_MASK) == next_state, | |
142 | 0, 0); | |
143 | } | |
144 | ||
145 | static int davinci_lpsc_clk_enable(struct clk_hw *hw) | |
146 | { | |
147 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); | |
148 | ||
149 | davinci_lpsc_config(lpsc, LPSC_STATE_ENABLE); | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
154 | static void davinci_lpsc_clk_disable(struct clk_hw *hw) | |
155 | { | |
156 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); | |
157 | ||
158 | davinci_lpsc_config(lpsc, LPSC_STATE_DISABLE); | |
159 | } | |
160 | ||
161 | static int davinci_lpsc_clk_is_enabled(struct clk_hw *hw) | |
162 | { | |
163 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); | |
164 | u32 mdstat; | |
165 | ||
166 | regmap_read(lpsc->regmap, MDSTAT(lpsc->md), &mdstat); | |
167 | ||
168 | return (mdstat & MDSTAT_MCKOUT) ? 1 : 0; | |
169 | } | |
170 | ||
171 | static const struct clk_ops davinci_lpsc_clk_ops = { | |
172 | .enable = davinci_lpsc_clk_enable, | |
173 | .disable = davinci_lpsc_clk_disable, | |
174 | .is_enabled = davinci_lpsc_clk_is_enabled, | |
175 | }; | |
176 | ||
177 | static int davinci_psc_genpd_attach_dev(struct generic_pm_domain *pm_domain, | |
178 | struct device *dev) | |
179 | { | |
180 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain); | |
181 | struct clk *clk; | |
182 | int ret; | |
183 | ||
184 | /* | |
185 | * pm_clk_remove_clk() will call clk_put(), so we have to use clk_get() | |
186 | * to get the clock instead of using lpsc->hw.clk directly. | |
187 | */ | |
188 | clk = clk_get_sys(best_dev_name(lpsc->dev), clk_hw_get_name(&lpsc->hw)); | |
189 | if (IS_ERR(clk)) | |
190 | return (PTR_ERR(clk)); | |
191 | ||
192 | ret = pm_clk_create(dev); | |
193 | if (ret < 0) | |
194 | goto fail_clk_put; | |
195 | ||
196 | ret = pm_clk_add_clk(dev, clk); | |
197 | if (ret < 0) | |
198 | goto fail_pm_clk_destroy; | |
199 | ||
200 | lpsc->genpd_clk = clk; | |
201 | ||
202 | return 0; | |
203 | ||
204 | fail_pm_clk_destroy: | |
205 | pm_clk_destroy(dev); | |
206 | fail_clk_put: | |
207 | clk_put(clk); | |
208 | ||
209 | return ret; | |
210 | } | |
211 | ||
212 | static void davinci_psc_genpd_detach_dev(struct generic_pm_domain *pm_domain, | |
213 | struct device *dev) | |
214 | { | |
215 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(pm_domain); | |
216 | ||
217 | pm_clk_remove_clk(dev, lpsc->genpd_clk); | |
218 | pm_clk_destroy(dev); | |
219 | ||
220 | lpsc->genpd_clk = NULL; | |
221 | } | |
222 | ||
223 | /** | |
224 | * davinci_lpsc_clk_register - register LPSC clock | |
043eaa70 | 225 | * @dev: the clocks's device or NULL |
c6ed4d73 DL |
226 | * @name: name of this clock |
227 | * @parent_name: name of clock's parent | |
228 | * @regmap: PSC MMIO region | |
229 | * @md: local PSC number | |
230 | * @pd: power domain | |
231 | * @flags: LPSC_* flags | |
232 | */ | |
233 | static struct davinci_lpsc_clk * | |
234 | davinci_lpsc_clk_register(struct device *dev, const char *name, | |
235 | const char *parent_name, struct regmap *regmap, | |
236 | u32 md, u32 pd, u32 flags) | |
237 | { | |
238 | struct clk_init_data init; | |
239 | struct davinci_lpsc_clk *lpsc; | |
240 | int ret; | |
241 | bool is_on; | |
242 | ||
043eaa70 | 243 | lpsc = kzalloc(sizeof(*lpsc), GFP_KERNEL); |
c6ed4d73 DL |
244 | if (!lpsc) |
245 | return ERR_PTR(-ENOMEM); | |
246 | ||
247 | init.name = name; | |
248 | init.ops = &davinci_lpsc_clk_ops; | |
249 | init.parent_names = (parent_name ? &parent_name : NULL); | |
250 | init.num_parents = (parent_name ? 1 : 0); | |
251 | init.flags = 0; | |
252 | ||
253 | if (flags & LPSC_ALWAYS_ENABLED) | |
254 | init.flags |= CLK_IS_CRITICAL; | |
255 | ||
256 | if (flags & LPSC_SET_RATE_PARENT) | |
257 | init.flags |= CLK_SET_RATE_PARENT; | |
258 | ||
259 | lpsc->dev = dev; | |
260 | lpsc->regmap = regmap; | |
261 | lpsc->hw.init = &init; | |
262 | lpsc->md = md; | |
263 | lpsc->pd = pd; | |
264 | lpsc->flags = flags; | |
265 | ||
043eaa70 DL |
266 | ret = clk_hw_register(dev, &lpsc->hw); |
267 | if (ret < 0) { | |
268 | kfree(lpsc); | |
c6ed4d73 | 269 | return ERR_PTR(ret); |
043eaa70 DL |
270 | } |
271 | ||
272 | /* for now, genpd is only registered when using device-tree */ | |
273 | if (!dev || !dev->of_node) | |
274 | return lpsc; | |
c6ed4d73 DL |
275 | |
276 | /* genpd attach needs a way to look up this clock */ | |
277 | ret = clk_hw_register_clkdev(&lpsc->hw, name, best_dev_name(dev)); | |
278 | ||
279 | lpsc->pm_domain.name = devm_kasprintf(dev, GFP_KERNEL, "%s: %s", | |
280 | best_dev_name(dev), name); | |
281 | lpsc->pm_domain.attach_dev = davinci_psc_genpd_attach_dev; | |
282 | lpsc->pm_domain.detach_dev = davinci_psc_genpd_detach_dev; | |
283 | lpsc->pm_domain.flags = GENPD_FLAG_PM_CLK; | |
284 | ||
285 | is_on = davinci_lpsc_clk_is_enabled(&lpsc->hw); | |
286 | pm_genpd_init(&lpsc->pm_domain, NULL, is_on); | |
287 | ||
288 | return lpsc; | |
289 | } | |
290 | ||
291 | static int davinci_lpsc_clk_reset(struct clk *clk, bool reset) | |
292 | { | |
293 | struct clk_hw *hw = __clk_get_hw(clk); | |
294 | struct davinci_lpsc_clk *lpsc = to_davinci_lpsc_clk(hw); | |
295 | u32 mdctl; | |
296 | ||
297 | if (IS_ERR_OR_NULL(lpsc)) | |
298 | return -EINVAL; | |
299 | ||
300 | mdctl = reset ? 0 : MDCTL_LRESET; | |
301 | regmap_write_bits(lpsc->regmap, MDCTL(lpsc->md), MDCTL_LRESET, mdctl); | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
c6ed4d73 DL |
306 | static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev, |
307 | unsigned long id) | |
308 | { | |
309 | struct davinci_psc_data *psc = to_davinci_psc_data(rcdev); | |
310 | struct clk *clk = psc->clk_data.clks[id]; | |
311 | ||
312 | return davinci_lpsc_clk_reset(clk, true); | |
313 | } | |
314 | ||
315 | static int davinci_psc_reset_deassert(struct reset_controller_dev *rcdev, | |
316 | unsigned long id) | |
317 | { | |
318 | struct davinci_psc_data *psc = to_davinci_psc_data(rcdev); | |
319 | struct clk *clk = psc->clk_data.clks[id]; | |
320 | ||
321 | return davinci_lpsc_clk_reset(clk, false); | |
322 | } | |
323 | ||
324 | static const struct reset_control_ops davinci_psc_reset_ops = { | |
325 | .assert = davinci_psc_reset_assert, | |
326 | .deassert = davinci_psc_reset_deassert, | |
327 | }; | |
328 | ||
329 | static int davinci_psc_reset_of_xlate(struct reset_controller_dev *rcdev, | |
330 | const struct of_phandle_args *reset_spec) | |
331 | { | |
332 | struct of_phandle_args clkspec = *reset_spec; /* discard const qualifier */ | |
333 | struct clk *clk; | |
334 | struct clk_hw *hw; | |
335 | struct davinci_lpsc_clk *lpsc; | |
336 | ||
337 | /* the clock node is the same as the reset node */ | |
338 | clk = of_clk_get_from_provider(&clkspec); | |
339 | if (IS_ERR(clk)) | |
340 | return PTR_ERR(clk); | |
341 | ||
342 | hw = __clk_get_hw(clk); | |
343 | lpsc = to_davinci_lpsc_clk(hw); | |
344 | clk_put(clk); | |
345 | ||
346 | /* not all modules support local reset */ | |
347 | if (!(lpsc->flags & LPSC_LOCAL_RESET)) | |
348 | return -EINVAL; | |
349 | ||
350 | return lpsc->md; | |
351 | } | |
352 | ||
353 | static const struct regmap_config davinci_psc_regmap_config = { | |
354 | .reg_bits = 32, | |
355 | .reg_stride = 4, | |
356 | .val_bits = 32, | |
357 | }; | |
358 | ||
359 | static struct davinci_psc_data * | |
360 | __davinci_psc_register_clocks(struct device *dev, | |
361 | const struct davinci_lpsc_clk_info *info, | |
362 | int num_clks, | |
363 | void __iomem *base) | |
364 | { | |
365 | struct davinci_psc_data *psc; | |
366 | struct clk **clks; | |
367 | struct generic_pm_domain **pm_domains; | |
368 | struct regmap *regmap; | |
369 | int i, ret; | |
370 | ||
043eaa70 | 371 | psc = kzalloc(sizeof(*psc), GFP_KERNEL); |
c6ed4d73 DL |
372 | if (!psc) |
373 | return ERR_PTR(-ENOMEM); | |
374 | ||
043eaa70 DL |
375 | clks = kmalloc_array(num_clks, sizeof(*clks), GFP_KERNEL); |
376 | if (!clks) { | |
377 | ret = -ENOMEM; | |
378 | goto err_free_psc; | |
379 | } | |
c6ed4d73 DL |
380 | |
381 | psc->clk_data.clks = clks; | |
382 | psc->clk_data.clk_num = num_clks; | |
383 | ||
384 | /* | |
385 | * init array with error so that of_clk_src_onecell_get() doesn't | |
386 | * return NULL for gaps in the sparse array | |
387 | */ | |
388 | for (i = 0; i < num_clks; i++) | |
389 | clks[i] = ERR_PTR(-ENOENT); | |
390 | ||
043eaa70 DL |
391 | pm_domains = kcalloc(num_clks, sizeof(*pm_domains), GFP_KERNEL); |
392 | if (!pm_domains) { | |
393 | ret = -ENOMEM; | |
394 | goto err_free_clks; | |
395 | } | |
c6ed4d73 DL |
396 | |
397 | psc->pm_data.domains = pm_domains; | |
398 | psc->pm_data.num_domains = num_clks; | |
399 | ||
043eaa70 DL |
400 | regmap = regmap_init_mmio(dev, base, &davinci_psc_regmap_config); |
401 | if (IS_ERR(regmap)) { | |
402 | ret = PTR_ERR(regmap); | |
403 | goto err_free_pm_domains; | |
404 | } | |
c6ed4d73 DL |
405 | |
406 | for (; info->name; info++) { | |
407 | struct davinci_lpsc_clk *lpsc; | |
408 | ||
409 | lpsc = davinci_lpsc_clk_register(dev, info->name, info->parent, | |
410 | regmap, info->md, info->pd, | |
411 | info->flags); | |
412 | if (IS_ERR(lpsc)) { | |
413 | dev_warn(dev, "Failed to register %s (%ld)\n", | |
414 | info->name, PTR_ERR(lpsc)); | |
415 | continue; | |
416 | } | |
417 | ||
418 | clks[info->md] = lpsc->hw.clk; | |
419 | pm_domains[info->md] = &lpsc->pm_domain; | |
420 | } | |
421 | ||
043eaa70 DL |
422 | /* |
423 | * for now, a reset controller is only registered when there is a device | |
424 | * to associate it with. | |
425 | */ | |
426 | if (!dev) | |
427 | return psc; | |
428 | ||
c6ed4d73 DL |
429 | psc->rcdev.ops = &davinci_psc_reset_ops; |
430 | psc->rcdev.owner = THIS_MODULE; | |
5ced1923 | 431 | psc->rcdev.dev = dev; |
c6ed4d73 DL |
432 | psc->rcdev.of_node = dev->of_node; |
433 | psc->rcdev.of_reset_n_cells = 1; | |
434 | psc->rcdev.of_xlate = davinci_psc_reset_of_xlate; | |
435 | psc->rcdev.nr_resets = num_clks; | |
436 | ||
437 | ret = devm_reset_controller_register(dev, &psc->rcdev); | |
438 | if (ret < 0) | |
439 | dev_warn(dev, "Failed to register reset controller (%d)\n", ret); | |
440 | ||
441 | return psc; | |
043eaa70 DL |
442 | |
443 | err_free_pm_domains: | |
444 | kfree(pm_domains); | |
445 | err_free_clks: | |
446 | kfree(clks); | |
447 | err_free_psc: | |
448 | kfree(psc); | |
449 | ||
450 | return ERR_PTR(ret); | |
c6ed4d73 DL |
451 | } |
452 | ||
453 | int davinci_psc_register_clocks(struct device *dev, | |
454 | const struct davinci_lpsc_clk_info *info, | |
455 | u8 num_clks, | |
456 | void __iomem *base) | |
457 | { | |
458 | struct davinci_psc_data *psc; | |
459 | ||
460 | psc = __davinci_psc_register_clocks(dev, info, num_clks, base); | |
461 | if (IS_ERR(psc)) | |
462 | return PTR_ERR(psc); | |
463 | ||
464 | for (; info->name; info++) { | |
465 | const struct davinci_lpsc_clkdev_info *cdevs = info->cdevs; | |
466 | struct clk *clk = psc->clk_data.clks[info->md]; | |
467 | ||
468 | if (!cdevs || IS_ERR_OR_NULL(clk)) | |
469 | continue; | |
470 | ||
471 | for (; cdevs->con_id || cdevs->dev_id; cdevs++) | |
472 | clk_register_clkdev(clk, cdevs->con_id, cdevs->dev_id); | |
473 | } | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
478 | int of_davinci_psc_clk_init(struct device *dev, | |
479 | const struct davinci_lpsc_clk_info *info, | |
480 | u8 num_clks, | |
481 | void __iomem *base) | |
482 | { | |
483 | struct device_node *node = dev->of_node; | |
484 | struct davinci_psc_data *psc; | |
485 | ||
486 | psc = __davinci_psc_register_clocks(dev, info, num_clks, base); | |
487 | if (IS_ERR(psc)) | |
488 | return PTR_ERR(psc); | |
489 | ||
490 | of_genpd_add_provider_onecell(node, &psc->pm_data); | |
491 | ||
492 | of_clk_add_provider(node, of_clk_src_onecell_get, &psc->clk_data); | |
493 | ||
494 | return 0; | |
495 | } | |
496 | ||
497 | static const struct of_device_id davinci_psc_of_match[] = { | |
4eff0beb | 498 | #ifdef CONFIG_ARCH_DAVINCI_DA850 |
a47d6040 DL |
499 | { .compatible = "ti,da850-psc0", .data = &of_da850_psc0_init_data }, |
500 | { .compatible = "ti,da850-psc1", .data = &of_da850_psc1_init_data }, | |
4eff0beb | 501 | #endif |
c6ed4d73 DL |
502 | { } |
503 | }; | |
504 | ||
505 | static const struct platform_device_id davinci_psc_id_table[] = { | |
4eff0beb | 506 | #ifdef CONFIG_ARCH_DAVINCI_DA830 |
c2952e27 DL |
507 | { .name = "da830-psc0", .driver_data = (kernel_ulong_t)&da830_psc0_init_data }, |
508 | { .name = "da830-psc1", .driver_data = (kernel_ulong_t)&da830_psc1_init_data }, | |
4eff0beb DL |
509 | #endif |
510 | #ifdef CONFIG_ARCH_DAVINCI_DA850 | |
a47d6040 DL |
511 | { .name = "da850-psc0", .driver_data = (kernel_ulong_t)&da850_psc0_init_data }, |
512 | { .name = "da850-psc1", .driver_data = (kernel_ulong_t)&da850_psc1_init_data }, | |
4eff0beb DL |
513 | #endif |
514 | #ifdef CONFIG_ARCH_DAVINCI_DM355 | |
b99bfca5 | 515 | { .name = "dm355-psc", .driver_data = (kernel_ulong_t)&dm355_psc_init_data }, |
4eff0beb DL |
516 | #endif |
517 | #ifdef CONFIG_ARCH_DAVINCI_DM365 | |
9ab1102c | 518 | { .name = "dm365-psc", .driver_data = (kernel_ulong_t)&dm365_psc_init_data }, |
4eff0beb DL |
519 | #endif |
520 | #ifdef CONFIG_ARCH_DAVINCI_DM644x | |
f41e5275 | 521 | { .name = "dm644x-psc", .driver_data = (kernel_ulong_t)&dm644x_psc_init_data }, |
4eff0beb DL |
522 | #endif |
523 | #ifdef CONFIG_ARCH_DAVINCI_DM646x | |
aad739f9 | 524 | { .name = "dm646x-psc", .driver_data = (kernel_ulong_t)&dm646x_psc_init_data }, |
4eff0beb | 525 | #endif |
c6ed4d73 DL |
526 | { } |
527 | }; | |
528 | ||
529 | static int davinci_psc_probe(struct platform_device *pdev) | |
530 | { | |
531 | struct device *dev = &pdev->dev; | |
532 | const struct of_device_id *of_id; | |
533 | const struct davinci_psc_init_data *init_data = NULL; | |
534 | struct resource *res; | |
535 | void __iomem *base; | |
536 | int ret; | |
537 | ||
538 | of_id = of_match_device(davinci_psc_of_match, dev); | |
539 | if (of_id) | |
540 | init_data = of_id->data; | |
541 | else if (pdev->id_entry) | |
542 | init_data = (void *)pdev->id_entry->driver_data; | |
543 | ||
544 | if (!init_data) { | |
545 | dev_err(dev, "unable to find driver init data\n"); | |
546 | return -EINVAL; | |
547 | } | |
548 | ||
549 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
550 | base = devm_ioremap_resource(dev, res); | |
fc3fcb4f | 551 | if (IS_ERR(base)) |
c6ed4d73 | 552 | return PTR_ERR(base); |
c6ed4d73 DL |
553 | |
554 | ret = devm_clk_bulk_get(dev, init_data->num_parent_clks, | |
555 | init_data->parent_clks); | |
556 | if (ret < 0) | |
557 | return ret; | |
558 | ||
559 | return init_data->psc_init(dev, base); | |
560 | } | |
561 | ||
562 | static struct platform_driver davinci_psc_driver = { | |
563 | .probe = davinci_psc_probe, | |
564 | .driver = { | |
565 | .name = "davinci-psc-clk", | |
566 | .of_match_table = davinci_psc_of_match, | |
567 | }, | |
568 | .id_table = davinci_psc_id_table, | |
569 | }; | |
570 | ||
571 | static int __init davinci_psc_driver_init(void) | |
572 | { | |
573 | return platform_driver_register(&davinci_psc_driver); | |
574 | } | |
575 | ||
576 | /* has to be postcore_initcall because davinci_gpio depend on PSC clocks */ | |
577 | postcore_initcall(davinci_psc_driver_init); |