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