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