blob: 8d57ab8d6ed86f51af2588c71167d9679338e6a2 [file] [log] [blame]
Linus Walleijef6eb322013-06-04 23:17:21 +02001/*
2 * Nomadik clock implementation
3 * Copyright (C) 2013 ST-Ericsson AB
4 * License terms: GNU General Public License (GPL) version 2
5 * Author: Linus Walleij <linus.walleij@linaro.org>
6 */
7
8#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
9
10#include <linux/bitops.h>
Stephen Boydaa1a7fc2015-06-19 15:00:46 -070011#include <linux/slab.h>
Linus Walleij4a31bd22012-01-11 13:52:34 +010012#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/clk-provider.h>
Linus Walleij6e2b07a2013-04-16 21:38:29 +020015#include <linux/of.h>
Linus Walleijef6eb322013-06-04 23:17:21 +020016#include <linux/of_address.h>
17#include <linux/debugfs.h>
18#include <linux/seq_file.h>
19#include <linux/spinlock.h>
20#include <linux/reboot.h>
Linus Walleij4a31bd22012-01-11 13:52:34 +010021
22/*
23 * The Nomadik clock tree is described in the STN8815A12 DB V4.2
24 * reference manual for the chip, page 94 ff.
Linus Walleijef6eb322013-06-04 23:17:21 +020025 * Clock IDs are in the STn8815 Reference Manual table 3, page 27.
Linus Walleij4a31bd22012-01-11 13:52:34 +010026 */
27
Linus Walleijef6eb322013-06-04 23:17:21 +020028#define SRC_CR 0x00U
Linus Walleijeb6b0362013-09-13 21:45:51 +020029#define SRC_CR_T0_ENSEL BIT(15)
30#define SRC_CR_T1_ENSEL BIT(17)
31#define SRC_CR_T2_ENSEL BIT(19)
32#define SRC_CR_T3_ENSEL BIT(21)
33#define SRC_CR_T4_ENSEL BIT(23)
34#define SRC_CR_T5_ENSEL BIT(25)
35#define SRC_CR_T6_ENSEL BIT(27)
36#define SRC_CR_T7_ENSEL BIT(29)
Linus Walleijef6eb322013-06-04 23:17:21 +020037#define SRC_XTALCR 0x0CU
38#define SRC_XTALCR_XTALTIMEN BIT(20)
39#define SRC_XTALCR_SXTALDIS BIT(19)
40#define SRC_XTALCR_MXTALSTAT BIT(2)
41#define SRC_XTALCR_MXTALEN BIT(1)
42#define SRC_XTALCR_MXTALOVER BIT(0)
43#define SRC_PLLCR 0x10U
44#define SRC_PLLCR_PLLTIMEN BIT(29)
45#define SRC_PLLCR_PLL2EN BIT(28)
46#define SRC_PLLCR_PLL1STAT BIT(2)
47#define SRC_PLLCR_PLL1EN BIT(1)
48#define SRC_PLLCR_PLL1OVER BIT(0)
49#define SRC_PLLFR 0x14U
50#define SRC_PCKEN0 0x24U
51#define SRC_PCKDIS0 0x28U
52#define SRC_PCKENSR0 0x2CU
53#define SRC_PCKSR0 0x30U
54#define SRC_PCKEN1 0x34U
55#define SRC_PCKDIS1 0x38U
56#define SRC_PCKENSR1 0x3CU
57#define SRC_PCKSR1 0x40U
58
59/* Lock protecting the SRC_CR register */
60static DEFINE_SPINLOCK(src_lock);
61/* Base address of the SRC */
62static void __iomem *src_base;
63
Sebastian Hesselbarthea25a902013-09-22 18:17:28 +020064static int nomadik_clk_reboot_handler(struct notifier_block *this,
65 unsigned long code,
66 void *unused)
67{
68 u32 val;
69
70 /* The main chrystal need to be enabled for reboot to work */
71 val = readl(src_base + SRC_XTALCR);
72 val &= ~SRC_XTALCR_MXTALOVER;
73 val |= SRC_XTALCR_MXTALEN;
74 pr_crit("force-enabling MXTALO\n");
75 writel(val, src_base + SRC_XTALCR);
76 return NOTIFY_OK;
77}
78
79static struct notifier_block nomadik_clk_reboot_notifier = {
80 .notifier_call = nomadik_clk_reboot_handler,
81};
82
83static const struct of_device_id nomadik_src_match[] __initconst = {
84 { .compatible = "stericsson,nomadik-src" },
85 { /* sentinel */ }
86};
87
Sebastian Hesselbarth54bf93c2013-10-07 19:53:13 +020088static void __init nomadik_src_init(void)
Sebastian Hesselbarthea25a902013-09-22 18:17:28 +020089{
90 struct device_node *np;
91 u32 val;
92
93 np = of_find_matching_node(NULL, nomadik_src_match);
94 if (!np) {
95 pr_crit("no matching node for SRC, aborting clock init\n");
96 return;
97 }
98 src_base = of_iomap(np, 0);
99 if (!src_base) {
100 pr_err("%s: must have src parent node with REGS (%s)\n",
101 __func__, np->name);
102 return;
103 }
104
105 /* Set all timers to use the 2.4 MHz TIMCLK */
106 val = readl(src_base + SRC_CR);
107 val |= SRC_CR_T0_ENSEL;
108 val |= SRC_CR_T1_ENSEL;
109 val |= SRC_CR_T2_ENSEL;
110 val |= SRC_CR_T3_ENSEL;
111 val |= SRC_CR_T4_ENSEL;
112 val |= SRC_CR_T5_ENSEL;
113 val |= SRC_CR_T6_ENSEL;
114 val |= SRC_CR_T7_ENSEL;
115 writel(val, src_base + SRC_CR);
116
117 val = readl(src_base + SRC_XTALCR);
118 pr_info("SXTALO is %s\n",
119 (val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
120 pr_info("MXTAL is %s\n",
121 (val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled");
122 if (of_property_read_bool(np, "disable-sxtalo")) {
123 /* The machine uses an external oscillator circuit */
124 val |= SRC_XTALCR_SXTALDIS;
125 pr_info("disabling SXTALO\n");
126 }
127 if (of_property_read_bool(np, "disable-mxtalo")) {
128 /* Disable this too: also run by external oscillator */
129 val |= SRC_XTALCR_MXTALOVER;
130 val &= ~SRC_XTALCR_MXTALEN;
131 pr_info("disabling MXTALO\n");
132 }
133 writel(val, src_base + SRC_XTALCR);
134 register_reboot_notifier(&nomadik_clk_reboot_notifier);
135}
136
Linus Walleijef6eb322013-06-04 23:17:21 +0200137/**
138 * struct clk_pll1 - Nomadik PLL1 clock
139 * @hw: corresponding clock hardware entry
140 * @id: PLL instance: 1 or 2
141 */
142struct clk_pll {
143 struct clk_hw hw;
144 int id;
145};
146
147/**
148 * struct clk_src - Nomadik src clock
149 * @hw: corresponding clock hardware entry
150 * @id: the clock ID
151 * @group1: true if the clock is in group1, else it is in group0
152 * @clkbit: bit 0...31 corresponding to the clock in each clock register
153 */
154struct clk_src {
155 struct clk_hw hw;
156 int id;
157 bool group1;
158 u32 clkbit;
159};
160
161#define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
162#define to_src(_hw) container_of(_hw, struct clk_src, hw)
163
164static int pll_clk_enable(struct clk_hw *hw)
165{
166 struct clk_pll *pll = to_pll(hw);
167 u32 val;
168
169 spin_lock(&src_lock);
170 val = readl(src_base + SRC_PLLCR);
171 if (pll->id == 1) {
172 if (val & SRC_PLLCR_PLL1OVER) {
173 val |= SRC_PLLCR_PLL1EN;
174 writel(val, src_base + SRC_PLLCR);
175 }
176 } else if (pll->id == 2) {
177 val |= SRC_PLLCR_PLL2EN;
178 writel(val, src_base + SRC_PLLCR);
179 }
180 spin_unlock(&src_lock);
181 return 0;
182}
183
184static void pll_clk_disable(struct clk_hw *hw)
185{
186 struct clk_pll *pll = to_pll(hw);
187 u32 val;
188
189 spin_lock(&src_lock);
190 val = readl(src_base + SRC_PLLCR);
191 if (pll->id == 1) {
192 if (val & SRC_PLLCR_PLL1OVER) {
193 val &= ~SRC_PLLCR_PLL1EN;
194 writel(val, src_base + SRC_PLLCR);
195 }
196 } else if (pll->id == 2) {
197 val &= ~SRC_PLLCR_PLL2EN;
198 writel(val, src_base + SRC_PLLCR);
199 }
200 spin_unlock(&src_lock);
201}
202
203static int pll_clk_is_enabled(struct clk_hw *hw)
204{
205 struct clk_pll *pll = to_pll(hw);
206 u32 val;
207
208 val = readl(src_base + SRC_PLLCR);
209 if (pll->id == 1) {
210 if (val & SRC_PLLCR_PLL1OVER)
211 return !!(val & SRC_PLLCR_PLL1EN);
212 } else if (pll->id == 2) {
213 return !!(val & SRC_PLLCR_PLL2EN);
214 }
215 return 1;
216}
217
218static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
219 unsigned long parent_rate)
220{
221 struct clk_pll *pll = to_pll(hw);
222 u32 val;
223
224 val = readl(src_base + SRC_PLLFR);
225
226 if (pll->id == 1) {
227 u8 mul;
228 u8 div;
229
230 mul = (val >> 8) & 0x3FU;
231 mul += 2;
232 div = val & 0x07U;
233 return (parent_rate * mul) >> div;
234 }
235
236 if (pll->id == 2) {
237 u8 mul;
238
239 mul = (val >> 24) & 0x3FU;
240 mul += 2;
241 return (parent_rate * mul);
242 }
243
244 /* Unknown PLL */
245 return 0;
246}
247
248
249static const struct clk_ops pll_clk_ops = {
250 .enable = pll_clk_enable,
251 .disable = pll_clk_disable,
252 .is_enabled = pll_clk_is_enabled,
253 .recalc_rate = pll_clk_recalc_rate,
254};
255
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700256static struct clk_hw * __init
Linus Walleijef6eb322013-06-04 23:17:21 +0200257pll_clk_register(struct device *dev, const char *name,
258 const char *parent_name, u32 id)
259{
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700260 int ret;
Linus Walleijef6eb322013-06-04 23:17:21 +0200261 struct clk_pll *pll;
262 struct clk_init_data init;
263
264 if (id != 1 && id != 2) {
265 pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
266 return ERR_PTR(-EINVAL);
267 }
268
269 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
270 if (!pll) {
271 pr_err("%s: could not allocate PLL clk\n", __func__);
272 return ERR_PTR(-ENOMEM);
273 }
274
275 init.name = name;
276 init.ops = &pll_clk_ops;
277 init.parent_names = (parent_name ? &parent_name : NULL);
278 init.num_parents = (parent_name ? 1 : 0);
279 pll->hw.init = &init;
280 pll->id = id;
281
282 pr_debug("register PLL1 clock \"%s\"\n", name);
283
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700284 ret = clk_hw_register(dev, &pll->hw);
285 if (ret) {
Linus Walleijef6eb322013-06-04 23:17:21 +0200286 kfree(pll);
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700287 return ERR_PTR(ret);
288 }
Linus Walleijef6eb322013-06-04 23:17:21 +0200289
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700290 return &pll->hw;
Linus Walleijef6eb322013-06-04 23:17:21 +0200291}
292
293/*
294 * The Nomadik SRC clocks are gated, but not in the sense that
295 * you read-modify-write a register. Instead there are separate
296 * clock enable and clock disable registers. Writing a '1' bit in
297 * the enable register for a certain clock ungates that clock without
298 * affecting the other clocks. The disable register works the opposite
299 * way.
300 */
301
302static int src_clk_enable(struct clk_hw *hw)
303{
304 struct clk_src *sclk = to_src(hw);
305 u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
306 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
307
308 writel(sclk->clkbit, src_base + enreg);
309 /* spin until enabled */
310 while (!(readl(src_base + sreg) & sclk->clkbit))
311 cpu_relax();
312 return 0;
313}
314
315static void src_clk_disable(struct clk_hw *hw)
316{
317 struct clk_src *sclk = to_src(hw);
318 u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
319 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
320
321 writel(sclk->clkbit, src_base + disreg);
322 /* spin until disabled */
323 while (readl(src_base + sreg) & sclk->clkbit)
324 cpu_relax();
325}
326
327static int src_clk_is_enabled(struct clk_hw *hw)
328{
329 struct clk_src *sclk = to_src(hw);
330 u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
331 u32 val = readl(src_base + sreg);
332
333 return !!(val & sclk->clkbit);
334}
335
336static unsigned long
337src_clk_recalc_rate(struct clk_hw *hw,
338 unsigned long parent_rate)
339{
340 return parent_rate;
341}
342
343static const struct clk_ops src_clk_ops = {
344 .enable = src_clk_enable,
345 .disable = src_clk_disable,
346 .is_enabled = src_clk_is_enabled,
347 .recalc_rate = src_clk_recalc_rate,
348};
349
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700350static struct clk_hw * __init
Linus Walleijef6eb322013-06-04 23:17:21 +0200351src_clk_register(struct device *dev, const char *name,
352 const char *parent_name, u8 id)
353{
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700354 int ret;
Linus Walleijef6eb322013-06-04 23:17:21 +0200355 struct clk_src *sclk;
356 struct clk_init_data init;
357
358 sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
359 if (!sclk) {
360 pr_err("could not allocate SRC clock %s\n",
361 name);
362 return ERR_PTR(-ENOMEM);
363 }
364 init.name = name;
365 init.ops = &src_clk_ops;
366 /* Do not force-disable the static SDRAM controller */
367 if (id == 2)
368 init.flags = CLK_IGNORE_UNUSED;
369 else
370 init.flags = 0;
371 init.parent_names = (parent_name ? &parent_name : NULL);
372 init.num_parents = (parent_name ? 1 : 0);
373 sclk->hw.init = &init;
374 sclk->id = id;
375 sclk->group1 = (id > 31);
376 sclk->clkbit = BIT(id & 0x1f);
377
378 pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
379 name, id, sclk->group1, sclk->clkbit);
380
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700381 ret = clk_hw_register(dev, &sclk->hw);
382 if (ret) {
Linus Walleijef6eb322013-06-04 23:17:21 +0200383 kfree(sclk);
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700384 return ERR_PTR(ret);
385 }
Linus Walleijef6eb322013-06-04 23:17:21 +0200386
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700387 return &sclk->hw;
Linus Walleijef6eb322013-06-04 23:17:21 +0200388}
389
390#ifdef CONFIG_DEBUG_FS
391
392static u32 src_pcksr0_boot;
393static u32 src_pcksr1_boot;
394
395static const char * const src_clk_names[] = {
396 "HCLKDMA0 ",
397 "HCLKSMC ",
398 "HCLKSDRAM ",
399 "HCLKDMA1 ",
400 "HCLKCLCD ",
401 "PCLKIRDA ",
402 "PCLKSSP ",
403 "PCLKUART0 ",
404 "PCLKSDI ",
405 "PCLKI2C0 ",
406 "PCLKI2C1 ",
407 "PCLKUART1 ",
408 "PCLMSP0 ",
409 "HCLKUSB ",
410 "HCLKDIF ",
411 "HCLKSAA ",
412 "HCLKSVA ",
413 "PCLKHSI ",
414 "PCLKXTI ",
415 "PCLKUART2 ",
416 "PCLKMSP1 ",
417 "PCLKMSP2 ",
418 "PCLKOWM ",
419 "HCLKHPI ",
420 "PCLKSKE ",
421 "PCLKHSEM ",
422 "HCLK3D ",
423 "HCLKHASH ",
424 "HCLKCRYP ",
425 "PCLKMSHC ",
426 "HCLKUSBM ",
427 "HCLKRNG ",
428 "RESERVED ",
429 "RESERVED ",
430 "RESERVED ",
431 "RESERVED ",
432 "CLDCLK ",
433 "IRDACLK ",
434 "SSPICLK ",
435 "UART0CLK ",
436 "SDICLK ",
437 "I2C0CLK ",
438 "I2C1CLK ",
439 "UART1CLK ",
440 "MSPCLK0 ",
441 "USBCLK ",
442 "DIFCLK ",
443 "IPI2CCLK ",
444 "IPBMCCLK ",
445 "HSICLKRX ",
446 "HSICLKTX ",
447 "UART2CLK ",
448 "MSPCLK1 ",
449 "MSPCLK2 ",
450 "OWMCLK ",
451 "RESERVED ",
452 "SKECLK ",
453 "RESERVED ",
454 "3DCLK ",
455 "PCLKMSP3 ",
456 "MSPCLK3 ",
457 "MSHCCLK ",
458 "USBMCLK ",
459 "RNGCCLK ",
460};
461
462static int nomadik_src_clk_show(struct seq_file *s, void *what)
463{
464 int i;
465 u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
466 u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
467 u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
468 u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
469
Markus Elfringadd31512017-04-20 09:45:04 +0200470 seq_puts(s, "Clock: Boot: Now: Request: ASKED:\n");
Linus Walleijef6eb322013-06-04 23:17:21 +0200471 for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
472 u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
473 u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
474 u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
475 u32 mask = BIT(i & 0x1f);
476
477 seq_printf(s, "%s %s %s %s\n",
478 src_clk_names[i],
479 (pcksrb & mask) ? "on " : "off",
480 (pcksr & mask) ? "on " : "off",
481 (pckreq & mask) ? "on " : "off");
482 }
483 return 0;
484}
485
486static int nomadik_src_clk_open(struct inode *inode, struct file *file)
487{
488 return single_open(file, nomadik_src_clk_show, NULL);
489}
490
491static const struct file_operations nomadik_src_clk_debugfs_ops = {
492 .open = nomadik_src_clk_open,
493 .read = seq_read,
494 .llseek = seq_lseek,
495 .release = single_release,
496};
497
498static int __init nomadik_src_clk_init_debugfs(void)
499{
Linus Walleijec6deea2014-01-21 09:06:21 +0100500 /* Vital for multiplatform */
501 if (!src_base)
502 return -ENODEV;
Linus Walleijef6eb322013-06-04 23:17:21 +0200503 src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
504 src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
505 debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
506 NULL, NULL, &nomadik_src_clk_debugfs_ops);
507 return 0;
508}
Paul Gortmaker791ed0b2015-05-01 20:05:51 -0400509device_initcall(nomadik_src_clk_init_debugfs);
Linus Walleijef6eb322013-06-04 23:17:21 +0200510
511#endif
512
513static void __init of_nomadik_pll_setup(struct device_node *np)
514{
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700515 struct clk_hw *hw;
Linus Walleijef6eb322013-06-04 23:17:21 +0200516 const char *clk_name = np->name;
517 const char *parent_name;
518 u32 pll_id;
519
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200520 if (!src_base)
521 nomadik_src_init();
522
Linus Walleijef6eb322013-06-04 23:17:21 +0200523 if (of_property_read_u32(np, "pll-id", &pll_id)) {
524 pr_err("%s: PLL \"%s\" missing pll-id property\n",
525 __func__, clk_name);
526 return;
527 }
528 parent_name = of_clk_get_parent_name(np, 0);
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700529 hw = pll_clk_register(NULL, clk_name, parent_name, pll_id);
530 if (!IS_ERR(hw))
531 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
Linus Walleijef6eb322013-06-04 23:17:21 +0200532}
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200533CLK_OF_DECLARE(nomadik_pll_clk,
534 "st,nomadik-pll-clock", of_nomadik_pll_setup);
Linus Walleijef6eb322013-06-04 23:17:21 +0200535
536static void __init of_nomadik_hclk_setup(struct device_node *np)
537{
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700538 struct clk_hw *hw;
Linus Walleijef6eb322013-06-04 23:17:21 +0200539 const char *clk_name = np->name;
540 const char *parent_name;
541
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200542 if (!src_base)
543 nomadik_src_init();
544
Linus Walleijef6eb322013-06-04 23:17:21 +0200545 parent_name = of_clk_get_parent_name(np, 0);
546 /*
547 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
548 */
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700549 hw = clk_hw_register_divider(NULL, clk_name, parent_name,
Linus Walleijef6eb322013-06-04 23:17:21 +0200550 0, src_base + SRC_CR,
551 13, 2,
552 CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
553 &src_lock);
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700554 if (!IS_ERR(hw))
555 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
Linus Walleijef6eb322013-06-04 23:17:21 +0200556}
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200557CLK_OF_DECLARE(nomadik_hclk_clk,
558 "st,nomadik-hclk-clock", of_nomadik_hclk_setup);
Linus Walleijef6eb322013-06-04 23:17:21 +0200559
560static void __init of_nomadik_src_clk_setup(struct device_node *np)
561{
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700562 struct clk_hw *hw;
Linus Walleijef6eb322013-06-04 23:17:21 +0200563 const char *clk_name = np->name;
564 const char *parent_name;
565 u32 clk_id;
566
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200567 if (!src_base)
568 nomadik_src_init();
569
Linus Walleijef6eb322013-06-04 23:17:21 +0200570 if (of_property_read_u32(np, "clock-id", &clk_id)) {
571 pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
572 __func__, clk_name);
573 return;
574 }
575 parent_name = of_clk_get_parent_name(np, 0);
Stephen Boyd7b38d1b2016-06-01 16:15:19 -0700576 hw = src_clk_register(NULL, clk_name, parent_name, clk_id);
577 if (!IS_ERR(hw))
578 of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
Linus Walleijef6eb322013-06-04 23:17:21 +0200579}
Sebastian Hesselbarth74227e62013-09-17 00:32:34 +0200580CLK_OF_DECLARE(nomadik_src_clk,
581 "st,nomadik-src-clock", of_nomadik_src_clk_setup);