blob: ccff2dae167f64a9c37eaca4f117137fa31483d7 [file] [log] [blame]
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +01001/*
2 * Copyright (C) 2009 ST-Ericsson
Rabin Vincent1df20af2010-03-01 05:07:47 +01003 * Copyright (C) 2009 STMicroelectronics
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#include <linux/module.h>
10#include <linux/kernel.h>
11#include <linux/list.h>
12#include <linux/errno.h>
13#include <linux/err.h>
14#include <linux/clk.h>
Rabin Vincent1df20af2010-03-01 05:07:47 +010015#include <linux/io.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010016#include <linux/clkdev.h>
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +010017
Linus Walleijba327b12010-05-26 07:38:54 +010018#include <plat/mtu.h>
Rabin Vincent1df20af2010-03-01 05:07:47 +010019#include <mach/hardware.h>
20#include "clock.h"
21
Vincent Guittot763eef82010-12-03 18:18:39 +010022#ifdef CONFIG_DEBUG_FS
23#include <linux/debugfs.h>
24#include <linux/uaccess.h> /* for copy_from_user */
25static LIST_HEAD(clk_list);
26#endif
27
Rabin Vincent1df20af2010-03-01 05:07:47 +010028#define PRCC_PCKEN 0x00
29#define PRCC_PCKDIS 0x04
30#define PRCC_KCKEN 0x08
31#define PRCC_KCKDIS 0x0C
32
33#define PRCM_YYCLKEN0_MGT_SET 0x510
34#define PRCM_YYCLKEN1_MGT_SET 0x514
35#define PRCM_YYCLKEN0_MGT_CLR 0x518
36#define PRCM_YYCLKEN1_MGT_CLR 0x51C
37#define PRCM_YYCLKEN0_MGT_VAL 0x520
38#define PRCM_YYCLKEN1_MGT_VAL 0x524
39
40#define PRCM_SVAMMDSPCLK_MGT 0x008
41#define PRCM_SIAMMDSPCLK_MGT 0x00C
42#define PRCM_SGACLK_MGT 0x014
43#define PRCM_UARTCLK_MGT 0x018
44#define PRCM_MSP02CLK_MGT 0x01C
45#define PRCM_MSP1CLK_MGT 0x288
46#define PRCM_I2CCLK_MGT 0x020
47#define PRCM_SDMMCCLK_MGT 0x024
48#define PRCM_SLIMCLK_MGT 0x028
49#define PRCM_PER1CLK_MGT 0x02C
50#define PRCM_PER2CLK_MGT 0x030
51#define PRCM_PER3CLK_MGT 0x034
52#define PRCM_PER5CLK_MGT 0x038
53#define PRCM_PER6CLK_MGT 0x03C
54#define PRCM_PER7CLK_MGT 0x040
55#define PRCM_LCDCLK_MGT 0x044
56#define PRCM_BMLCLK_MGT 0x04C
57#define PRCM_HSITXCLK_MGT 0x050
58#define PRCM_HSIRXCLK_MGT 0x054
59#define PRCM_HDMICLK_MGT 0x058
60#define PRCM_APEATCLK_MGT 0x05C
61#define PRCM_APETRACECLK_MGT 0x060
62#define PRCM_MCDECLK_MGT 0x064
63#define PRCM_IPI2CCLK_MGT 0x068
64#define PRCM_DSIALTCLK_MGT 0x06C
65#define PRCM_DMACLK_MGT 0x074
66#define PRCM_B2R2CLK_MGT 0x078
67#define PRCM_TVCLK_MGT 0x07C
Linus Walleijba327b12010-05-26 07:38:54 +010068#define PRCM_TCR 0x1C8
69#define PRCM_TCR_STOPPED (1 << 16)
70#define PRCM_TCR_DOZE_MODE (1 << 17)
Rabin Vincent1df20af2010-03-01 05:07:47 +010071#define PRCM_UNIPROCLK_MGT 0x278
72#define PRCM_SSPCLK_MGT 0x280
73#define PRCM_RNGCLK_MGT 0x284
74#define PRCM_UICCCLK_MGT 0x27C
75
76#define PRCM_MGT_ENABLE (1 << 8)
77
78static DEFINE_SPINLOCK(clocks_lock);
79
80static void __clk_enable(struct clk *clk)
81{
82 if (clk->enabled++ == 0) {
83 if (clk->parent_cluster)
84 __clk_enable(clk->parent_cluster);
85
86 if (clk->parent_periph)
87 __clk_enable(clk->parent_periph);
88
89 if (clk->ops && clk->ops->enable)
90 clk->ops->enable(clk);
91 }
92}
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +010093
94int clk_enable(struct clk *clk)
95{
Rabin Vincent1df20af2010-03-01 05:07:47 +010096 unsigned long flags;
97
98 spin_lock_irqsave(&clocks_lock, flags);
99 __clk_enable(clk);
100 spin_unlock_irqrestore(&clocks_lock, flags);
101
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100102 return 0;
103}
104EXPORT_SYMBOL(clk_enable);
105
Rabin Vincent1df20af2010-03-01 05:07:47 +0100106static void __clk_disable(struct clk *clk)
107{
108 if (--clk->enabled == 0) {
109 if (clk->ops && clk->ops->disable)
110 clk->ops->disable(clk);
111
112 if (clk->parent_periph)
113 __clk_disable(clk->parent_periph);
114
115 if (clk->parent_cluster)
116 __clk_disable(clk->parent_cluster);
117 }
118}
119
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100120void clk_disable(struct clk *clk)
121{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100122 unsigned long flags;
123
124 WARN_ON(!clk->enabled);
125
126 spin_lock_irqsave(&clocks_lock, flags);
127 __clk_disable(clk);
128 spin_unlock_irqrestore(&clocks_lock, flags);
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100129}
130EXPORT_SYMBOL(clk_disable);
131
Linus Walleijba327b12010-05-26 07:38:54 +0100132/*
133 * The MTU has a separate, rather complex muxing setup
134 * with alternative parents (peripheral cluster or
135 * ULP or fixed 32768 Hz) depending on settings
136 */
137static unsigned long clk_mtu_get_rate(struct clk *clk)
138{
Linus Walleijd9e38042010-06-23 07:59:48 +0100139 void __iomem *addr = __io_address(UX500_PRCMU_BASE)
Linus Walleijba327b12010-05-26 07:38:54 +0100140 + PRCM_TCR;
Sundar Iyerf3069542010-12-03 20:35:51 +0530141 u32 tcr;
Linus Walleijba327b12010-05-26 07:38:54 +0100142 int mtu = (int) clk->data;
143 /*
144 * One of these is selected eventually
145 * TODO: Replace the constant with a reference
146 * to the ULP source once this is modeled.
147 */
148 unsigned long clk32k = 32768;
149 unsigned long mturate;
150 unsigned long retclk;
151
Sundar Iyerf3069542010-12-03 20:35:51 +0530152 /*
153 * On a startup, always conifgure the TCR to the doze mode;
154 * bootloaders do it for us. Do this in the kernel too.
155 */
156 writel(PRCM_TCR_DOZE_MODE, addr);
157
158 tcr = readl(addr);
159
Linus Walleijba327b12010-05-26 07:38:54 +0100160 /* Get the rate from the parent as a default */
161 if (clk->parent_periph)
162 mturate = clk_get_rate(clk->parent_periph);
163 else if (clk->parent_cluster)
164 mturate = clk_get_rate(clk->parent_cluster);
165 else
166 /* We need to be connected SOMEWHERE */
167 BUG();
168
Linus Walleijba327b12010-05-26 07:38:54 +0100169 /* Return the clock selected for this MTU */
170 if (tcr & (1 << mtu))
171 retclk = clk32k;
172 else
173 retclk = mturate;
174
175 pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
176 return retclk;
177}
178
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100179unsigned long clk_get_rate(struct clk *clk)
180{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100181 unsigned long rate;
182
Linus Walleijba327b12010-05-26 07:38:54 +0100183 /*
184 * If there is a custom getrate callback for this clock,
185 * it will take precedence.
186 */
187 if (clk->get_rate)
188 return clk->get_rate(clk);
189
Rabin Vincent1df20af2010-03-01 05:07:47 +0100190 if (clk->ops && clk->ops->get_rate)
191 return clk->ops->get_rate(clk);
192
193 rate = clk->rate;
194 if (!rate) {
195 if (clk->parent_periph)
196 rate = clk_get_rate(clk->parent_periph);
197 else if (clk->parent_cluster)
198 rate = clk_get_rate(clk->parent_cluster);
199 }
200
201 return rate;
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100202}
203EXPORT_SYMBOL(clk_get_rate);
204
205long clk_round_rate(struct clk *clk, unsigned long rate)
206{
207 /*TODO*/
208 return rate;
209}
210EXPORT_SYMBOL(clk_round_rate);
211
212int clk_set_rate(struct clk *clk, unsigned long rate)
213{
214 clk->rate = rate;
215 return 0;
216}
217EXPORT_SYMBOL(clk_set_rate);
218
Rabin Vincent1df20af2010-03-01 05:07:47 +0100219static void clk_prcmu_enable(struct clk *clk)
220{
221 void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
222 + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off;
223
224 writel(1 << clk->prcmu_cg_bit, cg_set_reg);
225}
226
227static void clk_prcmu_disable(struct clk *clk)
228{
229 void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE)
230 + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off;
231
232 writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
233}
234
235/* ED doesn't have the combined set/clr registers */
236static void clk_prcmu_ed_enable(struct clk *clk)
237{
238 void __iomem *addr = __io_address(U8500_PRCMU_BASE)
239 + clk->prcmu_cg_mgt;
240
241 writel(readl(addr) | PRCM_MGT_ENABLE, addr);
242}
243
244static void clk_prcmu_ed_disable(struct clk *clk)
245{
246 void __iomem *addr = __io_address(U8500_PRCMU_BASE)
247 + clk->prcmu_cg_mgt;
248
249 writel(readl(addr) & ~PRCM_MGT_ENABLE, addr);
250}
251
252static struct clkops clk_prcmu_ops = {
253 .enable = clk_prcmu_enable,
254 .disable = clk_prcmu_disable,
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100255};
256
Rabin Vincent1df20af2010-03-01 05:07:47 +0100257static unsigned int clkrst_base[] = {
258 [1] = U8500_CLKRST1_BASE,
259 [2] = U8500_CLKRST2_BASE,
260 [3] = U8500_CLKRST3_BASE,
261 [5] = U8500_CLKRST5_BASE,
262 [6] = U8500_CLKRST6_BASE,
263 [7] = U8500_CLKRST7_BASE_ED,
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100264};
265
Rabin Vincent1df20af2010-03-01 05:07:47 +0100266static void clk_prcc_enable(struct clk *clk)
267{
268 void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
269
270 if (clk->prcc_kernel != -1)
271 writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
272
273 if (clk->prcc_bus != -1)
274 writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
275}
276
277static void clk_prcc_disable(struct clk *clk)
278{
279 void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
280
281 if (clk->prcc_bus != -1)
282 writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
283
284 if (clk->prcc_kernel != -1)
285 writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
286}
287
288static struct clkops clk_prcc_ops = {
289 .enable = clk_prcc_enable,
290 .disable = clk_prcc_disable,
291};
292
293static struct clk clk_32khz = {
Vincent Guittot763eef82010-12-03 18:18:39 +0100294 .name = "clk_32khz",
Rabin Vincent1df20af2010-03-01 05:07:47 +0100295 .rate = 32000,
296};
297
298/*
299 * PRCMU level clock gating
300 */
301
302/* Bank 0 */
303static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK);
304static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK);
305static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK);
306static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
307static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
308static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
309static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
310static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000);
311static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
312static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
313static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
314static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK);
315static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK);
316static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000);
317static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000);
318static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK);
319static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK);
320static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK);
321static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK);
322static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK);
323static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK);
324static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK);
325static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK);
326static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK);
327static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */
328static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK);
329static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK);
330static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK);
331static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */
332static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */
333
334/* Bank 1 */
335static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */
336static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
337
338/*
339 * PRCC level clock gating
340 * Format: per#, clk, PCKEN bit, KCKEN bit, parent
341 */
342
343/* Peripheral Cluster #1 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530344static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100345static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530346static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
347static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
348static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
349static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100350static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530351static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
352static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
353static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
354static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
355static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
356static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100357
358/* Peripheral Cluster #2 */
359
360static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530361static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
362static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
363static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
364static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
365static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
366static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
367static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100368static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530369static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
370static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
371static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100372
373static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530374static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
375static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
376static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
377static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
378static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
379static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
380static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100381static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530382static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
383static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
384static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100385
386/* Peripheral Cluster #3 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530387static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
388static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
389static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
390static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
391static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
392static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
393static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
394static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
395static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
396static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
397static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100398
399/* Peripheral Cluster #4 is in the always on domain */
400
401/* Peripheral Cluster #5 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530402static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
403static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
404static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100405
406/* Peripheral Cluster #6 */
407
Linus Walleijba327b12010-05-26 07:38:54 +0100408/* MTU ID in data */
409static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
410static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530411static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
412static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
413static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
414static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
415static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
416static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
417static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
418static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
419static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
420static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100421
422/* Peripheral Cluster #7 */
423
Sundar Iyer592b2f22010-12-03 20:35:52 +0530424static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
Linus Walleijba327b12010-05-26 07:38:54 +0100425/* MTU ID in data */
426static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
427static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530428static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
429static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100430
Vincent Guittot763eef82010-12-03 18:18:39 +0100431static struct clk clk_dummy_apb_pclk = {
432 .name = "apb_pclk",
433};
Russell King3126c7b2010-07-15 11:01:17 +0100434
Rabin Vincent1df20af2010-03-01 05:07:47 +0100435static struct clk_lookup u8500_common_clks[] = {
Russell King3126c7b2010-07-15 11:01:17 +0100436 CLK(dummy_apb_pclk, NULL, "apb_pclk"),
437
Rabin Vincent1df20af2010-03-01 05:07:47 +0100438 /* Peripheral Cluster #1 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100439 CLK(gpio0, "gpio.0", NULL),
440 CLK(gpio0, "gpio.1", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100441 CLK(slimbus0, "slimbus0", NULL),
442 CLK(i2c2, "nmk-i2c.2", NULL),
443 CLK(sdi0, "sdi0", NULL),
444 CLK(msp0, "msp0", NULL),
445 CLK(i2c1, "nmk-i2c.1", NULL),
446 CLK(uart1, "uart1", NULL),
447 CLK(uart0, "uart0", NULL),
448
449 /* Peripheral Cluster #3 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100450 CLK(gpio2, "gpio.2", NULL),
451 CLK(gpio2, "gpio.3", NULL),
452 CLK(gpio2, "gpio.4", NULL),
453 CLK(gpio2, "gpio.5", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100454 CLK(sdi5, "sdi5", NULL),
455 CLK(uart2, "uart2", NULL),
456 CLK(ske, "ske", NULL),
Sundar Iyer4c61c842010-09-29 19:43:09 -0700457 CLK(ske, "nmk-ske-keypad", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100458 CLK(sdi2, "sdi2", NULL),
459 CLK(i2c0, "nmk-i2c.0", NULL),
460 CLK(fsmc, "fsmc", NULL),
461
462 /* Peripheral Cluster #5 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100463 CLK(gpio3, "gpio.8", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100464
465 /* Peripheral Cluster #6 */
466 CLK(hash1, "hash1", NULL),
467 CLK(pka, "pka", NULL),
468 CLK(hash0, "hash0", NULL),
469 CLK(cryp0, "cryp0", NULL),
470
471 /* PRCMU level clock gating */
472
473 /* Bank 0 */
474 CLK(svaclk, "sva", NULL),
475 CLK(siaclk, "sia", NULL),
476 CLK(sgaclk, "sga", NULL),
477 CLK(slimclk, "slim", NULL),
478 CLK(lcdclk, "lcd", NULL),
479 CLK(bmlclk, "bml", NULL),
480 CLK(hsitxclk, "stm-hsi.0", NULL),
481 CLK(hsirxclk, "stm-hsi.1", NULL),
482 CLK(hdmiclk, "hdmi", NULL),
483 CLK(apeatclk, "apeat", NULL),
484 CLK(apetraceclk, "apetrace", NULL),
485 CLK(mcdeclk, "mcde", NULL),
486 CLK(ipi2clk, "ipi2", NULL),
Linus Walleij7b8ddb02010-05-27 15:21:26 -0700487 CLK(dmaclk, "dma40.0", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100488 CLK(b2r2clk, "b2r2", NULL),
489 CLK(tvclk, "tv", NULL),
490};
491
492static struct clk_lookup u8500_ed_clks[] = {
493 /* Peripheral Cluster #1 */
494 CLK(spi3_ed, "spi3", NULL),
495 CLK(msp1_ed, "msp1", NULL),
496
497 /* Peripheral Cluster #2 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100498 CLK(gpio1_ed, "gpio.6", NULL),
499 CLK(gpio1_ed, "gpio.7", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100500 CLK(ssitx_ed, "ssitx", NULL),
501 CLK(ssirx_ed, "ssirx", NULL),
502 CLK(spi0_ed, "spi0", NULL),
503 CLK(sdi3_ed, "sdi3", NULL),
504 CLK(sdi1_ed, "sdi1", NULL),
505 CLK(msp2_ed, "msp2", NULL),
506 CLK(sdi4_ed, "sdi4", NULL),
507 CLK(pwl_ed, "pwl", NULL),
508 CLK(spi1_ed, "spi1", NULL),
509 CLK(spi2_ed, "spi2", NULL),
510 CLK(i2c3_ed, "nmk-i2c.3", NULL),
511
512 /* Peripheral Cluster #3 */
513 CLK(ssp1_ed, "ssp1", NULL),
514 CLK(ssp0_ed, "ssp0", NULL),
515
516 /* Peripheral Cluster #5 */
517 CLK(usb_ed, "musb_hdrc.0", "usb"),
518
519 /* Peripheral Cluster #6 */
520 CLK(dmc_ed, "dmc", NULL),
521 CLK(cryp1_ed, "cryp1", NULL),
522 CLK(rng_ed, "rng", NULL),
523
524 /* Peripheral Cluster #7 */
525 CLK(tzpc0_ed, "tzpc0", NULL),
526 CLK(mtu1_ed, "mtu1", NULL),
527 CLK(mtu0_ed, "mtu0", NULL),
528 CLK(wdg_ed, "wdg", NULL),
529 CLK(cfgreg_ed, "cfgreg", NULL),
530};
531
532static struct clk_lookup u8500_v1_clks[] = {
533 /* Peripheral Cluster #1 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530534 CLK(i2c4, "nmk-i2c.4", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100535 CLK(spi3_v1, "spi3", NULL),
536 CLK(msp1_v1, "msp1", NULL),
537
538 /* Peripheral Cluster #2 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100539 CLK(gpio1_v1, "gpio.6", NULL),
540 CLK(gpio1_v1, "gpio.7", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100541 CLK(ssitx_v1, "ssitx", NULL),
542 CLK(ssirx_v1, "ssirx", NULL),
543 CLK(spi0_v1, "spi0", NULL),
544 CLK(sdi3_v1, "sdi3", NULL),
545 CLK(sdi1_v1, "sdi1", NULL),
546 CLK(msp2_v1, "msp2", NULL),
547 CLK(sdi4_v1, "sdi4", NULL),
548 CLK(pwl_v1, "pwl", NULL),
549 CLK(spi1_v1, "spi1", NULL),
550 CLK(spi2_v1, "spi2", NULL),
551 CLK(i2c3_v1, "nmk-i2c.3", NULL),
552
553 /* Peripheral Cluster #3 */
554 CLK(ssp1_v1, "ssp1", NULL),
555 CLK(ssp0_v1, "ssp0", NULL),
556
557 /* Peripheral Cluster #5 */
558 CLK(usb_v1, "musb_hdrc.0", "usb"),
559
560 /* Peripheral Cluster #6 */
561 CLK(mtu1_v1, "mtu1", NULL),
562 CLK(mtu0_v1, "mtu0", NULL),
563 CLK(cfgreg_v1, "cfgreg", NULL),
564 CLK(hash1, "hash1", NULL),
565 CLK(unipro_v1, "unipro", NULL),
566 CLK(rng_v1, "rng", NULL),
567
568 /* PRCMU level clock gating */
569
570 /* Bank 0 */
571 CLK(uniproclk, "uniproclk", NULL),
572 CLK(dsialtclk, "dsialt", NULL),
573
574 /* Bank 1 */
575 CLK(rngclk, "rng", NULL),
576 CLK(uiccclk, "uicc", NULL),
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100577};
578
Vincent Guittot763eef82010-12-03 18:18:39 +0100579#ifdef CONFIG_DEBUG_FS
580/*
581 * debugfs support to trace clock tree hierarchy and attributes with
582 * powerdebug
583 */
584static struct dentry *clk_debugfs_root;
585
586void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
587{
588 while (num--) {
589 /* Check that the clock has not been already registered */
590 if (!(cl->clk->list.prev != cl->clk->list.next))
591 list_add_tail(&cl->clk->list, &clk_list);
592
593 cl++;
594 }
595}
596
597static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
598 size_t size, loff_t *off)
599{
600 struct clk *clk = file->f_dentry->d_inode->i_private;
601 char cusecount[128];
602 unsigned int len;
603
604 len = sprintf(cusecount, "%u\n", clk->enabled);
605 return simple_read_from_buffer(buf, size, off, cusecount, len);
606}
607
608static ssize_t rate_dbg_read(struct file *file, char __user *buf,
609 size_t size, loff_t *off)
610{
611 struct clk *clk = file->f_dentry->d_inode->i_private;
612 char crate[128];
613 unsigned int rate;
614 unsigned int len;
615
616 rate = clk_get_rate(clk);
617 len = sprintf(crate, "%u\n", rate);
618 return simple_read_from_buffer(buf, size, off, crate, len);
619}
620
621static const struct file_operations usecount_fops = {
622 .read = usecount_dbg_read,
623};
624
625static const struct file_operations set_rate_fops = {
626 .read = rate_dbg_read,
627};
628
629static struct dentry *clk_debugfs_register_dir(struct clk *c,
630 struct dentry *p_dentry)
631{
632 struct dentry *d, *clk_d, *child, *child_tmp;
633 char s[255];
634 char *p = s;
635
636 if (c->name == NULL)
637 p += sprintf(p, "BUG");
638 else
639 p += sprintf(p, "%s", c->name);
640
641 clk_d = debugfs_create_dir(s, p_dentry);
642 if (!clk_d)
643 return NULL;
644
645 d = debugfs_create_file("usecount", S_IRUGO,
646 clk_d, c, &usecount_fops);
647 if (!d)
648 goto err_out;
649 d = debugfs_create_file("rate", S_IRUGO,
650 clk_d, c, &set_rate_fops);
651 if (!d)
652 goto err_out;
653 /*
654 * TODO : not currently available in ux500
655 * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
656 * if (!d)
657 * goto err_out;
658 */
659
660 return clk_d;
661
662err_out:
663 d = clk_d;
664 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
665 debugfs_remove(child);
666 debugfs_remove(clk_d);
667 return NULL;
668}
669
670static void clk_debugfs_remove_dir(struct dentry *cdentry)
671{
672 struct dentry *d, *child, *child_tmp;
673
674 d = cdentry;
675 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
676 debugfs_remove(child);
677 debugfs_remove(cdentry);
678 return ;
679}
680
681static int clk_debugfs_register_one(struct clk *c)
682{
683 struct clk *pa = c->parent_periph;
684 struct clk *bpa = c->parent_cluster;
685
686 if (!(bpa && !pa)) {
687 c->dent = clk_debugfs_register_dir(c,
688 pa ? pa->dent : clk_debugfs_root);
689 if (!c->dent)
690 return -ENOMEM;
691 }
692
693 if (bpa) {
694 c->dent_bus = clk_debugfs_register_dir(c,
695 bpa->dent_bus ? bpa->dent_bus : bpa->dent);
696 if ((!c->dent_bus) && (c->dent)) {
697 clk_debugfs_remove_dir(c->dent);
698 c->dent = NULL;
699 return -ENOMEM;
700 }
701 }
702 return 0;
703}
704
705static int clk_debugfs_register(struct clk *c)
706{
707 int err;
708 struct clk *pa = c->parent_periph;
709 struct clk *bpa = c->parent_cluster;
710
711 if (pa && (!pa->dent && !pa->dent_bus)) {
712 err = clk_debugfs_register(pa);
713 if (err)
714 return err;
715 }
716
717 if (bpa && (!bpa->dent && !bpa->dent_bus)) {
718 err = clk_debugfs_register(bpa);
719 if (err)
720 return err;
721 }
722
723 if ((!c->dent) && (!c->dent_bus)) {
724 err = clk_debugfs_register_one(c);
725 if (err)
726 return err;
727 }
728 return 0;
729}
730
731static int __init clk_debugfs_init(void)
732{
733 struct clk *c;
734 struct dentry *d;
735 int err;
736
737 d = debugfs_create_dir("clock", NULL);
738 if (!d)
739 return -ENOMEM;
740 clk_debugfs_root = d;
741
742 list_for_each_entry(c, &clk_list, list) {
743 err = clk_debugfs_register(c);
744 if (err)
745 goto err_out;
746 }
747 return 0;
748err_out:
749 debugfs_remove_recursive(clk_debugfs_root);
750 return err;
751}
752
753late_initcall(clk_debugfs_init);
754#endif /* defined(CONFIG_DEBUG_FS) */
755
Linus Walleijba327b12010-05-26 07:38:54 +0100756int __init clk_init(void)
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100757{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100758 if (cpu_is_u8500ed()) {
759 clk_prcmu_ops.enable = clk_prcmu_ed_enable;
760 clk_prcmu_ops.disable = clk_prcmu_ed_disable;
Linus Walleijba327b12010-05-26 07:38:54 +0100761 clk_per6clk.rate = 100000000;
Rabin Vincent591d8dd2010-05-03 08:46:51 +0100762 } else if (cpu_is_u5500()) {
763 /* Clock tree for U5500 not implemented yet */
764 clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
765 clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
Per Forlinbab263e2010-12-05 12:49:03 +0100766 clk_uartclk.rate = 36360000;
767 clk_sdmmcclk.rate = 99900000;
Rabin Vincent1df20af2010-03-01 05:07:47 +0100768 }
769
770 clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
771 if (cpu_is_u8500ed())
772 clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
773 else
774 clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
775
Vincent Guittot763eef82010-12-03 18:18:39 +0100776#ifdef CONFIG_DEBUG_FS
777 clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
778 if (cpu_is_u8500ed())
779 clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
780 else
781 clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
782#endif
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100783 return 0;
784}