xref: /OK3568_Linux_fs/kernel/arch/c6x/platforms/pll.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Clock and PLL control for C64x+ devices
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010, 2011 Texas Instruments.
6*4882a593Smuzhiyun  * Contributed by: Mark Salter <msalter@redhat.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copied heavily from arm/mach-davinci/clock.c, so:
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Copyright (C) 2006-2007 Texas Instruments.
11*4882a593Smuzhiyun  * Copyright (C) 2008-2009 Deep Root Systems, LLC
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/clkdev.h>
16*4882a593Smuzhiyun #include <linux/clk.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include <linux/err.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <asm/clock.h>
21*4882a593Smuzhiyun #include <asm/soc.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static LIST_HEAD(clocks);
24*4882a593Smuzhiyun static DEFINE_MUTEX(clocks_mutex);
25*4882a593Smuzhiyun static DEFINE_SPINLOCK(clockfw_lock);
26*4882a593Smuzhiyun 
__clk_enable(struct clk * clk)27*4882a593Smuzhiyun static void __clk_enable(struct clk *clk)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	if (clk->parent)
30*4882a593Smuzhiyun 		__clk_enable(clk->parent);
31*4882a593Smuzhiyun 	clk->usecount++;
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun 
__clk_disable(struct clk * clk)34*4882a593Smuzhiyun static void __clk_disable(struct clk *clk)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	if (WARN_ON(clk->usecount == 0))
37*4882a593Smuzhiyun 		return;
38*4882a593Smuzhiyun 	--clk->usecount;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	if (clk->parent)
41*4882a593Smuzhiyun 		__clk_disable(clk->parent);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
clk_enable(struct clk * clk)44*4882a593Smuzhiyun int clk_enable(struct clk *clk)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	unsigned long flags;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
49*4882a593Smuzhiyun 		return -EINVAL;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	spin_lock_irqsave(&clockfw_lock, flags);
52*4882a593Smuzhiyun 	__clk_enable(clk);
53*4882a593Smuzhiyun 	spin_unlock_irqrestore(&clockfw_lock, flags);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun EXPORT_SYMBOL(clk_enable);
58*4882a593Smuzhiyun 
clk_disable(struct clk * clk)59*4882a593Smuzhiyun void clk_disable(struct clk *clk)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	unsigned long flags;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
64*4882a593Smuzhiyun 		return;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	spin_lock_irqsave(&clockfw_lock, flags);
67*4882a593Smuzhiyun 	__clk_disable(clk);
68*4882a593Smuzhiyun 	spin_unlock_irqrestore(&clockfw_lock, flags);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun EXPORT_SYMBOL(clk_disable);
71*4882a593Smuzhiyun 
clk_get_rate(struct clk * clk)72*4882a593Smuzhiyun unsigned long clk_get_rate(struct clk *clk)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
75*4882a593Smuzhiyun 		return -EINVAL;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return clk->rate;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun EXPORT_SYMBOL(clk_get_rate);
80*4882a593Smuzhiyun 
clk_round_rate(struct clk * clk,unsigned long rate)81*4882a593Smuzhiyun long clk_round_rate(struct clk *clk, unsigned long rate)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
84*4882a593Smuzhiyun 		return -EINVAL;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (clk->round_rate)
87*4882a593Smuzhiyun 		return clk->round_rate(clk, rate);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	return clk->rate;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun EXPORT_SYMBOL(clk_round_rate);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* Propagate rate to children */
propagate_rate(struct clk * root)94*4882a593Smuzhiyun static void propagate_rate(struct clk *root)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct clk *clk;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	list_for_each_entry(clk, &root->children, childnode) {
99*4882a593Smuzhiyun 		if (clk->recalc)
100*4882a593Smuzhiyun 			clk->rate = clk->recalc(clk);
101*4882a593Smuzhiyun 		propagate_rate(clk);
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
clk_set_rate(struct clk * clk,unsigned long rate)105*4882a593Smuzhiyun int clk_set_rate(struct clk *clk, unsigned long rate)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	unsigned long flags;
108*4882a593Smuzhiyun 	int ret = -EINVAL;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
111*4882a593Smuzhiyun 		return ret;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (clk->set_rate)
114*4882a593Smuzhiyun 		ret = clk->set_rate(clk, rate);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	spin_lock_irqsave(&clockfw_lock, flags);
117*4882a593Smuzhiyun 	if (ret == 0) {
118*4882a593Smuzhiyun 		if (clk->recalc)
119*4882a593Smuzhiyun 			clk->rate = clk->recalc(clk);
120*4882a593Smuzhiyun 		propagate_rate(clk);
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 	spin_unlock_irqrestore(&clockfw_lock, flags);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return ret;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun EXPORT_SYMBOL(clk_set_rate);
127*4882a593Smuzhiyun 
clk_set_parent(struct clk * clk,struct clk * parent)128*4882a593Smuzhiyun int clk_set_parent(struct clk *clk, struct clk *parent)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	unsigned long flags;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* Cannot change parent on enabled clock */
136*4882a593Smuzhiyun 	if (WARN_ON(clk->usecount))
137*4882a593Smuzhiyun 		return -EINVAL;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	mutex_lock(&clocks_mutex);
140*4882a593Smuzhiyun 	clk->parent = parent;
141*4882a593Smuzhiyun 	list_del_init(&clk->childnode);
142*4882a593Smuzhiyun 	list_add(&clk->childnode, &clk->parent->children);
143*4882a593Smuzhiyun 	mutex_unlock(&clocks_mutex);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	spin_lock_irqsave(&clockfw_lock, flags);
146*4882a593Smuzhiyun 	if (clk->recalc)
147*4882a593Smuzhiyun 		clk->rate = clk->recalc(clk);
148*4882a593Smuzhiyun 	propagate_rate(clk);
149*4882a593Smuzhiyun 	spin_unlock_irqrestore(&clockfw_lock, flags);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	return 0;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun EXPORT_SYMBOL(clk_set_parent);
154*4882a593Smuzhiyun 
clk_register(struct clk * clk)155*4882a593Smuzhiyun int clk_register(struct clk *clk)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
158*4882a593Smuzhiyun 		return -EINVAL;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	if (WARN(clk->parent && !clk->parent->rate,
161*4882a593Smuzhiyun 		 "CLK: %s parent %s has no rate!\n",
162*4882a593Smuzhiyun 		 clk->name, clk->parent->name))
163*4882a593Smuzhiyun 		return -EINVAL;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	mutex_lock(&clocks_mutex);
166*4882a593Smuzhiyun 	list_add_tail(&clk->node, &clocks);
167*4882a593Smuzhiyun 	if (clk->parent)
168*4882a593Smuzhiyun 		list_add_tail(&clk->childnode, &clk->parent->children);
169*4882a593Smuzhiyun 	mutex_unlock(&clocks_mutex);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	/* If rate is already set, use it */
172*4882a593Smuzhiyun 	if (clk->rate)
173*4882a593Smuzhiyun 		return 0;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	/* Else, see if there is a way to calculate it */
176*4882a593Smuzhiyun 	if (clk->recalc)
177*4882a593Smuzhiyun 		clk->rate = clk->recalc(clk);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	/* Otherwise, default to parent rate */
180*4882a593Smuzhiyun 	else if (clk->parent)
181*4882a593Smuzhiyun 		clk->rate = clk->parent->rate;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun EXPORT_SYMBOL(clk_register);
186*4882a593Smuzhiyun 
clk_unregister(struct clk * clk)187*4882a593Smuzhiyun void clk_unregister(struct clk *clk)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	if (clk == NULL || IS_ERR(clk))
190*4882a593Smuzhiyun 		return;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	mutex_lock(&clocks_mutex);
193*4882a593Smuzhiyun 	list_del(&clk->node);
194*4882a593Smuzhiyun 	list_del(&clk->childnode);
195*4882a593Smuzhiyun 	mutex_unlock(&clocks_mutex);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun EXPORT_SYMBOL(clk_unregister);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 
pll_read(struct pll_data * pll,int reg)200*4882a593Smuzhiyun static u32 pll_read(struct pll_data *pll, int reg)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	return soc_readl(pll->base + reg);
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
clk_sysclk_recalc(struct clk * clk)205*4882a593Smuzhiyun static unsigned long clk_sysclk_recalc(struct clk *clk)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	u32 v, plldiv = 0;
208*4882a593Smuzhiyun 	struct pll_data *pll;
209*4882a593Smuzhiyun 	unsigned long rate = clk->rate;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (WARN_ON(!clk->parent))
212*4882a593Smuzhiyun 		return rate;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	rate = clk->parent->rate;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	/* the parent must be a PLL */
217*4882a593Smuzhiyun 	if (WARN_ON(!clk->parent->pll_data))
218*4882a593Smuzhiyun 		return rate;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	pll = clk->parent->pll_data;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* If pre-PLL, source clock is before the multiplier and divider(s) */
223*4882a593Smuzhiyun 	if (clk->flags & PRE_PLL)
224*4882a593Smuzhiyun 		rate = pll->input_rate;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (!clk->div) {
227*4882a593Smuzhiyun 		pr_debug("%s: (no divider) rate = %lu KHz\n",
228*4882a593Smuzhiyun 			 clk->name, rate / 1000);
229*4882a593Smuzhiyun 		return rate;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (clk->flags & FIXED_DIV_PLL) {
233*4882a593Smuzhiyun 		rate /= clk->div;
234*4882a593Smuzhiyun 		pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n",
235*4882a593Smuzhiyun 			 clk->name, clk->div, rate / 1000);
236*4882a593Smuzhiyun 		return rate;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	v = pll_read(pll, clk->div);
240*4882a593Smuzhiyun 	if (v & PLLDIV_EN)
241*4882a593Smuzhiyun 		plldiv = (v & PLLDIV_RATIO_MASK) + 1;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (plldiv == 0)
244*4882a593Smuzhiyun 		plldiv = 1;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	rate /= plldiv;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	pr_debug("%s: (divide by %d) rate = %lu KHz\n",
249*4882a593Smuzhiyun 		 clk->name, plldiv, rate / 1000);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return rate;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
clk_leafclk_recalc(struct clk * clk)254*4882a593Smuzhiyun static unsigned long clk_leafclk_recalc(struct clk *clk)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	if (WARN_ON(!clk->parent))
257*4882a593Smuzhiyun 		return clk->rate;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	pr_debug("%s: (parent %s) rate = %lu KHz\n",
260*4882a593Smuzhiyun 		 clk->name, clk->parent->name,	clk->parent->rate / 1000);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	return clk->parent->rate;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
clk_pllclk_recalc(struct clk * clk)265*4882a593Smuzhiyun static unsigned long clk_pllclk_recalc(struct clk *clk)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	u32 ctrl, mult = 0, prediv = 0, postdiv = 0;
268*4882a593Smuzhiyun 	u8 bypass;
269*4882a593Smuzhiyun 	struct pll_data *pll = clk->pll_data;
270*4882a593Smuzhiyun 	unsigned long rate = clk->rate;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (clk->flags & FIXED_RATE_PLL)
273*4882a593Smuzhiyun 		return rate;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	ctrl = pll_read(pll, PLLCTL);
276*4882a593Smuzhiyun 	rate = pll->input_rate = clk->parent->rate;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (ctrl & PLLCTL_PLLEN)
279*4882a593Smuzhiyun 		bypass = 0;
280*4882a593Smuzhiyun 	else
281*4882a593Smuzhiyun 		bypass = 1;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	if (pll->flags & PLL_HAS_MUL) {
284*4882a593Smuzhiyun 		mult = pll_read(pll, PLLM);
285*4882a593Smuzhiyun 		mult = (mult & PLLM_PLLM_MASK) + 1;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 	if (pll->flags & PLL_HAS_PRE) {
288*4882a593Smuzhiyun 		prediv = pll_read(pll, PLLPRE);
289*4882a593Smuzhiyun 		if (prediv & PLLDIV_EN)
290*4882a593Smuzhiyun 			prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
291*4882a593Smuzhiyun 		else
292*4882a593Smuzhiyun 			prediv = 0;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 	if (pll->flags & PLL_HAS_POST) {
295*4882a593Smuzhiyun 		postdiv = pll_read(pll, PLLPOST);
296*4882a593Smuzhiyun 		if (postdiv & PLLDIV_EN)
297*4882a593Smuzhiyun 			postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1;
298*4882a593Smuzhiyun 		else
299*4882a593Smuzhiyun 			postdiv = 1;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (!bypass) {
303*4882a593Smuzhiyun 		if (prediv)
304*4882a593Smuzhiyun 			rate /= prediv;
305*4882a593Smuzhiyun 		if (mult)
306*4882a593Smuzhiyun 			rate *= mult;
307*4882a593Smuzhiyun 		if (postdiv)
308*4882a593Smuzhiyun 			rate /= postdiv;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 		pr_debug("PLL%d: input = %luMHz, pre[%d] mul[%d] post[%d] "
311*4882a593Smuzhiyun 			 "--> %luMHz output.\n",
312*4882a593Smuzhiyun 			 pll->num, clk->parent->rate / 1000000,
313*4882a593Smuzhiyun 			 prediv, mult, postdiv, rate / 1000000);
314*4882a593Smuzhiyun 	} else
315*4882a593Smuzhiyun 		pr_debug("PLL%d: input = %luMHz, bypass mode.\n",
316*4882a593Smuzhiyun 			 pll->num, clk->parent->rate / 1000000);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return rate;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 
__init_clk(struct clk * clk)322*4882a593Smuzhiyun static void __init __init_clk(struct clk *clk)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	INIT_LIST_HEAD(&clk->node);
325*4882a593Smuzhiyun 	INIT_LIST_HEAD(&clk->children);
326*4882a593Smuzhiyun 	INIT_LIST_HEAD(&clk->childnode);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (!clk->recalc) {
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 		/* Check if clock is a PLL */
331*4882a593Smuzhiyun 		if (clk->pll_data)
332*4882a593Smuzhiyun 			clk->recalc = clk_pllclk_recalc;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 		/* Else, if it is a PLL-derived clock */
335*4882a593Smuzhiyun 		else if (clk->flags & CLK_PLL)
336*4882a593Smuzhiyun 			clk->recalc = clk_sysclk_recalc;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 		/* Otherwise, it is a leaf clock (PSC clock) */
339*4882a593Smuzhiyun 		else if (clk->parent)
340*4882a593Smuzhiyun 			clk->recalc = clk_leafclk_recalc;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
c6x_clks_init(struct clk_lookup * clocks)344*4882a593Smuzhiyun void __init c6x_clks_init(struct clk_lookup *clocks)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	struct clk_lookup *c;
347*4882a593Smuzhiyun 	struct clk *clk;
348*4882a593Smuzhiyun 	size_t num_clocks = 0;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	for (c = clocks; c->clk; c++) {
351*4882a593Smuzhiyun 		clk = c->clk;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		__init_clk(clk);
354*4882a593Smuzhiyun 		clk_register(clk);
355*4882a593Smuzhiyun 		num_clocks++;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		/* Turn on clocks that Linux doesn't otherwise manage */
358*4882a593Smuzhiyun 		if (clk->flags & ALWAYS_ENABLED)
359*4882a593Smuzhiyun 			clk_enable(clk);
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	clkdev_add_table(clocks, num_clocks);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun #include <linux/debugfs.h>
368*4882a593Smuzhiyun #include <linux/seq_file.h>
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun #define CLKNAME_MAX	10		/* longest clock name */
371*4882a593Smuzhiyun #define NEST_DELTA	2
372*4882a593Smuzhiyun #define NEST_MAX	4
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun static void
dump_clock(struct seq_file * s,unsigned nest,struct clk * parent)375*4882a593Smuzhiyun dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	char		*state;
378*4882a593Smuzhiyun 	char		buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX];
379*4882a593Smuzhiyun 	struct clk	*clk;
380*4882a593Smuzhiyun 	unsigned	i;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if (parent->flags & CLK_PLL)
383*4882a593Smuzhiyun 		state = "pll";
384*4882a593Smuzhiyun 	else
385*4882a593Smuzhiyun 		state = "";
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* <nest spaces> name <pad to end> */
388*4882a593Smuzhiyun 	memset(buf, ' ', sizeof(buf) - 1);
389*4882a593Smuzhiyun 	buf[sizeof(buf) - 1] = 0;
390*4882a593Smuzhiyun 	i = strlen(parent->name);
391*4882a593Smuzhiyun 	memcpy(buf + nest, parent->name,
392*4882a593Smuzhiyun 	       min(i, (unsigned)(sizeof(buf) - 1 - nest)));
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
395*4882a593Smuzhiyun 		   buf, parent->usecount, state, clk_get_rate(parent));
396*4882a593Smuzhiyun 	/* REVISIT show device associations too */
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	/* cost is now small, but not linear... */
399*4882a593Smuzhiyun 	list_for_each_entry(clk, &parent->children, childnode) {
400*4882a593Smuzhiyun 		dump_clock(s, nest + NEST_DELTA, clk);
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
c6x_ck_show(struct seq_file * m,void * v)404*4882a593Smuzhiyun static int c6x_ck_show(struct seq_file *m, void *v)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	struct clk *clk;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	/*
409*4882a593Smuzhiyun 	 * Show clock tree; We trust nonzero usecounts equate to PSC enables...
410*4882a593Smuzhiyun 	 */
411*4882a593Smuzhiyun 	mutex_lock(&clocks_mutex);
412*4882a593Smuzhiyun 	list_for_each_entry(clk, &clocks, node)
413*4882a593Smuzhiyun 		if (!clk->parent)
414*4882a593Smuzhiyun 			dump_clock(m, 0, clk);
415*4882a593Smuzhiyun 	mutex_unlock(&clocks_mutex);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
c6x_ck_open(struct inode * inode,struct file * file)420*4882a593Smuzhiyun static int c6x_ck_open(struct inode *inode, struct file *file)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	return single_open(file, c6x_ck_show, NULL);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun static const struct file_operations c6x_ck_operations = {
426*4882a593Smuzhiyun 	.open		= c6x_ck_open,
427*4882a593Smuzhiyun 	.read		= seq_read,
428*4882a593Smuzhiyun 	.llseek		= seq_lseek,
429*4882a593Smuzhiyun 	.release	= single_release,
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun 
c6x_clk_debugfs_init(void)432*4882a593Smuzhiyun static int __init c6x_clk_debugfs_init(void)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL,
435*4882a593Smuzhiyun 			    &c6x_ck_operations);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	return 0;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun device_initcall(c6x_clk_debugfs_init);
440*4882a593Smuzhiyun #endif /* CONFIG_DEBUG_FS */
441