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