xref: /linux/drivers/clk/clk-nomadik.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ef6eb322SLinus Walleij /*
3ef6eb322SLinus Walleij  * Nomadik clock implementation
4ef6eb322SLinus Walleij  * Copyright (C) 2013 ST-Ericsson AB
5ef6eb322SLinus Walleij  * Author: Linus Walleij <linus.walleij@linaro.org>
6ef6eb322SLinus Walleij  */
7ef6eb322SLinus Walleij 
8ef6eb322SLinus Walleij #define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
9ef6eb322SLinus Walleij 
10ef6eb322SLinus Walleij #include <linux/bitops.h>
11aa1a7fc4SStephen Boyd #include <linux/slab.h>
124a31bd28SLinus Walleij #include <linux/err.h>
134a31bd28SLinus Walleij #include <linux/io.h>
144a31bd28SLinus Walleij #include <linux/clk-provider.h>
156e2b07a1SLinus Walleij #include <linux/of.h>
16ef6eb322SLinus Walleij #include <linux/of_address.h>
17ef6eb322SLinus Walleij #include <linux/debugfs.h>
18ef6eb322SLinus Walleij #include <linux/seq_file.h>
19ef6eb322SLinus Walleij #include <linux/spinlock.h>
20ef6eb322SLinus Walleij #include <linux/reboot.h>
214a31bd28SLinus Walleij 
224a31bd28SLinus Walleij /*
234a31bd28SLinus Walleij  * The Nomadik clock tree is described in the STN8815A12 DB V4.2
244a31bd28SLinus Walleij  * reference manual for the chip, page 94 ff.
25ef6eb322SLinus Walleij  * Clock IDs are in the STn8815 Reference Manual table 3, page 27.
264a31bd28SLinus Walleij  */
274a31bd28SLinus Walleij 
28ef6eb322SLinus Walleij #define SRC_CR			0x00U
29eb6b036dSLinus Walleij #define SRC_CR_T0_ENSEL		BIT(15)
30eb6b036dSLinus Walleij #define SRC_CR_T1_ENSEL		BIT(17)
31eb6b036dSLinus Walleij #define SRC_CR_T2_ENSEL		BIT(19)
32eb6b036dSLinus Walleij #define SRC_CR_T3_ENSEL		BIT(21)
33eb6b036dSLinus Walleij #define SRC_CR_T4_ENSEL		BIT(23)
34eb6b036dSLinus Walleij #define SRC_CR_T5_ENSEL		BIT(25)
35eb6b036dSLinus Walleij #define SRC_CR_T6_ENSEL		BIT(27)
36eb6b036dSLinus Walleij #define SRC_CR_T7_ENSEL		BIT(29)
37ef6eb322SLinus Walleij #define SRC_XTALCR		0x0CU
38ef6eb322SLinus Walleij #define SRC_XTALCR_XTALTIMEN	BIT(20)
39ef6eb322SLinus Walleij #define SRC_XTALCR_SXTALDIS	BIT(19)
40ef6eb322SLinus Walleij #define SRC_XTALCR_MXTALSTAT	BIT(2)
41ef6eb322SLinus Walleij #define SRC_XTALCR_MXTALEN	BIT(1)
42ef6eb322SLinus Walleij #define SRC_XTALCR_MXTALOVER	BIT(0)
43ef6eb322SLinus Walleij #define SRC_PLLCR		0x10U
44ef6eb322SLinus Walleij #define SRC_PLLCR_PLLTIMEN	BIT(29)
45ef6eb322SLinus Walleij #define SRC_PLLCR_PLL2EN	BIT(28)
46ef6eb322SLinus Walleij #define SRC_PLLCR_PLL1STAT	BIT(2)
47ef6eb322SLinus Walleij #define SRC_PLLCR_PLL1EN	BIT(1)
48ef6eb322SLinus Walleij #define SRC_PLLCR_PLL1OVER	BIT(0)
49ef6eb322SLinus Walleij #define SRC_PLLFR		0x14U
50ef6eb322SLinus Walleij #define SRC_PCKEN0		0x24U
51ef6eb322SLinus Walleij #define SRC_PCKDIS0		0x28U
52ef6eb322SLinus Walleij #define SRC_PCKENSR0		0x2CU
53ef6eb322SLinus Walleij #define SRC_PCKSR0		0x30U
54ef6eb322SLinus Walleij #define SRC_PCKEN1		0x34U
55ef6eb322SLinus Walleij #define SRC_PCKDIS1		0x38U
56ef6eb322SLinus Walleij #define SRC_PCKENSR1		0x3CU
57ef6eb322SLinus Walleij #define SRC_PCKSR1		0x40U
58ef6eb322SLinus Walleij 
59ef6eb322SLinus Walleij /* Lock protecting the SRC_CR register */
60ef6eb322SLinus Walleij static DEFINE_SPINLOCK(src_lock);
61ef6eb322SLinus Walleij /* Base address of the SRC */
62ef6eb322SLinus Walleij static void __iomem *src_base;
63ef6eb322SLinus Walleij 
nomadik_clk_reboot_handler(struct notifier_block * this,unsigned long code,void * unused)64ea25a900SSebastian Hesselbarth static int nomadik_clk_reboot_handler(struct notifier_block *this,
65ea25a900SSebastian Hesselbarth 				unsigned long code,
66ea25a900SSebastian Hesselbarth 				void *unused)
67ea25a900SSebastian Hesselbarth {
68ea25a900SSebastian Hesselbarth 	u32 val;
69ea25a900SSebastian Hesselbarth 
70ea25a900SSebastian Hesselbarth 	/* The main chrystal need to be enabled for reboot to work */
71ea25a900SSebastian Hesselbarth 	val = readl(src_base + SRC_XTALCR);
72ea25a900SSebastian Hesselbarth 	val &= ~SRC_XTALCR_MXTALOVER;
73ea25a900SSebastian Hesselbarth 	val |= SRC_XTALCR_MXTALEN;
74ea25a900SSebastian Hesselbarth 	pr_crit("force-enabling MXTALO\n");
75ea25a900SSebastian Hesselbarth 	writel(val, src_base + SRC_XTALCR);
76ea25a900SSebastian Hesselbarth 	return NOTIFY_OK;
77ea25a900SSebastian Hesselbarth }
78ea25a900SSebastian Hesselbarth 
79ea25a900SSebastian Hesselbarth static struct notifier_block nomadik_clk_reboot_notifier = {
80ea25a900SSebastian Hesselbarth 	.notifier_call = nomadik_clk_reboot_handler,
81ea25a900SSebastian Hesselbarth };
82ea25a900SSebastian Hesselbarth 
83ea25a900SSebastian Hesselbarth static const struct of_device_id nomadik_src_match[] __initconst = {
84ea25a900SSebastian Hesselbarth 	{ .compatible = "stericsson,nomadik-src" },
85ea25a900SSebastian Hesselbarth 	{ /* sentinel */ }
86ea25a900SSebastian Hesselbarth };
87ea25a900SSebastian Hesselbarth 
nomadik_src_init(void)8854bf93c4SSebastian Hesselbarth static void __init nomadik_src_init(void)
89ea25a900SSebastian Hesselbarth {
90ea25a900SSebastian Hesselbarth 	struct device_node *np;
91ea25a900SSebastian Hesselbarth 	u32 val;
92ea25a900SSebastian Hesselbarth 
93ea25a900SSebastian Hesselbarth 	np = of_find_matching_node(NULL, nomadik_src_match);
94ea25a900SSebastian Hesselbarth 	if (!np) {
95ea25a900SSebastian Hesselbarth 		pr_crit("no matching node for SRC, aborting clock init\n");
96ea25a900SSebastian Hesselbarth 		return;
97ea25a900SSebastian Hesselbarth 	}
98ea25a900SSebastian Hesselbarth 	src_base = of_iomap(np, 0);
99ea25a900SSebastian Hesselbarth 	if (!src_base) {
100e665f029SRob Herring 		pr_err("%s: must have src parent node with REGS (%pOFn)\n",
101e665f029SRob Herring 		       __func__, np);
10228a0b098SLiang He 		goto out_put;
103ea25a900SSebastian Hesselbarth 	}
104ea25a900SSebastian Hesselbarth 
105ea25a900SSebastian Hesselbarth 	/* Set all timers to use the 2.4 MHz TIMCLK */
106ea25a900SSebastian Hesselbarth 	val = readl(src_base + SRC_CR);
107ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T0_ENSEL;
108ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T1_ENSEL;
109ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T2_ENSEL;
110ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T3_ENSEL;
111ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T4_ENSEL;
112ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T5_ENSEL;
113ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T6_ENSEL;
114ea25a900SSebastian Hesselbarth 	val |= SRC_CR_T7_ENSEL;
115ea25a900SSebastian Hesselbarth 	writel(val, src_base + SRC_CR);
116ea25a900SSebastian Hesselbarth 
117ea25a900SSebastian Hesselbarth 	val = readl(src_base + SRC_XTALCR);
118ea25a900SSebastian Hesselbarth 	pr_info("SXTALO is %s\n",
119ea25a900SSebastian Hesselbarth 		(val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
120ea25a900SSebastian Hesselbarth 	pr_info("MXTAL is %s\n",
121ea25a900SSebastian Hesselbarth 		(val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled");
122ea25a900SSebastian Hesselbarth 	if (of_property_read_bool(np, "disable-sxtalo")) {
123ea25a900SSebastian Hesselbarth 		/* The machine uses an external oscillator circuit */
124ea25a900SSebastian Hesselbarth 		val |= SRC_XTALCR_SXTALDIS;
125ea25a900SSebastian Hesselbarth 		pr_info("disabling SXTALO\n");
126ea25a900SSebastian Hesselbarth 	}
127ea25a900SSebastian Hesselbarth 	if (of_property_read_bool(np, "disable-mxtalo")) {
128ea25a900SSebastian Hesselbarth 		/* Disable this too: also run by external oscillator */
129ea25a900SSebastian Hesselbarth 		val |= SRC_XTALCR_MXTALOVER;
130ea25a900SSebastian Hesselbarth 		val &= ~SRC_XTALCR_MXTALEN;
131ea25a900SSebastian Hesselbarth 		pr_info("disabling MXTALO\n");
132ea25a900SSebastian Hesselbarth 	}
133ea25a900SSebastian Hesselbarth 	writel(val, src_base + SRC_XTALCR);
134ea25a900SSebastian Hesselbarth 	register_reboot_notifier(&nomadik_clk_reboot_notifier);
13528a0b098SLiang He 
13628a0b098SLiang He out_put:
13728a0b098SLiang He 	of_node_put(np);
138ea25a900SSebastian Hesselbarth }
139ea25a900SSebastian Hesselbarth 
140ef6eb322SLinus Walleij /**
141*5e57aaa8SRandy Dunlap  * struct clk_pll - Nomadik PLL clock
142ef6eb322SLinus Walleij  * @hw: corresponding clock hardware entry
143ef6eb322SLinus Walleij  * @id: PLL instance: 1 or 2
144ef6eb322SLinus Walleij  */
145ef6eb322SLinus Walleij struct clk_pll {
146ef6eb322SLinus Walleij 	struct clk_hw hw;
147ef6eb322SLinus Walleij 	int id;
148ef6eb322SLinus Walleij };
149ef6eb322SLinus Walleij 
150ef6eb322SLinus Walleij /**
151ef6eb322SLinus Walleij  * struct clk_src - Nomadik src clock
152ef6eb322SLinus Walleij  * @hw: corresponding clock hardware entry
153ef6eb322SLinus Walleij  * @id: the clock ID
154ef6eb322SLinus Walleij  * @group1: true if the clock is in group1, else it is in group0
155ef6eb322SLinus Walleij  * @clkbit: bit 0...31 corresponding to the clock in each clock register
156ef6eb322SLinus Walleij  */
157ef6eb322SLinus Walleij struct clk_src {
158ef6eb322SLinus Walleij 	struct clk_hw hw;
159ef6eb322SLinus Walleij 	int id;
160ef6eb322SLinus Walleij 	bool group1;
161ef6eb322SLinus Walleij 	u32 clkbit;
162ef6eb322SLinus Walleij };
163ef6eb322SLinus Walleij 
164ef6eb322SLinus Walleij #define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
165ef6eb322SLinus Walleij #define to_src(_hw) container_of(_hw, struct clk_src, hw)
166ef6eb322SLinus Walleij 
pll_clk_enable(struct clk_hw * hw)167ef6eb322SLinus Walleij static int pll_clk_enable(struct clk_hw *hw)
168ef6eb322SLinus Walleij {
169ef6eb322SLinus Walleij 	struct clk_pll *pll = to_pll(hw);
170ef6eb322SLinus Walleij 	u32 val;
171ef6eb322SLinus Walleij 
172ef6eb322SLinus Walleij 	spin_lock(&src_lock);
173ef6eb322SLinus Walleij 	val = readl(src_base + SRC_PLLCR);
174ef6eb322SLinus Walleij 	if (pll->id == 1) {
175ef6eb322SLinus Walleij 		if (val & SRC_PLLCR_PLL1OVER) {
176ef6eb322SLinus Walleij 			val |= SRC_PLLCR_PLL1EN;
177ef6eb322SLinus Walleij 			writel(val, src_base + SRC_PLLCR);
178ef6eb322SLinus Walleij 		}
179ef6eb322SLinus Walleij 	} else if (pll->id == 2) {
180ef6eb322SLinus Walleij 		val |= SRC_PLLCR_PLL2EN;
181ef6eb322SLinus Walleij 		writel(val, src_base + SRC_PLLCR);
182ef6eb322SLinus Walleij 	}
183ef6eb322SLinus Walleij 	spin_unlock(&src_lock);
184ef6eb322SLinus Walleij 	return 0;
185ef6eb322SLinus Walleij }
186ef6eb322SLinus Walleij 
pll_clk_disable(struct clk_hw * hw)187ef6eb322SLinus Walleij static void pll_clk_disable(struct clk_hw *hw)
188ef6eb322SLinus Walleij {
189ef6eb322SLinus Walleij 	struct clk_pll *pll = to_pll(hw);
190ef6eb322SLinus Walleij 	u32 val;
191ef6eb322SLinus Walleij 
192ef6eb322SLinus Walleij 	spin_lock(&src_lock);
193ef6eb322SLinus Walleij 	val = readl(src_base + SRC_PLLCR);
194ef6eb322SLinus Walleij 	if (pll->id == 1) {
195ef6eb322SLinus Walleij 		if (val & SRC_PLLCR_PLL1OVER) {
196ef6eb322SLinus Walleij 			val &= ~SRC_PLLCR_PLL1EN;
197ef6eb322SLinus Walleij 			writel(val, src_base + SRC_PLLCR);
198ef6eb322SLinus Walleij 		}
199ef6eb322SLinus Walleij 	} else if (pll->id == 2) {
200ef6eb322SLinus Walleij 		val &= ~SRC_PLLCR_PLL2EN;
201ef6eb322SLinus Walleij 		writel(val, src_base + SRC_PLLCR);
202ef6eb322SLinus Walleij 	}
203ef6eb322SLinus Walleij 	spin_unlock(&src_lock);
204ef6eb322SLinus Walleij }
205ef6eb322SLinus Walleij 
pll_clk_is_enabled(struct clk_hw * hw)206ef6eb322SLinus Walleij static int pll_clk_is_enabled(struct clk_hw *hw)
207ef6eb322SLinus Walleij {
208ef6eb322SLinus Walleij 	struct clk_pll *pll = to_pll(hw);
209ef6eb322SLinus Walleij 	u32 val;
210ef6eb322SLinus Walleij 
211ef6eb322SLinus Walleij 	val = readl(src_base + SRC_PLLCR);
212ef6eb322SLinus Walleij 	if (pll->id == 1) {
213ef6eb322SLinus Walleij 		if (val & SRC_PLLCR_PLL1OVER)
214ef6eb322SLinus Walleij 			return !!(val & SRC_PLLCR_PLL1EN);
215ef6eb322SLinus Walleij 	} else if (pll->id == 2) {
216ef6eb322SLinus Walleij 		return !!(val & SRC_PLLCR_PLL2EN);
217ef6eb322SLinus Walleij 	}
218ef6eb322SLinus Walleij 	return 1;
219ef6eb322SLinus Walleij }
220ef6eb322SLinus Walleij 
pll_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)221ef6eb322SLinus Walleij static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
222ef6eb322SLinus Walleij 					  unsigned long parent_rate)
223ef6eb322SLinus Walleij {
224ef6eb322SLinus Walleij 	struct clk_pll *pll = to_pll(hw);
225ef6eb322SLinus Walleij 	u32 val;
226ef6eb322SLinus Walleij 
227ef6eb322SLinus Walleij 	val = readl(src_base + SRC_PLLFR);
228ef6eb322SLinus Walleij 
229ef6eb322SLinus Walleij 	if (pll->id == 1) {
230ef6eb322SLinus Walleij 		u8 mul;
231ef6eb322SLinus Walleij 		u8 div;
232ef6eb322SLinus Walleij 
233ef6eb322SLinus Walleij 		mul = (val >> 8) & 0x3FU;
234ef6eb322SLinus Walleij 		mul += 2;
235ef6eb322SLinus Walleij 		div = val & 0x07U;
236ef6eb322SLinus Walleij 		return (parent_rate * mul) >> div;
237ef6eb322SLinus Walleij 	}
238ef6eb322SLinus Walleij 
239ef6eb322SLinus Walleij 	if (pll->id == 2) {
240ef6eb322SLinus Walleij 		u8 mul;
241ef6eb322SLinus Walleij 
242ef6eb322SLinus Walleij 		mul = (val >> 24) & 0x3FU;
243ef6eb322SLinus Walleij 		mul += 2;
244ef6eb322SLinus Walleij 		return (parent_rate * mul);
245ef6eb322SLinus Walleij 	}
246ef6eb322SLinus Walleij 
247ef6eb322SLinus Walleij 	/* Unknown PLL */
248ef6eb322SLinus Walleij 	return 0;
249ef6eb322SLinus Walleij }
250ef6eb322SLinus Walleij 
251ef6eb322SLinus Walleij 
252ef6eb322SLinus Walleij static const struct clk_ops pll_clk_ops = {
253ef6eb322SLinus Walleij 	.enable = pll_clk_enable,
254ef6eb322SLinus Walleij 	.disable = pll_clk_disable,
255ef6eb322SLinus Walleij 	.is_enabled = pll_clk_is_enabled,
256ef6eb322SLinus Walleij 	.recalc_rate = pll_clk_recalc_rate,
257ef6eb322SLinus Walleij };
258ef6eb322SLinus Walleij 
2597b38d1b2SStephen Boyd static struct clk_hw * __init
pll_clk_register(struct device * dev,const char * name,const char * parent_name,u32 id)260ef6eb322SLinus Walleij pll_clk_register(struct device *dev, const char *name,
261ef6eb322SLinus Walleij 		 const char *parent_name, u32 id)
262ef6eb322SLinus Walleij {
2637b38d1b2SStephen Boyd 	int ret;
264ef6eb322SLinus Walleij 	struct clk_pll *pll;
265ef6eb322SLinus Walleij 	struct clk_init_data init;
266ef6eb322SLinus Walleij 
267ef6eb322SLinus Walleij 	if (id != 1 && id != 2) {
268ef6eb322SLinus Walleij 		pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
269ef6eb322SLinus Walleij 		return ERR_PTR(-EINVAL);
270ef6eb322SLinus Walleij 	}
271ef6eb322SLinus Walleij 
272ef6eb322SLinus Walleij 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
27324f8186eSMarkus Elfring 	if (!pll)
274ef6eb322SLinus Walleij 		return ERR_PTR(-ENOMEM);
275ef6eb322SLinus Walleij 
276ef6eb322SLinus Walleij 	init.name = name;
277ef6eb322SLinus Walleij 	init.ops = &pll_clk_ops;
278ef6eb322SLinus Walleij 	init.parent_names = (parent_name ? &parent_name : NULL);
279ef6eb322SLinus Walleij 	init.num_parents = (parent_name ? 1 : 0);
280ef6eb322SLinus Walleij 	pll->hw.init = &init;
281ef6eb322SLinus Walleij 	pll->id = id;
282ef6eb322SLinus Walleij 
283ef6eb322SLinus Walleij 	pr_debug("register PLL1 clock \"%s\"\n", name);
284ef6eb322SLinus Walleij 
2857b38d1b2SStephen Boyd 	ret = clk_hw_register(dev, &pll->hw);
2867b38d1b2SStephen Boyd 	if (ret) {
287ef6eb322SLinus Walleij 		kfree(pll);
2887b38d1b2SStephen Boyd 		return ERR_PTR(ret);
2897b38d1b2SStephen Boyd 	}
290ef6eb322SLinus Walleij 
2917b38d1b2SStephen Boyd 	return &pll->hw;
292ef6eb322SLinus Walleij }
293ef6eb322SLinus Walleij 
294ef6eb322SLinus Walleij /*
295ef6eb322SLinus Walleij  * The Nomadik SRC clocks are gated, but not in the sense that
296ef6eb322SLinus Walleij  * you read-modify-write a register. Instead there are separate
297ef6eb322SLinus Walleij  * clock enable and clock disable registers. Writing a '1' bit in
298ef6eb322SLinus Walleij  * the enable register for a certain clock ungates that clock without
299ef6eb322SLinus Walleij  * affecting the other clocks. The disable register works the opposite
300ef6eb322SLinus Walleij  * way.
301ef6eb322SLinus Walleij  */
302ef6eb322SLinus Walleij 
src_clk_enable(struct clk_hw * hw)303ef6eb322SLinus Walleij static int src_clk_enable(struct clk_hw *hw)
304ef6eb322SLinus Walleij {
305ef6eb322SLinus Walleij 	struct clk_src *sclk = to_src(hw);
306ef6eb322SLinus Walleij 	u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
307ef6eb322SLinus Walleij 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
308ef6eb322SLinus Walleij 
309ef6eb322SLinus Walleij 	writel(sclk->clkbit, src_base + enreg);
310ef6eb322SLinus Walleij 	/* spin until enabled */
311ef6eb322SLinus Walleij 	while (!(readl(src_base + sreg) & sclk->clkbit))
312ef6eb322SLinus Walleij 		cpu_relax();
313ef6eb322SLinus Walleij 	return 0;
314ef6eb322SLinus Walleij }
315ef6eb322SLinus Walleij 
src_clk_disable(struct clk_hw * hw)316ef6eb322SLinus Walleij static void src_clk_disable(struct clk_hw *hw)
317ef6eb322SLinus Walleij {
318ef6eb322SLinus Walleij 	struct clk_src *sclk = to_src(hw);
319ef6eb322SLinus Walleij 	u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
320ef6eb322SLinus Walleij 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
321ef6eb322SLinus Walleij 
322ef6eb322SLinus Walleij 	writel(sclk->clkbit, src_base + disreg);
323ef6eb322SLinus Walleij 	/* spin until disabled */
324ef6eb322SLinus Walleij 	while (readl(src_base + sreg) & sclk->clkbit)
325ef6eb322SLinus Walleij 		cpu_relax();
326ef6eb322SLinus Walleij }
327ef6eb322SLinus Walleij 
src_clk_is_enabled(struct clk_hw * hw)328ef6eb322SLinus Walleij static int src_clk_is_enabled(struct clk_hw *hw)
329ef6eb322SLinus Walleij {
330ef6eb322SLinus Walleij 	struct clk_src *sclk = to_src(hw);
331ef6eb322SLinus Walleij 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
332ef6eb322SLinus Walleij 	u32 val = readl(src_base + sreg);
333ef6eb322SLinus Walleij 
334ef6eb322SLinus Walleij 	return !!(val & sclk->clkbit);
335ef6eb322SLinus Walleij }
336ef6eb322SLinus Walleij 
337ef6eb322SLinus Walleij static unsigned long
src_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)338ef6eb322SLinus Walleij src_clk_recalc_rate(struct clk_hw *hw,
339ef6eb322SLinus Walleij 		    unsigned long parent_rate)
340ef6eb322SLinus Walleij {
341ef6eb322SLinus Walleij 	return parent_rate;
342ef6eb322SLinus Walleij }
343ef6eb322SLinus Walleij 
344ef6eb322SLinus Walleij static const struct clk_ops src_clk_ops = {
345ef6eb322SLinus Walleij 	.enable = src_clk_enable,
346ef6eb322SLinus Walleij 	.disable = src_clk_disable,
347ef6eb322SLinus Walleij 	.is_enabled = src_clk_is_enabled,
348ef6eb322SLinus Walleij 	.recalc_rate = src_clk_recalc_rate,
349ef6eb322SLinus Walleij };
350ef6eb322SLinus Walleij 
3517b38d1b2SStephen Boyd static struct clk_hw * __init
src_clk_register(struct device * dev,const char * name,const char * parent_name,u8 id)352ef6eb322SLinus Walleij src_clk_register(struct device *dev, const char *name,
353ef6eb322SLinus Walleij 		 const char *parent_name, u8 id)
354ef6eb322SLinus Walleij {
3557b38d1b2SStephen Boyd 	int ret;
356ef6eb322SLinus Walleij 	struct clk_src *sclk;
357ef6eb322SLinus Walleij 	struct clk_init_data init;
358ef6eb322SLinus Walleij 
359ef6eb322SLinus Walleij 	sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
36024f8186eSMarkus Elfring 	if (!sclk)
361ef6eb322SLinus Walleij 		return ERR_PTR(-ENOMEM);
36224f8186eSMarkus Elfring 
363ef6eb322SLinus Walleij 	init.name = name;
364ef6eb322SLinus Walleij 	init.ops = &src_clk_ops;
365ef6eb322SLinus Walleij 	/* Do not force-disable the static SDRAM controller */
366ef6eb322SLinus Walleij 	if (id == 2)
367ef6eb322SLinus Walleij 		init.flags = CLK_IGNORE_UNUSED;
368ef6eb322SLinus Walleij 	else
369ef6eb322SLinus Walleij 		init.flags = 0;
370ef6eb322SLinus Walleij 	init.parent_names = (parent_name ? &parent_name : NULL);
371ef6eb322SLinus Walleij 	init.num_parents = (parent_name ? 1 : 0);
372ef6eb322SLinus Walleij 	sclk->hw.init = &init;
373ef6eb322SLinus Walleij 	sclk->id = id;
374ef6eb322SLinus Walleij 	sclk->group1 = (id > 31);
375ef6eb322SLinus Walleij 	sclk->clkbit = BIT(id & 0x1f);
376ef6eb322SLinus Walleij 
377ef6eb322SLinus Walleij 	pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
378ef6eb322SLinus Walleij 		 name, id, sclk->group1, sclk->clkbit);
379ef6eb322SLinus Walleij 
3807b38d1b2SStephen Boyd 	ret = clk_hw_register(dev, &sclk->hw);
3817b38d1b2SStephen Boyd 	if (ret) {
382ef6eb322SLinus Walleij 		kfree(sclk);
3837b38d1b2SStephen Boyd 		return ERR_PTR(ret);
3847b38d1b2SStephen Boyd 	}
385ef6eb322SLinus Walleij 
3867b38d1b2SStephen Boyd 	return &sclk->hw;
387ef6eb322SLinus Walleij }
388ef6eb322SLinus Walleij 
389ef6eb322SLinus Walleij #ifdef CONFIG_DEBUG_FS
390ef6eb322SLinus Walleij 
391ef6eb322SLinus Walleij static u32 src_pcksr0_boot;
392ef6eb322SLinus Walleij static u32 src_pcksr1_boot;
393ef6eb322SLinus Walleij 
394ef6eb322SLinus Walleij static const char * const src_clk_names[] = {
395ef6eb322SLinus Walleij 	"HCLKDMA0  ",
396ef6eb322SLinus Walleij 	"HCLKSMC   ",
397ef6eb322SLinus Walleij 	"HCLKSDRAM ",
398ef6eb322SLinus Walleij 	"HCLKDMA1  ",
399ef6eb322SLinus Walleij 	"HCLKCLCD  ",
400ef6eb322SLinus Walleij 	"PCLKIRDA  ",
401ef6eb322SLinus Walleij 	"PCLKSSP   ",
402ef6eb322SLinus Walleij 	"PCLKUART0 ",
403ef6eb322SLinus Walleij 	"PCLKSDI   ",
404ef6eb322SLinus Walleij 	"PCLKI2C0  ",
405ef6eb322SLinus Walleij 	"PCLKI2C1  ",
406ef6eb322SLinus Walleij 	"PCLKUART1 ",
407ef6eb322SLinus Walleij 	"PCLMSP0   ",
408ef6eb322SLinus Walleij 	"HCLKUSB   ",
409ef6eb322SLinus Walleij 	"HCLKDIF   ",
410ef6eb322SLinus Walleij 	"HCLKSAA   ",
411ef6eb322SLinus Walleij 	"HCLKSVA   ",
412ef6eb322SLinus Walleij 	"PCLKHSI   ",
413ef6eb322SLinus Walleij 	"PCLKXTI   ",
414ef6eb322SLinus Walleij 	"PCLKUART2 ",
415ef6eb322SLinus Walleij 	"PCLKMSP1  ",
416ef6eb322SLinus Walleij 	"PCLKMSP2  ",
417ef6eb322SLinus Walleij 	"PCLKOWM   ",
418ef6eb322SLinus Walleij 	"HCLKHPI   ",
419ef6eb322SLinus Walleij 	"PCLKSKE   ",
420ef6eb322SLinus Walleij 	"PCLKHSEM  ",
421ef6eb322SLinus Walleij 	"HCLK3D    ",
422ef6eb322SLinus Walleij 	"HCLKHASH  ",
423ef6eb322SLinus Walleij 	"HCLKCRYP  ",
424ef6eb322SLinus Walleij 	"PCLKMSHC  ",
425ef6eb322SLinus Walleij 	"HCLKUSBM  ",
426ef6eb322SLinus Walleij 	"HCLKRNG   ",
427ef6eb322SLinus Walleij 	"RESERVED  ",
428ef6eb322SLinus Walleij 	"RESERVED  ",
429ef6eb322SLinus Walleij 	"RESERVED  ",
430ef6eb322SLinus Walleij 	"RESERVED  ",
431ef6eb322SLinus Walleij 	"CLDCLK    ",
432ef6eb322SLinus Walleij 	"IRDACLK   ",
433ef6eb322SLinus Walleij 	"SSPICLK   ",
434ef6eb322SLinus Walleij 	"UART0CLK  ",
435ef6eb322SLinus Walleij 	"SDICLK    ",
436ef6eb322SLinus Walleij 	"I2C0CLK   ",
437ef6eb322SLinus Walleij 	"I2C1CLK   ",
438ef6eb322SLinus Walleij 	"UART1CLK  ",
439ef6eb322SLinus Walleij 	"MSPCLK0   ",
440ef6eb322SLinus Walleij 	"USBCLK    ",
441ef6eb322SLinus Walleij 	"DIFCLK    ",
442ef6eb322SLinus Walleij 	"IPI2CCLK  ",
443ef6eb322SLinus Walleij 	"IPBMCCLK  ",
444ef6eb322SLinus Walleij 	"HSICLKRX  ",
445ef6eb322SLinus Walleij 	"HSICLKTX  ",
446ef6eb322SLinus Walleij 	"UART2CLK  ",
447ef6eb322SLinus Walleij 	"MSPCLK1   ",
448ef6eb322SLinus Walleij 	"MSPCLK2   ",
449ef6eb322SLinus Walleij 	"OWMCLK    ",
450ef6eb322SLinus Walleij 	"RESERVED  ",
451ef6eb322SLinus Walleij 	"SKECLK    ",
452ef6eb322SLinus Walleij 	"RESERVED  ",
453ef6eb322SLinus Walleij 	"3DCLK     ",
454ef6eb322SLinus Walleij 	"PCLKMSP3  ",
455ef6eb322SLinus Walleij 	"MSPCLK3   ",
456ef6eb322SLinus Walleij 	"MSHCCLK   ",
457ef6eb322SLinus Walleij 	"USBMCLK   ",
458ef6eb322SLinus Walleij 	"RNGCCLK   ",
459ef6eb322SLinus Walleij };
460ef6eb322SLinus Walleij 
nomadik_src_clk_debugfs_show(struct seq_file * s,void * what)4619579346eSYangtao Li static int nomadik_src_clk_debugfs_show(struct seq_file *s, void *what)
462ef6eb322SLinus Walleij {
463ef6eb322SLinus Walleij 	int i;
464ef6eb322SLinus Walleij 	u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
465ef6eb322SLinus Walleij 	u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
466ef6eb322SLinus Walleij 	u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
467ef6eb322SLinus Walleij 	u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
468ef6eb322SLinus Walleij 
469add31511SMarkus Elfring 	seq_puts(s, "Clock:      Boot:   Now:    Request: ASKED:\n");
470ef6eb322SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
471ef6eb322SLinus Walleij 		u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
472ef6eb322SLinus Walleij 		u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
473ef6eb322SLinus Walleij 		u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
474ef6eb322SLinus Walleij 		u32 mask = BIT(i & 0x1f);
475ef6eb322SLinus Walleij 
476ef6eb322SLinus Walleij 		seq_printf(s, "%s  %s     %s     %s\n",
477ef6eb322SLinus Walleij 			   src_clk_names[i],
478ef6eb322SLinus Walleij 			   (pcksrb & mask) ? "on " : "off",
479ef6eb322SLinus Walleij 			   (pcksr & mask) ? "on " : "off",
480ef6eb322SLinus Walleij 			   (pckreq & mask) ? "on " : "off");
481ef6eb322SLinus Walleij 	}
482ef6eb322SLinus Walleij 	return 0;
483ef6eb322SLinus Walleij }
484ef6eb322SLinus Walleij 
4859579346eSYangtao Li DEFINE_SHOW_ATTRIBUTE(nomadik_src_clk_debugfs);
486ef6eb322SLinus Walleij 
nomadik_src_clk_init_debugfs(void)487ef6eb322SLinus Walleij static int __init nomadik_src_clk_init_debugfs(void)
488ef6eb322SLinus Walleij {
489ec6deea1SLinus Walleij 	/* Vital for multiplatform */
490ec6deea1SLinus Walleij 	if (!src_base)
491ec6deea1SLinus Walleij 		return -ENODEV;
492ef6eb322SLinus Walleij 	src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
493ef6eb322SLinus Walleij 	src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
494ef6eb322SLinus Walleij 	debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
4959579346eSYangtao Li 			    NULL, NULL, &nomadik_src_clk_debugfs_fops);
496ef6eb322SLinus Walleij 	return 0;
497ef6eb322SLinus Walleij }
498791ed0bbSPaul Gortmaker device_initcall(nomadik_src_clk_init_debugfs);
499ef6eb322SLinus Walleij 
500ef6eb322SLinus Walleij #endif
501ef6eb322SLinus Walleij 
of_nomadik_pll_setup(struct device_node * np)502ef6eb322SLinus Walleij static void __init of_nomadik_pll_setup(struct device_node *np)
503ef6eb322SLinus Walleij {
5047b38d1b2SStephen Boyd 	struct clk_hw *hw;
505ef6eb322SLinus Walleij 	const char *clk_name = np->name;
506ef6eb322SLinus Walleij 	const char *parent_name;
507ef6eb322SLinus Walleij 	u32 pll_id;
508ef6eb322SLinus Walleij 
50974227e65SSebastian Hesselbarth 	if (!src_base)
51074227e65SSebastian Hesselbarth 		nomadik_src_init();
51174227e65SSebastian Hesselbarth 
512ef6eb322SLinus Walleij 	if (of_property_read_u32(np, "pll-id", &pll_id)) {
513ef6eb322SLinus Walleij 		pr_err("%s: PLL \"%s\" missing pll-id property\n",
514ef6eb322SLinus Walleij 			__func__, clk_name);
515ef6eb322SLinus Walleij 		return;
516ef6eb322SLinus Walleij 	}
517ef6eb322SLinus Walleij 	parent_name = of_clk_get_parent_name(np, 0);
5187b38d1b2SStephen Boyd 	hw = pll_clk_register(NULL, clk_name, parent_name, pll_id);
5197b38d1b2SStephen Boyd 	if (!IS_ERR(hw))
5207b38d1b2SStephen Boyd 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
521ef6eb322SLinus Walleij }
52274227e65SSebastian Hesselbarth CLK_OF_DECLARE(nomadik_pll_clk,
52374227e65SSebastian Hesselbarth 	"st,nomadik-pll-clock", of_nomadik_pll_setup);
524ef6eb322SLinus Walleij 
of_nomadik_hclk_setup(struct device_node * np)525ef6eb322SLinus Walleij static void __init of_nomadik_hclk_setup(struct device_node *np)
526ef6eb322SLinus Walleij {
5277b38d1b2SStephen Boyd 	struct clk_hw *hw;
528ef6eb322SLinus Walleij 	const char *clk_name = np->name;
529ef6eb322SLinus Walleij 	const char *parent_name;
530ef6eb322SLinus Walleij 
53174227e65SSebastian Hesselbarth 	if (!src_base)
53274227e65SSebastian Hesselbarth 		nomadik_src_init();
53374227e65SSebastian Hesselbarth 
534ef6eb322SLinus Walleij 	parent_name = of_clk_get_parent_name(np, 0);
535ef6eb322SLinus Walleij 	/*
536ef6eb322SLinus Walleij 	 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
537ef6eb322SLinus Walleij 	 */
5387b38d1b2SStephen Boyd 	hw = clk_hw_register_divider(NULL, clk_name, parent_name,
539ef6eb322SLinus Walleij 			   0, src_base + SRC_CR,
540ef6eb322SLinus Walleij 			   13, 2,
541ef6eb322SLinus Walleij 			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
542ef6eb322SLinus Walleij 			   &src_lock);
5437b38d1b2SStephen Boyd 	if (!IS_ERR(hw))
5447b38d1b2SStephen Boyd 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
545ef6eb322SLinus Walleij }
54674227e65SSebastian Hesselbarth CLK_OF_DECLARE(nomadik_hclk_clk,
54774227e65SSebastian Hesselbarth 	"st,nomadik-hclk-clock", of_nomadik_hclk_setup);
548ef6eb322SLinus Walleij 
of_nomadik_src_clk_setup(struct device_node * np)549ef6eb322SLinus Walleij static void __init of_nomadik_src_clk_setup(struct device_node *np)
550ef6eb322SLinus Walleij {
5517b38d1b2SStephen Boyd 	struct clk_hw *hw;
552ef6eb322SLinus Walleij 	const char *clk_name = np->name;
553ef6eb322SLinus Walleij 	const char *parent_name;
554ef6eb322SLinus Walleij 	u32 clk_id;
555ef6eb322SLinus Walleij 
55674227e65SSebastian Hesselbarth 	if (!src_base)
55774227e65SSebastian Hesselbarth 		nomadik_src_init();
55874227e65SSebastian Hesselbarth 
559ef6eb322SLinus Walleij 	if (of_property_read_u32(np, "clock-id", &clk_id)) {
560ef6eb322SLinus Walleij 		pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
561ef6eb322SLinus Walleij 			__func__, clk_name);
562ef6eb322SLinus Walleij 		return;
563ef6eb322SLinus Walleij 	}
564ef6eb322SLinus Walleij 	parent_name = of_clk_get_parent_name(np, 0);
5657b38d1b2SStephen Boyd 	hw = src_clk_register(NULL, clk_name, parent_name, clk_id);
5667b38d1b2SStephen Boyd 	if (!IS_ERR(hw))
5677b38d1b2SStephen Boyd 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
568ef6eb322SLinus Walleij }
56974227e65SSebastian Hesselbarth CLK_OF_DECLARE(nomadik_src_clk,
57074227e65SSebastian Hesselbarth 	"st,nomadik-src-clock", of_nomadik_src_clk_setup);
571