blob: 912d1cc18c5767affee605e444becf3f07775c4b [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>
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +010016
17#include <asm/clkdev.h>
18
Linus Walleijba327b12010-05-26 07:38:54 +010019#include <plat/mtu.h>
Rabin Vincent1df20af2010-03-01 05:07:47 +010020#include <mach/hardware.h>
21#include "clock.h"
22
Vincent Guittot763eef82010-12-03 18:18:39 +010023#ifdef CONFIG_DEBUG_FS
24#include <linux/debugfs.h>
25#include <linux/uaccess.h> /* for copy_from_user */
26static LIST_HEAD(clk_list);
27#endif
28
Rabin Vincent1df20af2010-03-01 05:07:47 +010029#define PRCC_PCKEN 0x00
30#define PRCC_PCKDIS 0x04
31#define PRCC_KCKEN 0x08
32#define PRCC_KCKDIS 0x0C
33
34#define PRCM_YYCLKEN0_MGT_SET 0x510
35#define PRCM_YYCLKEN1_MGT_SET 0x514
36#define PRCM_YYCLKEN0_MGT_CLR 0x518
37#define PRCM_YYCLKEN1_MGT_CLR 0x51C
38#define PRCM_YYCLKEN0_MGT_VAL 0x520
39#define PRCM_YYCLKEN1_MGT_VAL 0x524
40
41#define PRCM_SVAMMDSPCLK_MGT 0x008
42#define PRCM_SIAMMDSPCLK_MGT 0x00C
43#define PRCM_SGACLK_MGT 0x014
44#define PRCM_UARTCLK_MGT 0x018
45#define PRCM_MSP02CLK_MGT 0x01C
46#define PRCM_MSP1CLK_MGT 0x288
47#define PRCM_I2CCLK_MGT 0x020
48#define PRCM_SDMMCCLK_MGT 0x024
49#define PRCM_SLIMCLK_MGT 0x028
50#define PRCM_PER1CLK_MGT 0x02C
51#define PRCM_PER2CLK_MGT 0x030
52#define PRCM_PER3CLK_MGT 0x034
53#define PRCM_PER5CLK_MGT 0x038
54#define PRCM_PER6CLK_MGT 0x03C
55#define PRCM_PER7CLK_MGT 0x040
56#define PRCM_LCDCLK_MGT 0x044
57#define PRCM_BMLCLK_MGT 0x04C
58#define PRCM_HSITXCLK_MGT 0x050
59#define PRCM_HSIRXCLK_MGT 0x054
60#define PRCM_HDMICLK_MGT 0x058
61#define PRCM_APEATCLK_MGT 0x05C
62#define PRCM_APETRACECLK_MGT 0x060
63#define PRCM_MCDECLK_MGT 0x064
64#define PRCM_IPI2CCLK_MGT 0x068
65#define PRCM_DSIALTCLK_MGT 0x06C
66#define PRCM_DMACLK_MGT 0x074
67#define PRCM_B2R2CLK_MGT 0x078
68#define PRCM_TVCLK_MGT 0x07C
Linus Walleijba327b12010-05-26 07:38:54 +010069#define PRCM_TCR 0x1C8
70#define PRCM_TCR_STOPPED (1 << 16)
71#define PRCM_TCR_DOZE_MODE (1 << 17)
Rabin Vincent1df20af2010-03-01 05:07:47 +010072#define PRCM_UNIPROCLK_MGT 0x278
73#define PRCM_SSPCLK_MGT 0x280
74#define PRCM_RNGCLK_MGT 0x284
75#define PRCM_UICCCLK_MGT 0x27C
76
77#define PRCM_MGT_ENABLE (1 << 8)
78
79static DEFINE_SPINLOCK(clocks_lock);
80
81static void __clk_enable(struct clk *clk)
82{
83 if (clk->enabled++ == 0) {
84 if (clk->parent_cluster)
85 __clk_enable(clk->parent_cluster);
86
87 if (clk->parent_periph)
88 __clk_enable(clk->parent_periph);
89
90 if (clk->ops && clk->ops->enable)
91 clk->ops->enable(clk);
92 }
93}
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +010094
95int clk_enable(struct clk *clk)
96{
Rabin Vincent1df20af2010-03-01 05:07:47 +010097 unsigned long flags;
98
99 spin_lock_irqsave(&clocks_lock, flags);
100 __clk_enable(clk);
101 spin_unlock_irqrestore(&clocks_lock, flags);
102
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100103 return 0;
104}
105EXPORT_SYMBOL(clk_enable);
106
Rabin Vincent1df20af2010-03-01 05:07:47 +0100107static void __clk_disable(struct clk *clk)
108{
109 if (--clk->enabled == 0) {
110 if (clk->ops && clk->ops->disable)
111 clk->ops->disable(clk);
112
113 if (clk->parent_periph)
114 __clk_disable(clk->parent_periph);
115
116 if (clk->parent_cluster)
117 __clk_disable(clk->parent_cluster);
118 }
119}
120
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100121void clk_disable(struct clk *clk)
122{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100123 unsigned long flags;
124
125 WARN_ON(!clk->enabled);
126
127 spin_lock_irqsave(&clocks_lock, flags);
128 __clk_disable(clk);
129 spin_unlock_irqrestore(&clocks_lock, flags);
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100130}
131EXPORT_SYMBOL(clk_disable);
132
Linus Walleijba327b12010-05-26 07:38:54 +0100133/*
134 * The MTU has a separate, rather complex muxing setup
135 * with alternative parents (peripheral cluster or
136 * ULP or fixed 32768 Hz) depending on settings
137 */
138static unsigned long clk_mtu_get_rate(struct clk *clk)
139{
Linus Walleijd9e38042010-06-23 07:59:48 +0100140 void __iomem *addr = __io_address(UX500_PRCMU_BASE)
Linus Walleijba327b12010-05-26 07:38:54 +0100141 + PRCM_TCR;
Sundar Iyerf3069542010-12-03 20:35:51 +0530142 u32 tcr;
Linus Walleijba327b12010-05-26 07:38:54 +0100143 int mtu = (int) clk->data;
144 /*
145 * One of these is selected eventually
146 * TODO: Replace the constant with a reference
147 * to the ULP source once this is modeled.
148 */
149 unsigned long clk32k = 32768;
150 unsigned long mturate;
151 unsigned long retclk;
152
Sundar Iyerf3069542010-12-03 20:35:51 +0530153 /*
154 * On a startup, always conifgure the TCR to the doze mode;
155 * bootloaders do it for us. Do this in the kernel too.
156 */
157 writel(PRCM_TCR_DOZE_MODE, addr);
158
159 tcr = readl(addr);
160
Linus Walleijba327b12010-05-26 07:38:54 +0100161 /* Get the rate from the parent as a default */
162 if (clk->parent_periph)
163 mturate = clk_get_rate(clk->parent_periph);
164 else if (clk->parent_cluster)
165 mturate = clk_get_rate(clk->parent_cluster);
166 else
167 /* We need to be connected SOMEWHERE */
168 BUG();
169
Linus Walleijba327b12010-05-26 07:38:54 +0100170 /* Return the clock selected for this MTU */
171 if (tcr & (1 << mtu))
172 retclk = clk32k;
173 else
174 retclk = mturate;
175
176 pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
177 return retclk;
178}
179
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100180unsigned long clk_get_rate(struct clk *clk)
181{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100182 unsigned long rate;
183
Linus Walleijba327b12010-05-26 07:38:54 +0100184 /*
185 * If there is a custom getrate callback for this clock,
186 * it will take precedence.
187 */
188 if (clk->get_rate)
189 return clk->get_rate(clk);
190
Rabin Vincent1df20af2010-03-01 05:07:47 +0100191 if (clk->ops && clk->ops->get_rate)
192 return clk->ops->get_rate(clk);
193
194 rate = clk->rate;
195 if (!rate) {
196 if (clk->parent_periph)
197 rate = clk_get_rate(clk->parent_periph);
198 else if (clk->parent_cluster)
199 rate = clk_get_rate(clk->parent_cluster);
200 }
201
202 return rate;
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100203}
204EXPORT_SYMBOL(clk_get_rate);
205
206long clk_round_rate(struct clk *clk, unsigned long rate)
207{
208 /*TODO*/
209 return rate;
210}
211EXPORT_SYMBOL(clk_round_rate);
212
213int clk_set_rate(struct clk *clk, unsigned long rate)
214{
215 clk->rate = rate;
216 return 0;
217}
218EXPORT_SYMBOL(clk_set_rate);
219
Rabin Vincent1df20af2010-03-01 05:07:47 +0100220static void clk_prcmu_enable(struct clk *clk)
221{
222 void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
223 + PRCM_YYCLKEN0_MGT_SET + clk->prcmu_cg_off;
224
225 writel(1 << clk->prcmu_cg_bit, cg_set_reg);
226}
227
228static void clk_prcmu_disable(struct clk *clk)
229{
230 void __iomem *cg_clr_reg = __io_address(U8500_PRCMU_BASE)
231 + PRCM_YYCLKEN0_MGT_CLR + clk->prcmu_cg_off;
232
233 writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
234}
235
236/* ED doesn't have the combined set/clr registers */
237static void clk_prcmu_ed_enable(struct clk *clk)
238{
239 void __iomem *addr = __io_address(U8500_PRCMU_BASE)
240 + clk->prcmu_cg_mgt;
241
242 writel(readl(addr) | PRCM_MGT_ENABLE, addr);
243}
244
245static void clk_prcmu_ed_disable(struct clk *clk)
246{
247 void __iomem *addr = __io_address(U8500_PRCMU_BASE)
248 + clk->prcmu_cg_mgt;
249
250 writel(readl(addr) & ~PRCM_MGT_ENABLE, addr);
251}
252
253static struct clkops clk_prcmu_ops = {
254 .enable = clk_prcmu_enable,
255 .disable = clk_prcmu_disable,
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100256};
257
Rabin Vincent1df20af2010-03-01 05:07:47 +0100258static unsigned int clkrst_base[] = {
259 [1] = U8500_CLKRST1_BASE,
260 [2] = U8500_CLKRST2_BASE,
261 [3] = U8500_CLKRST3_BASE,
262 [5] = U8500_CLKRST5_BASE,
263 [6] = U8500_CLKRST6_BASE,
264 [7] = U8500_CLKRST7_BASE_ED,
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100265};
266
Rabin Vincent1df20af2010-03-01 05:07:47 +0100267static void clk_prcc_enable(struct clk *clk)
268{
269 void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
270
271 if (clk->prcc_kernel != -1)
272 writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
273
274 if (clk->prcc_bus != -1)
275 writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
276}
277
278static void clk_prcc_disable(struct clk *clk)
279{
280 void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
281
282 if (clk->prcc_bus != -1)
283 writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
284
285 if (clk->prcc_kernel != -1)
286 writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
287}
288
289static struct clkops clk_prcc_ops = {
290 .enable = clk_prcc_enable,
291 .disable = clk_prcc_disable,
292};
293
294static struct clk clk_32khz = {
Vincent Guittot763eef82010-12-03 18:18:39 +0100295 .name = "clk_32khz",
Rabin Vincent1df20af2010-03-01 05:07:47 +0100296 .rate = 32000,
297};
298
299/*
300 * PRCMU level clock gating
301 */
302
303/* Bank 0 */
304static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK);
305static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK);
306static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK);
307static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
308static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
309static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
310static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
311static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000);
312static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
313static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
314static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
315static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK);
316static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK);
317static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000);
318static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000);
319static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK);
320static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK);
321static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK);
322static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK);
323static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK);
324static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK);
325static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK);
326static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK);
327static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK);
328static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */
329static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK);
330static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK);
331static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK);
332static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */
333static DEFINE_PRCMU_CLK_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* v1 */
334
335/* Bank 1 */
336static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */
337static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
338
339/*
340 * PRCC level clock gating
341 * Format: per#, clk, PCKEN bit, KCKEN bit, parent
342 */
343
344/* Peripheral Cluster #1 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530345static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100346static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530347static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
348static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
349static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
350static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100351static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530352static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
353static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
354static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
355static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
356static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
357static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100358
359/* Peripheral Cluster #2 */
360
361static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530362static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
363static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
364static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
365static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
366static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
367static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
368static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100369static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530370static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
371static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
372static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100373
374static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530375static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
376static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
377static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
378static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
379static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
380static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
381static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100382static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530383static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
384static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
385static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100386
387/* Peripheral Cluster #3 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530388static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
389static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
390static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
391static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
392static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
393static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
394static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
395static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
396static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
397static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
398static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100399
400/* Peripheral Cluster #4 is in the always on domain */
401
402/* Peripheral Cluster #5 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530403static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
404static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
405static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100406
407/* Peripheral Cluster #6 */
408
Linus Walleijba327b12010-05-26 07:38:54 +0100409/* MTU ID in data */
410static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
411static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530412static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
413static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
414static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
415static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
416static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
417static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
418static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
419static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
420static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
421static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100422
423/* Peripheral Cluster #7 */
424
Sundar Iyer592b2f22010-12-03 20:35:52 +0530425static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
Linus Walleijba327b12010-05-26 07:38:54 +0100426/* MTU ID in data */
427static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
428static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
Sundar Iyer592b2f22010-12-03 20:35:52 +0530429static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
430static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
Rabin Vincent1df20af2010-03-01 05:07:47 +0100431
Vincent Guittot763eef82010-12-03 18:18:39 +0100432static struct clk clk_dummy_apb_pclk = {
433 .name = "apb_pclk",
434};
Russell King3126c7b2010-07-15 11:01:17 +0100435
Rabin Vincent1df20af2010-03-01 05:07:47 +0100436static struct clk_lookup u8500_common_clks[] = {
Russell King3126c7b2010-07-15 11:01:17 +0100437 CLK(dummy_apb_pclk, NULL, "apb_pclk"),
438
Rabin Vincent1df20af2010-03-01 05:07:47 +0100439 /* Peripheral Cluster #1 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100440 CLK(gpio0, "gpio.0", NULL),
441 CLK(gpio0, "gpio.1", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100442 CLK(slimbus0, "slimbus0", NULL),
443 CLK(i2c2, "nmk-i2c.2", NULL),
444 CLK(sdi0, "sdi0", NULL),
445 CLK(msp0, "msp0", NULL),
446 CLK(i2c1, "nmk-i2c.1", NULL),
447 CLK(uart1, "uart1", NULL),
448 CLK(uart0, "uart0", NULL),
449
450 /* Peripheral Cluster #3 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100451 CLK(gpio2, "gpio.2", NULL),
452 CLK(gpio2, "gpio.3", NULL),
453 CLK(gpio2, "gpio.4", NULL),
454 CLK(gpio2, "gpio.5", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100455 CLK(sdi5, "sdi5", NULL),
456 CLK(uart2, "uart2", NULL),
457 CLK(ske, "ske", NULL),
Sundar Iyer4c61c842010-09-29 19:43:09 -0700458 CLK(ske, "nmk-ske-keypad", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100459 CLK(sdi2, "sdi2", NULL),
460 CLK(i2c0, "nmk-i2c.0", NULL),
461 CLK(fsmc, "fsmc", NULL),
462
463 /* Peripheral Cluster #5 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100464 CLK(gpio3, "gpio.8", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100465
466 /* Peripheral Cluster #6 */
467 CLK(hash1, "hash1", NULL),
468 CLK(pka, "pka", NULL),
469 CLK(hash0, "hash0", NULL),
470 CLK(cryp0, "cryp0", NULL),
471
472 /* PRCMU level clock gating */
473
474 /* Bank 0 */
475 CLK(svaclk, "sva", NULL),
476 CLK(siaclk, "sia", NULL),
477 CLK(sgaclk, "sga", NULL),
478 CLK(slimclk, "slim", NULL),
479 CLK(lcdclk, "lcd", NULL),
480 CLK(bmlclk, "bml", NULL),
481 CLK(hsitxclk, "stm-hsi.0", NULL),
482 CLK(hsirxclk, "stm-hsi.1", NULL),
483 CLK(hdmiclk, "hdmi", NULL),
484 CLK(apeatclk, "apeat", NULL),
485 CLK(apetraceclk, "apetrace", NULL),
486 CLK(mcdeclk, "mcde", NULL),
487 CLK(ipi2clk, "ipi2", NULL),
Linus Walleij7b8ddb02010-05-27 15:21:26 -0700488 CLK(dmaclk, "dma40.0", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100489 CLK(b2r2clk, "b2r2", NULL),
490 CLK(tvclk, "tv", NULL),
491};
492
493static struct clk_lookup u8500_ed_clks[] = {
494 /* Peripheral Cluster #1 */
495 CLK(spi3_ed, "spi3", NULL),
496 CLK(msp1_ed, "msp1", NULL),
497
498 /* Peripheral Cluster #2 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100499 CLK(gpio1_ed, "gpio.6", NULL),
500 CLK(gpio1_ed, "gpio.7", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100501 CLK(ssitx_ed, "ssitx", NULL),
502 CLK(ssirx_ed, "ssirx", NULL),
503 CLK(spi0_ed, "spi0", NULL),
504 CLK(sdi3_ed, "sdi3", NULL),
505 CLK(sdi1_ed, "sdi1", NULL),
506 CLK(msp2_ed, "msp2", NULL),
507 CLK(sdi4_ed, "sdi4", NULL),
508 CLK(pwl_ed, "pwl", NULL),
509 CLK(spi1_ed, "spi1", NULL),
510 CLK(spi2_ed, "spi2", NULL),
511 CLK(i2c3_ed, "nmk-i2c.3", NULL),
512
513 /* Peripheral Cluster #3 */
514 CLK(ssp1_ed, "ssp1", NULL),
515 CLK(ssp0_ed, "ssp0", NULL),
516
517 /* Peripheral Cluster #5 */
518 CLK(usb_ed, "musb_hdrc.0", "usb"),
519
520 /* Peripheral Cluster #6 */
521 CLK(dmc_ed, "dmc", NULL),
522 CLK(cryp1_ed, "cryp1", NULL),
523 CLK(rng_ed, "rng", NULL),
524
525 /* Peripheral Cluster #7 */
526 CLK(tzpc0_ed, "tzpc0", NULL),
527 CLK(mtu1_ed, "mtu1", NULL),
528 CLK(mtu0_ed, "mtu0", NULL),
529 CLK(wdg_ed, "wdg", NULL),
530 CLK(cfgreg_ed, "cfgreg", NULL),
531};
532
533static struct clk_lookup u8500_v1_clks[] = {
534 /* Peripheral Cluster #1 */
Sundar Iyer592b2f22010-12-03 20:35:52 +0530535 CLK(i2c4, "nmk-i2c.4", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100536 CLK(spi3_v1, "spi3", NULL),
537 CLK(msp1_v1, "msp1", NULL),
538
539 /* Peripheral Cluster #2 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100540 CLK(gpio1_v1, "gpio.6", NULL),
541 CLK(gpio1_v1, "gpio.7", NULL),
Rabin Vincent1df20af2010-03-01 05:07:47 +0100542 CLK(ssitx_v1, "ssitx", NULL),
543 CLK(ssirx_v1, "ssirx", NULL),
544 CLK(spi0_v1, "spi0", NULL),
545 CLK(sdi3_v1, "sdi3", NULL),
546 CLK(sdi1_v1, "sdi1", NULL),
547 CLK(msp2_v1, "msp2", NULL),
548 CLK(sdi4_v1, "sdi4", NULL),
549 CLK(pwl_v1, "pwl", NULL),
550 CLK(spi1_v1, "spi1", NULL),
551 CLK(spi2_v1, "spi2", NULL),
552 CLK(i2c3_v1, "nmk-i2c.3", NULL),
553
554 /* Peripheral Cluster #3 */
555 CLK(ssp1_v1, "ssp1", NULL),
556 CLK(ssp0_v1, "ssp0", NULL),
557
558 /* Peripheral Cluster #5 */
559 CLK(usb_v1, "musb_hdrc.0", "usb"),
560
561 /* Peripheral Cluster #6 */
562 CLK(mtu1_v1, "mtu1", NULL),
563 CLK(mtu0_v1, "mtu0", NULL),
564 CLK(cfgreg_v1, "cfgreg", NULL),
565 CLK(hash1, "hash1", NULL),
566 CLK(unipro_v1, "unipro", NULL),
567 CLK(rng_v1, "rng", NULL),
568
569 /* PRCMU level clock gating */
570
571 /* Bank 0 */
572 CLK(uniproclk, "uniproclk", NULL),
573 CLK(dsialtclk, "dsialt", NULL),
574
575 /* Bank 1 */
576 CLK(rngclk, "rng", NULL),
577 CLK(uiccclk, "uicc", NULL),
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100578};
579
Vincent Guittot763eef82010-12-03 18:18:39 +0100580#ifdef CONFIG_DEBUG_FS
581/*
582 * debugfs support to trace clock tree hierarchy and attributes with
583 * powerdebug
584 */
585static struct dentry *clk_debugfs_root;
586
587void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
588{
589 while (num--) {
590 /* Check that the clock has not been already registered */
591 if (!(cl->clk->list.prev != cl->clk->list.next))
592 list_add_tail(&cl->clk->list, &clk_list);
593
594 cl++;
595 }
596}
597
598static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
599 size_t size, loff_t *off)
600{
601 struct clk *clk = file->f_dentry->d_inode->i_private;
602 char cusecount[128];
603 unsigned int len;
604
605 len = sprintf(cusecount, "%u\n", clk->enabled);
606 return simple_read_from_buffer(buf, size, off, cusecount, len);
607}
608
609static ssize_t rate_dbg_read(struct file *file, char __user *buf,
610 size_t size, loff_t *off)
611{
612 struct clk *clk = file->f_dentry->d_inode->i_private;
613 char crate[128];
614 unsigned int rate;
615 unsigned int len;
616
617 rate = clk_get_rate(clk);
618 len = sprintf(crate, "%u\n", rate);
619 return simple_read_from_buffer(buf, size, off, crate, len);
620}
621
622static const struct file_operations usecount_fops = {
623 .read = usecount_dbg_read,
624};
625
626static const struct file_operations set_rate_fops = {
627 .read = rate_dbg_read,
628};
629
630static struct dentry *clk_debugfs_register_dir(struct clk *c,
631 struct dentry *p_dentry)
632{
633 struct dentry *d, *clk_d, *child, *child_tmp;
634 char s[255];
635 char *p = s;
636
637 if (c->name == NULL)
638 p += sprintf(p, "BUG");
639 else
640 p += sprintf(p, "%s", c->name);
641
642 clk_d = debugfs_create_dir(s, p_dentry);
643 if (!clk_d)
644 return NULL;
645
646 d = debugfs_create_file("usecount", S_IRUGO,
647 clk_d, c, &usecount_fops);
648 if (!d)
649 goto err_out;
650 d = debugfs_create_file("rate", S_IRUGO,
651 clk_d, c, &set_rate_fops);
652 if (!d)
653 goto err_out;
654 /*
655 * TODO : not currently available in ux500
656 * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
657 * if (!d)
658 * goto err_out;
659 */
660
661 return clk_d;
662
663err_out:
664 d = clk_d;
665 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
666 debugfs_remove(child);
667 debugfs_remove(clk_d);
668 return NULL;
669}
670
671static void clk_debugfs_remove_dir(struct dentry *cdentry)
672{
673 struct dentry *d, *child, *child_tmp;
674
675 d = cdentry;
676 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
677 debugfs_remove(child);
678 debugfs_remove(cdentry);
679 return ;
680}
681
682static int clk_debugfs_register_one(struct clk *c)
683{
684 struct clk *pa = c->parent_periph;
685 struct clk *bpa = c->parent_cluster;
686
687 if (!(bpa && !pa)) {
688 c->dent = clk_debugfs_register_dir(c,
689 pa ? pa->dent : clk_debugfs_root);
690 if (!c->dent)
691 return -ENOMEM;
692 }
693
694 if (bpa) {
695 c->dent_bus = clk_debugfs_register_dir(c,
696 bpa->dent_bus ? bpa->dent_bus : bpa->dent);
697 if ((!c->dent_bus) && (c->dent)) {
698 clk_debugfs_remove_dir(c->dent);
699 c->dent = NULL;
700 return -ENOMEM;
701 }
702 }
703 return 0;
704}
705
706static int clk_debugfs_register(struct clk *c)
707{
708 int err;
709 struct clk *pa = c->parent_periph;
710 struct clk *bpa = c->parent_cluster;
711
712 if (pa && (!pa->dent && !pa->dent_bus)) {
713 err = clk_debugfs_register(pa);
714 if (err)
715 return err;
716 }
717
718 if (bpa && (!bpa->dent && !bpa->dent_bus)) {
719 err = clk_debugfs_register(bpa);
720 if (err)
721 return err;
722 }
723
724 if ((!c->dent) && (!c->dent_bus)) {
725 err = clk_debugfs_register_one(c);
726 if (err)
727 return err;
728 }
729 return 0;
730}
731
732static int __init clk_debugfs_init(void)
733{
734 struct clk *c;
735 struct dentry *d;
736 int err;
737
738 d = debugfs_create_dir("clock", NULL);
739 if (!d)
740 return -ENOMEM;
741 clk_debugfs_root = d;
742
743 list_for_each_entry(c, &clk_list, list) {
744 err = clk_debugfs_register(c);
745 if (err)
746 goto err_out;
747 }
748 return 0;
749err_out:
750 debugfs_remove_recursive(clk_debugfs_root);
751 return err;
752}
753
754late_initcall(clk_debugfs_init);
755#endif /* defined(CONFIG_DEBUG_FS) */
756
Linus Walleijba327b12010-05-26 07:38:54 +0100757int __init clk_init(void)
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100758{
Rabin Vincent1df20af2010-03-01 05:07:47 +0100759 if (cpu_is_u8500ed()) {
760 clk_prcmu_ops.enable = clk_prcmu_ed_enable;
761 clk_prcmu_ops.disable = clk_prcmu_ed_disable;
Linus Walleijba327b12010-05-26 07:38:54 +0100762 clk_per6clk.rate = 100000000;
Rabin Vincent591d8dd2010-05-03 08:46:51 +0100763 } else if (cpu_is_u5500()) {
764 /* Clock tree for U5500 not implemented yet */
765 clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
766 clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
Per Forlinbab263e2010-12-05 12:49:03 +0100767 clk_uartclk.rate = 36360000;
768 clk_sdmmcclk.rate = 99900000;
Rabin Vincent1df20af2010-03-01 05:07:47 +0100769 }
770
771 clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
772 if (cpu_is_u8500ed())
773 clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
774 else
775 clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
776
Vincent Guittot763eef82010-12-03 18:18:39 +0100777#ifdef CONFIG_DEBUG_FS
778 clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
779 if (cpu_is_u8500ed())
780 clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
781 else
782 clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
783#endif
Srinidhi Kasagarc6b503c2009-11-28 08:15:01 +0100784 return 0;
785}