aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-ux500/clock.c
diff options
context:
space:
mode:
authorMian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>2010-05-10 18:08:53 +0200
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:44:36 -0600
commit3ea2f3a7cd8e2d470bdaba599efb57968d7114a6 (patch)
treec84adc3431887fb0b515ec5265e86905c3cef0f5 /arch/arm/mach-ux500/clock.c
parent747e3fcf01bb45034fe21512fe244d175559b493 (diff)
ux500: move mach-u8500 to mach-ux500
Diffstat (limited to 'arch/arm/mach-ux500/clock.c')
-rwxr-xr-xarch/arm/mach-ux500/clock.c724
1 files changed, 724 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
new file mode 100755
index 00000000000..5f84994e3ab
--- /dev/null
+++ b/arch/arm/mach-ux500/clock.c
@@ -0,0 +1,724 @@
+/*
+ * linux/arch/arm/mach-u8500/clock.c
+ *
+ * Copyright (C) ST Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/clkdev.h>
+#include <asm/io.h>
+
+#include <mach/hardware.h>
+#include <mach/prcmu-regs.h>
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clocks_lock);
+
+static void __clk_enable(struct clk *clk)
+{
+ if (clk->enabled++ == 0) {
+ if (clk->parent_cluster)
+ __clk_enable(clk->parent_cluster);
+
+ if (clk->parent_periph)
+ __clk_enable(clk->parent_periph);
+
+ if (clk->ops && clk->ops->enable)
+ clk->ops->enable(clk);
+ }
+}
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk || IS_ERR(clk))
+ return -EINVAL;
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ __clk_enable(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void __clk_disable(struct clk *clk)
+{
+ if (--clk->enabled == 0) {
+ if (clk->ops && clk->ops->disable)
+ clk->ops->disable(clk);
+
+ if (clk->parent_periph)
+ __clk_disable(clk->parent_periph);
+
+ if (clk->parent_cluster)
+ __clk_disable(clk->parent_cluster);
+ }
+}
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk || IS_ERR(clk))
+ return;
+
+ WARN_ON(!clk->enabled);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ if (clk->ops && clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+
+ rate = clk->rate;
+ if (!rate) {
+ if (clk->parent_periph)
+ rate = clk_get_rate(clk->parent_periph);
+ else if (clk->parent_cluster)
+ rate = clk_get_rate(clk->parent_cluster);
+ }
+
+ return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static void clk_prcmu_enable(struct clk *clk)
+{
+ void __iomem *cg_set_reg = (void __iomem *)PRCM_YYCLKEN0_MGT_SET
+ + clk->prcmu_cg_off;
+
+ writel(1 << clk->prcmu_cg_bit, cg_set_reg);
+}
+
+static void clk_prcmu_disable(struct clk *clk)
+{
+ void __iomem *cg_clr_reg = (void __iomem *)PRCM_YYCLKEN0_MGT_CLR
+ + clk->prcmu_cg_off;
+
+ writel(1 << clk->prcmu_cg_bit, cg_clr_reg);
+}
+
+/* ED doesn't have the combined set/clr registers */
+
+static void clk_prcmu_ed_enable(struct clk *clk)
+{
+ unsigned int val = readl(clk->prcmu_cg_mgt);
+
+ val |= 1 << 8;
+ writel(val, clk->prcmu_cg_mgt);
+}
+
+static void clk_prcmu_ed_disable(struct clk *clk)
+{
+ unsigned int val = readl(clk->prcmu_cg_mgt);
+
+ val &= ~(1 << 8);
+ writel(val, clk->prcmu_cg_mgt);
+}
+
+static struct clkops clk_prcmu_ops = {
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+};
+
+static void clk_prcc_enable(struct clk *clk)
+{
+ if (clk->prcc_kernel != -1)
+ writel(1 << (clk->prcc_kernel), clk->prcc_base + 0x8);
+
+ if (clk->prcc_bus != -1)
+ writel(1 << (clk->prcc_bus), clk->prcc_base + 0x0);
+}
+
+static void clk_prcc_disable(struct clk *clk)
+{
+ if (clk->prcc_bus != -1)
+ writel(1 << (clk->prcc_bus), clk->prcc_base + 0x4);
+
+ if (clk->prcc_kernel != -1)
+ writel(1 << (clk->prcc_kernel), clk->prcc_base + 0xc);
+}
+
+static struct clkops clk_prcc_ops = {
+ .enable = clk_prcc_enable,
+ .disable = clk_prcc_disable,
+};
+
+static struct clk clk_32khz = {
+ .rate = 32000,
+};
+
+/*
+ * PRCMU level clock gating
+ */
+
+/* Bank 0 */
+static DEFINE_PRCMU_CLK(svaclk, 0x0, 2, SVAMMDSPCLK);
+static DEFINE_PRCMU_CLK(siaclk, 0x0, 3, SIAMMDSPCLK);
+static DEFINE_PRCMU_CLK(sgaclk, 0x0, 4, SGACLK);
+static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
+static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
+static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
+static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
+static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000);
+static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
+static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
+static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
+static DEFINE_PRCMU_CLK(per3clk, 0x0, 13, PER3CLK);
+static DEFINE_PRCMU_CLK(per5clk, 0x0, 14, PER5CLK);
+static DEFINE_PRCMU_CLK_RATE(per6clk, 0x0, 15, PER6CLK, 133330000);
+static DEFINE_PRCMU_CLK_RATE(per7clk, 0x0, 16, PER7CLK, 100000000);
+static DEFINE_PRCMU_CLK(lcdclk, 0x0, 17, LCDCLK);
+static DEFINE_PRCMU_CLK(bmlclk, 0x0, 18, BMLCLK);
+static DEFINE_PRCMU_CLK(hsitxclk, 0x0, 19, HSITXCLK);
+static DEFINE_PRCMU_CLK(hsirxclk, 0x0, 20, HSIRXCLK);
+static DEFINE_PRCMU_CLK(hdmiclk, 0x0, 21, HDMICLK);
+static DEFINE_PRCMU_CLK(apeatclk, 0x0, 22, APEATCLK);
+static DEFINE_PRCMU_CLK(apetraceclk, 0x0, 23, APETRACECLK);
+static DEFINE_PRCMU_CLK(mcdeclk, 0x0, 24, MCDECLK);
+static DEFINE_PRCMU_CLK(ipi2clk, 0x0, 25, IPI2CCLK);
+static DEFINE_PRCMU_CLK(dsialtclk, 0x0, 26, DSIALTCLK); /* v1 */
+static DEFINE_PRCMU_CLK(dmaclk, 0x0, 27, DMACLK);
+static DEFINE_PRCMU_CLK(b2r2clk, 0x0, 28, B2R2CLK);
+static DEFINE_PRCMU_CLK(tvclk, 0x0, 29, TVCLK);
+static DEFINE_PRCMU_CLK(uniproclk, 0x0, 30, UNIPROCLK); /* v1 */
+static DEFINE_PRCMU_CLK(sspclk, 0x0, 31, SSPCLK); /* v1 */
+
+/* Bank 1 */
+static DEFINE_PRCMU_CLK(rngclk, 0x4, 0, RNGCLK); /* v1 */
+static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
+
+/*
+ * PRCC level clock gating
+ * Format: per#, clk, PCKEN bit, KCKEN bit, parent
+ */
+
+/* Peripheral Cluster #1 */
+static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
+static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
+static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
+static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
+static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
+static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
+static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
+static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
+static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
+static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
+static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
+static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
+
+/* Peripheral Cluster #2 */
+
+static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL);
+static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
+static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
+static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
+static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
+static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL);
+static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
+static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
+static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
+
+static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL);
+static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
+static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
+static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
+static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
+static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL);
+static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
+static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
+static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
+
+/* Peripheral Cluster #3 */
+static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
+static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
+static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
+static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
+static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
+static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
+static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
+static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
+static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
+static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
+
+/* Peripheral Cluster #4 is in the always on domain */
+
+/* Peripheral Cluster #5 */
+static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
+static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
+static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
+
+/* Peripheral Cluster #6 */
+
+static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL);
+static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL);
+static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
+static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
+static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
+static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
+static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
+static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
+static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
+static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
+static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
+static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
+
+/* Peripheral Cluster #7 */
+
+static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
+static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL);
+static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL);
+static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
+static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
+
+/*
+ * TODO: Ensure names match with devices and then remove unnecessary entries
+ * when all drivers use the clk API.
+ */
+
+static struct clk_lookup u8500_common_clkregs[] = {
+ /* Peripheral Cluster #1 */
+ CLK(gpio0, "gpioblock0", NULL),
+ CLK(slimbus0, "slimbus0", NULL),
+ CLK(i2c2, "STM-I2C.2", NULL),
+ CLK(sdi0, NULL, "MMC"), /* remove */
+ CLK(sdi0, "sdi0", NULL),
+ CLK(msp0, "msp0", NULL),
+ CLK(msp0, "MSP_I2S.0", NULL),
+ CLK(i2c1, "STM-I2C.1", NULL),
+ CLK(uart1, "uart1", NULL),
+ CLK(uart0, "uart0", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(gpio2, "gpioblock2", NULL),
+ CLK(sdi5, "sdi5", NULL),
+ CLK(uart2, "uart2", NULL),
+ CLK(ske, "ske", NULL),
+ CLK(sdi2, "sdi2", NULL),
+ CLK(i2c0, "STM-I2C.0", NULL),
+ CLK(fsmc, "fsmc", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(gpio3, "gpioblock3", NULL),
+
+ /* Peripheral Cluster #6 */
+ CLK(hash1, "hash1", NULL),
+ CLK(pka, "pka", NULL),
+ CLK(hash0, "hash0", NULL),
+ CLK(cryp0, "cryp0", NULL),
+
+ /*
+ * PRCMU level clock gating
+ */
+
+ /* Bank 0 */
+ CLK(svaclk, "sva", NULL),
+ CLK(siaclk, "sia", NULL),
+ CLK(sgaclk, "sga", NULL),
+ CLK(uartclk, "UART", NULL),
+ CLK(msp02clk, "MSP02", NULL),
+ CLK(i2cclk, "I2C", NULL),
+ CLK(sdmmcclk, "sdmmc", NULL),
+ CLK(slimclk, "SLIM", NULL),
+ CLK(per1clk, "PERIPH1", NULL),
+ CLK(per2clk, "PERIPH2", NULL),
+ CLK(per3clk, "PERIPH3", NULL),
+ CLK(per5clk, "PERIPH5", NULL),
+ CLK(per6clk, "PERIPH6", NULL),
+ CLK(per7clk, "PERIPH7", NULL),
+ CLK(lcdclk, "lcd", NULL),
+ CLK(bmlclk, "bml", NULL),
+ CLK(hsitxclk, "stm-hsi.0", NULL),
+ CLK(hsirxclk, "stm-hsi.1", NULL),
+ CLK(hdmiclk, "hdmi", NULL),
+ CLK(apeatclk, "apeat", NULL),
+ CLK(apetraceclk, "apetrace", NULL),
+ CLK(mcdeclk, "mcde", NULL),
+ CLK(ipi2clk, "ipi2", NULL),
+ CLK(dmaclk, "STM-DMA.0", NULL),
+ CLK(b2r2clk, "b2r2", NULL),
+ CLK(tvclk, "tv", NULL),
+
+ /* With device names */
+
+ CLK(mcdeclk, "U8500-MCDE.0", "mcde"),
+ CLK(hdmiclk, "U8500-MCDE.0", "hdmi"),
+ CLK(tvclk, "U8500-MCDE.0", "tv"),
+ CLK(lcdclk, "U8500-MCDE.0", "lcd"),
+ CLK(mcdeclk, "U8500-MCDE.1", "mcde"),
+ CLK(hdmiclk, "U8500-MCDE.1", "hdmi"),
+ CLK(tvclk, "U8500-MCDE.1", "tv"),
+ CLK(lcdclk, "U8500-MCDE.1", "lcd"),
+ CLK(mcdeclk, "U8500-MCDE.2", "mcde"),
+ CLK(hdmiclk, "U8500-MCDE.2", "hdmi"),
+ CLK(tvclk, "U8500-MCDE.2", "tv"),
+ CLK(lcdclk, "U8500-MCDE.2", "lcd"),
+ CLK(mcdeclk, "U8500-MCDE.3", "mcde"),
+ CLK(hdmiclk, "U8500-MCDE.3", "hdmi"),
+ CLK(tvclk, "U8500-MCDE.3", "tv"),
+ CLK(lcdclk, "U8500-MCDE.3", "lcd"),
+ CLK(b2r2clk, "U8500-B2R2.0", NULL),
+};
+
+static struct clk_lookup u8500_ed_clkregs[] = {
+ /* Peripheral Cluster #1 */
+ CLK(spi3_ed, "spi3", NULL),
+ CLK(msp1_ed, "msp1", NULL),
+ CLK(msp1_ed, "MSP_I2S.1", NULL),
+
+ /* Peripheral Cluster #2 */
+ CLK(gpio1_ed, "gpioblock1", NULL),
+ CLK(ssitx_ed, "ssitx", NULL),
+ CLK(ssirx_ed, "ssirx", NULL),
+ CLK(spi0_ed, "spi0", NULL),
+ CLK(sdi3_ed, "sdi3", NULL),
+ CLK(sdi1_ed, "sdi1", NULL),
+ CLK(msp2_ed, "msp2", NULL),
+ CLK(msp2_ed, "MSP_I2S.2", NULL),
+ CLK(sdi4_ed, NULL, "EMMC"), /* remove */
+ CLK(sdi4_ed, "sdi4", NULL),
+ CLK(pwl_ed, "pwl", NULL),
+ CLK(spi1_ed, "spi1", NULL),
+ CLK(spi2_ed, "spi2", NULL),
+ CLK(i2c3_ed, "STM-I2C.3", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(ssp1_ed, "ssp1", NULL),
+ CLK(ssp0_ed, "ssp0", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(usb_ed, "musb_hdrc.0", "usb"),
+
+ /* Peripheral Cluster #6 */
+ CLK(dmc_ed, "dmc", NULL),
+ CLK(cryp1_ed, "cryp1", NULL),
+ CLK(rng_ed, "rng", NULL),
+
+ /* Peripheral Cluster #7 */
+ CLK(tzpc0_ed, "tzpc0", NULL),
+ CLK(mtu1_ed, "mtu1", NULL),
+ CLK(mtu0_ed, "mtu0", NULL),
+ CLK(wdg_ed, "wdg", NULL),
+ CLK(cfgreg_ed, "cfgreg", NULL),
+};
+
+static struct clk_lookup u8500_v1_clkregs[] = {
+ /* Peripheral Cluster #1 */
+ CLK(i2c4, "STM-I2C.4", NULL),
+ CLK(spi3_v1, "spi3", NULL),
+ CLK(msp1_v1, "msp1", NULL),
+ CLK(msp1_v1, "MSP_I2S.1", NULL),
+
+ /* Peripheral Cluster #2 */
+ CLK(gpio1_v1, "gpioblock1", NULL),
+ CLK(ssitx_v1, "ssitx", NULL),
+ CLK(ssirx_v1, "ssirx", NULL),
+ CLK(spi0_v1, "spi0", NULL),
+ CLK(sdi3_v1, "sdi3", NULL),
+ CLK(sdi1_v1, "sdi1", NULL),
+ CLK(msp2_v1, "msp2", NULL),
+ CLK(msp2_v1, "MSP_I2S.2", NULL),
+ CLK(sdi4_v1, NULL, "EMMC"), /* remove */
+ CLK(sdi4_v1, "sdi4", NULL),
+ CLK(pwl_v1, "pwl", NULL),
+ CLK(spi1_v1, "spi1", NULL),
+ CLK(spi2_v1, "spi2", NULL),
+ CLK(i2c3_v1, "STM-I2C.3", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(ssp1_v1, "ssp1", NULL),
+ CLK(ssp0_v1, "ssp0", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(usb_v1, "musb_hdrc.0", "usb"),
+
+ /* Peripheral Cluster #6 */
+ CLK(mtu1_v1, "mtu1", NULL),
+ CLK(mtu0_v1, "mtu0", NULL),
+ CLK(cfgreg_v1, "cfgreg", NULL),
+ CLK(hash1, "hash1", NULL),
+ CLK(unipro_v1, "unipro", NULL),
+ CLK(rng_v1, "rng", NULL),
+
+ /*
+ * PRCMU level clock gating
+ */
+
+ /* Bank 0 */
+ CLK(msp1clk, "MSP1", NULL),
+ CLK(uniproclk, "uniproclk", NULL),
+ CLK(sspclk, "SSP", NULL),
+ CLK(dsialtclk, "dsialt", NULL),
+
+ /* Bank 1 */
+ CLK(rngclk, "rng", NULL),
+ CLK(uiccclk, "uicc", NULL),
+};
+
+static void clk_register(struct clk *clk);
+
+static void clks_register(struct clk_lookup *clks, size_t num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ clkdev_add(&clks[i]);
+ clk_register(clks[i].clk);
+ }
+}
+
+/* these are the clocks which are default from the bootloader */
+static const char *u8500_boot_clk[] = {
+ "uart0",
+ "uart1",
+ "uart2",
+ "gpio0",
+ "gpio1",
+ "gpio2",
+ "gpio3",
+ "mtu0",
+ "mtu1",
+ "ssp0",
+ "ssp1",
+ "spi0",
+ "spi1",
+ "spi2",
+ "spi3",
+ "msp0",
+ "msp1",
+ "msp2",
+ "msp3",
+ "i2c0",
+ "i2c1",
+ "i2c2",
+ "i2c3",
+ "i2c4"
+};
+
+struct clk *boot_clks[ARRAY_SIZE(u8500_boot_clk)];
+
+/* we disable a majority of peripherals enabled by default
+ * but without drivers
+ */
+static void __init u8500_boot_clk_disable(void)
+{
+ int i = 0;
+ for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) {
+ clk_disable(boot_clks[i]);
+ clk_put(boot_clks[i]);
+ }
+}
+late_initcall_sync(u8500_boot_clk_disable);
+
+static void u8500_amba_clk_enable(void)
+{
+ int i = 0;
+
+ writel(~0x0 & ~(1 << 9), IO_ADDRESS(U8500_PER1_BASE + 0xF000 + 0x04));
+ writel(~0x0, IO_ADDRESS(U8500_PER1_BASE + 0xF000 + 0x0C));
+
+ writel(~0x0 & ~(1 << 11), IO_ADDRESS(U8500_PER2_BASE + 0xF000 + 0x04));
+ writel(~0x0, IO_ADDRESS(U8500_PER2_BASE + 0xF000 + 0x0C));
+
+ /*GPIO,UART2 are enabled for booting*/
+ writel(0xBF, IO_ADDRESS(U8500_PER3_BASE + 0xF000 + 0x04));
+ writel(~0x0 & ~(1 << 6), IO_ADDRESS(U8500_PER3_BASE + 0xF000 + 0x0C));
+
+ /* enable AMBA configuration clock ONLY */
+ writel(~0x0, IO_ADDRESS(U8500_PER6_BASE + 0xF000 + 0x04));
+ writel(~0x0, IO_ADDRESS(U8500_PER6_BASE + 0xF000 + 0x0C));
+
+ for (i = 0; i < ARRAY_SIZE(u8500_boot_clk); i++) {
+ boot_clks[i] = clk_get_sys(u8500_boot_clk[i], NULL);
+ clk_enable(boot_clks[i]);
+ }
+}
+
+int __init clk_init(void)
+{
+ if (cpu_is_u8500ed()) {
+ clk_prcmu_ops.enable = clk_prcmu_ed_enable;
+ clk_prcmu_ops.disable = clk_prcmu_ed_disable;
+ } else if (cpu_is_u8500v1()) {
+ void __iomem *sdmmclkmgt = (void __iomem *) PRCM_SDMMCCLK_MGT;
+ unsigned int val;
+
+ /* Switch SDMMCCLK to 52Mhz instead of 104Mhz */
+ val = readl(sdmmclkmgt);
+ val = (val & ~0x1f) | 16;
+ writel(val, sdmmclkmgt);
+ } else if (cpu_is_u5500()) {
+ clk_prcmu_ops.enable = NULL;
+ clk_prcmu_ops.disable = NULL;
+ clk_prcc_ops.enable = NULL;
+ clk_prcc_ops.disable = NULL;
+ }
+
+ clks_register(u8500_common_clkregs, ARRAY_SIZE(u8500_common_clkregs));
+
+ if (cpu_is_u8500ed())
+ clks_register(u8500_ed_clkregs, ARRAY_SIZE(u8500_ed_clkregs));
+ else
+ clks_register(u8500_v1_clkregs, ARRAY_SIZE(u8500_v1_clkregs));
+
+ if (cpu_is_u8500() && !cpu_is_u8500ed())
+ u8500_amba_clk_enable();
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+static void clk_register(struct clk *clk)
+{
+ mutex_lock(&clocks_mutex);
+
+ /* Ignore duplicate clocks */
+ if (clk->list.prev != NULL || clk->list.next != NULL) {
+ mutex_unlock(&clocks_mutex);
+ return;
+ }
+
+ list_add(&clk->list, &clocks);
+ mutex_unlock(&clocks_mutex);
+}
+
+/*
+ * The following makes it possible to view the status (especially reference
+ * count and reset status) for the clocks in the platform by looking into the
+ * special file <debugfs>/u8500_clocks
+ */
+static void *u8500_clocks_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *u8500_clocks_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return NULL;
+}
+
+static void u8500_clocks_stop(struct seq_file *m, void *v)
+{
+}
+
+static int u8500_clocks_show(struct seq_file *m, void *v)
+{
+ struct clk *clk;
+
+ list_for_each_entry(clk, &clocks, list) {
+ struct clk *child;
+ bool first = true;
+
+ seq_printf(m, "%-11s %d", clk->name, clk->enabled);
+
+ list_for_each_entry(child, &clocks, list) {
+ if (!child->enabled)
+ continue;
+
+ if (child->parent_cluster == clk ||
+ child->parent_periph == clk) {
+ if (first) {
+ first = false;
+ seq_printf(m, "\t[active children:");
+ }
+
+ seq_printf(m, " %s", child->name);
+ }
+ }
+
+ seq_printf(m, "%s\n", first ? "" : "]");
+ }
+
+ printk(KERN_INFO "Periph1 PCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER1_BASE + 0xF000 + 0x10)));
+ printk(KERN_INFO "Periph1 KCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER1_BASE + 0xF000 + 0x14)));
+ printk(KERN_INFO "Periph2 PCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER2_BASE + 0xF000 + 0x10)));
+ printk(KERN_INFO "Periph2 KCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER2_BASE + 0xF000 + 0x14)));
+ printk(KERN_INFO "Periph3 PCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER3_BASE + 0xF000 + 0x10)));
+ printk(KERN_INFO "Periph3 KCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER3_BASE + 0xF000 + 0x14)));
+ printk(KERN_INFO "Periph5 PCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER5_BASE + 0x1F000 + 0x10)));
+ printk(KERN_INFO "Periph5 KCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER5_BASE + 0x1F000 + 0x14)));
+ printk(KERN_INFO "Periph6 PCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER6_BASE + 0xF000 + 0x10)));
+ printk(KERN_INFO "Periph6 KCKEN : 0x%x\n",
+ readl(IO_ADDRESS(U8500_PER6_BASE + 0xF000 + 0x14)));
+
+ return 0;
+}
+
+static const struct seq_operations u8500_clocks_op = {
+ .start = u8500_clocks_start,
+ .next = u8500_clocks_next,
+ .stop = u8500_clocks_stop,
+ .show = u8500_clocks_show
+};
+
+static int u8500_clocks_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &u8500_clocks_op);
+}
+
+static const struct file_operations u8500_clocks_operations = {
+ .open = u8500_clocks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init init_clk_read_debugfs(void)
+{
+ /* Expose a simple debugfs interface to view all clocks */
+ (void) debugfs_create_file("u8500_clocks", S_IFREG | S_IRUGO,
+ NULL, NULL, &u8500_clocks_operations);
+ return 0;
+}
+/*
+ * This needs to come in after the arch_initcall() for the
+ * overall clocks, because debugfs is not available until
+ * the subsystems come up.
+ */
+module_init(init_clk_read_debugfs);
+#else
+static void clk_register(struct clk *clk) { }
+#endif