aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ux500/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ux500/clock.c')
-rw-r--r--arch/arm/mach-ux500/clock.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
new file mode 100644
index 00000000..32ce9084
--- /dev/null
+++ b/arch/arm/mach-ux500/clock.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * 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/io.h>
+#include <linux/clkdev.h>
+
+#include <plat/mtu.h>
+#include <mach/hardware.h>
+#include "clock.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h> /* for copy_from_user */
+static LIST_HEAD(clk_list);
+#endif
+
+#define PRCC_PCKEN 0x00
+#define PRCC_PCKDIS 0x04
+#define PRCC_KCKEN 0x08
+#define PRCC_KCKDIS 0x0C
+
+#define PRCM_YYCLKEN0_MGT_SET 0x510
+#define PRCM_YYCLKEN1_MGT_SET 0x514
+#define PRCM_YYCLKEN0_MGT_CLR 0x518
+#define PRCM_YYCLKEN1_MGT_CLR 0x51C
+#define PRCM_YYCLKEN0_MGT_VAL 0x520
+#define PRCM_YYCLKEN1_MGT_VAL 0x524
+
+#define PRCM_SVAMMDSPCLK_MGT 0x008
+#define PRCM_SIAMMDSPCLK_MGT 0x00C
+#define PRCM_SGACLK_MGT 0x014
+#define PRCM_UARTCLK_MGT 0x018
+#define PRCM_MSP02CLK_MGT 0x01C
+#define PRCM_MSP1CLK_MGT 0x288
+#define PRCM_I2CCLK_MGT 0x020
+#define PRCM_SDMMCCLK_MGT 0x024
+#define PRCM_SLIMCLK_MGT 0x028
+#define PRCM_PER1CLK_MGT 0x02C
+#define PRCM_PER2CLK_MGT 0x030
+#define PRCM_PER3CLK_MGT 0x034
+#define PRCM_PER5CLK_MGT 0x038
+#define PRCM_PER6CLK_MGT 0x03C
+#define PRCM_PER7CLK_MGT 0x040
+#define PRCM_LCDCLK_MGT 0x044
+#define PRCM_BMLCLK_MGT 0x04C
+#define PRCM_HSITXCLK_MGT 0x050
+#define PRCM_HSIRXCLK_MGT 0x054
+#define PRCM_HDMICLK_MGT 0x058
+#define PRCM_APEATCLK_MGT 0x05C
+#define PRCM_APETRACECLK_MGT 0x060
+#define PRCM_MCDECLK_MGT 0x064
+#define PRCM_IPI2CCLK_MGT 0x068
+#define PRCM_DSIALTCLK_MGT 0x06C
+#define PRCM_DMACLK_MGT 0x074
+#define PRCM_B2R2CLK_MGT 0x078
+#define PRCM_TVCLK_MGT 0x07C
+#define PRCM_TCR 0x1C8
+#define PRCM_TCR_STOPPED (1 << 16)
+#define PRCM_TCR_DOZE_MODE (1 << 17)
+#define PRCM_UNIPROCLK_MGT 0x278
+#define PRCM_SSPCLK_MGT 0x280
+#define PRCM_RNGCLK_MGT 0x284
+#define PRCM_UICCCLK_MGT 0x27C
+
+#define PRCM_MGT_ENABLE (1 << 8)
+
+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;
+
+ 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;
+
+ WARN_ON(!clk->enabled);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+/*
+ * The MTU has a separate, rather complex muxing setup
+ * with alternative parents (peripheral cluster or
+ * ULP or fixed 32768 Hz) depending on settings
+ */
+static unsigned long clk_mtu_get_rate(struct clk *clk)
+{
+ void __iomem *addr;
+ u32 tcr;
+ int mtu = (int) clk->data;
+ /*
+ * One of these is selected eventually
+ * TODO: Replace the constant with a reference
+ * to the ULP source once this is modeled.
+ */
+ unsigned long clk32k = 32768;
+ unsigned long mturate;
+ unsigned long retclk;
+
+ if (cpu_is_u5500())
+ addr = __io_address(U5500_PRCMU_BASE);
+ else if (cpu_is_u8500())
+ addr = __io_address(U8500_PRCMU_BASE);
+ else
+ ux500_unknown_soc();
+
+ /*
+ * On a startup, always conifgure the TCR to the doze mode;
+ * bootloaders do it for us. Do this in the kernel too.
+ */
+ writel(PRCM_TCR_DOZE_MODE, addr + PRCM_TCR);
+
+ tcr = readl(addr + PRCM_TCR);
+
+ /* Get the rate from the parent as a default */
+ if (clk->parent_periph)
+ mturate = clk_get_rate(clk->parent_periph);
+ else if (clk->parent_cluster)
+ mturate = clk_get_rate(clk->parent_cluster);
+ else
+ /* We need to be connected SOMEWHERE */
+ BUG();
+
+ /* Return the clock selected for this MTU */
+ if (tcr & (1 << mtu))
+ retclk = clk32k;
+ else
+ retclk = mturate;
+
+ pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
+ return retclk;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ /*
+ * If there is a custom getrate callback for this clock,
+ * it will take precedence.
+ */
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
+ 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);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ /*TODO*/
+ return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ clk->rate = rate;
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+static void clk_prcmu_enable(struct clk *clk)
+{
+ void __iomem *cg_set_reg = __io_address(U8500_PRCMU_BASE)
+ + 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 = __io_address(U8500_PRCMU_BASE)
+ + 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)
+{
+ void __iomem *addr = __io_address(U8500_PRCMU_BASE)
+ + clk->prcmu_cg_mgt;
+
+ writel(readl(addr) | PRCM_MGT_ENABLE, addr);
+}
+
+static void clk_prcmu_ed_disable(struct clk *clk)
+{
+ void __iomem *addr = __io_address(U8500_PRCMU_BASE)
+ + clk->prcmu_cg_mgt;
+
+ writel(readl(addr) & ~PRCM_MGT_ENABLE, addr);
+}
+
+static struct clkops clk_prcmu_ops = {
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+};
+
+static unsigned int clkrst_base[] = {
+ [1] = U8500_CLKRST1_BASE,
+ [2] = U8500_CLKRST2_BASE,
+ [3] = U8500_CLKRST3_BASE,
+ [5] = U8500_CLKRST5_BASE,
+ [6] = U8500_CLKRST6_BASE,
+ [7] = U8500_CLKRST7_BASE_ED,
+};
+
+static void clk_prcc_enable(struct clk *clk)
+{
+ void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
+
+ if (clk->prcc_kernel != -1)
+ writel(1 << clk->prcc_kernel, addr + PRCC_KCKEN);
+
+ if (clk->prcc_bus != -1)
+ writel(1 << clk->prcc_bus, addr + PRCC_PCKEN);
+}
+
+static void clk_prcc_disable(struct clk *clk)
+{
+ void __iomem *addr = __io_address(clkrst_base[clk->cluster]);
+
+ if (clk->prcc_bus != -1)
+ writel(1 << clk->prcc_bus, addr + PRCC_PCKDIS);
+
+ if (clk->prcc_kernel != -1)
+ writel(1 << clk->prcc_kernel, addr + PRCC_KCKDIS);
+}
+
+static struct clkops clk_prcc_ops = {
+ .enable = clk_prcc_enable,
+ .disable = clk_prcc_disable,
+};
+
+static struct clk clk_32khz = {
+ .name = "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, 100000000);
+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_RATE(sspclk, 0x0, 31, SSPCLK, 48000000); /* 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 */
+
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
+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);
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
+static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
+static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
+
+static struct clk clk_dummy_apb_pclk = {
+ .name = "apb_pclk",
+};
+
+static struct clk_lookup u8500_common_clks[] = {
+ CLK(dummy_apb_pclk, NULL, "apb_pclk"),
+
+ /* Peripheral Cluster #1 */
+ CLK(gpio0, "gpio.0", NULL),
+ CLK(gpio0, "gpio.1", NULL),
+ CLK(slimbus0, "slimbus0", NULL),
+ CLK(i2c2, "nmk-i2c.2", NULL),
+ CLK(sdi0, "sdi0", NULL),
+ CLK(msp0, "msp0", NULL),
+ CLK(i2c1, "nmk-i2c.1", NULL),
+ CLK(uart1, "uart1", NULL),
+ CLK(uart0, "uart0", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(gpio2, "gpio.2", NULL),
+ CLK(gpio2, "gpio.3", NULL),
+ CLK(gpio2, "gpio.4", NULL),
+ CLK(gpio2, "gpio.5", NULL),
+ CLK(sdi5, "sdi5", NULL),
+ CLK(uart2, "uart2", NULL),
+ CLK(ske, "ske", NULL),
+ CLK(ske, "nmk-ske-keypad", NULL),
+ CLK(sdi2, "sdi2", NULL),
+ CLK(i2c0, "nmk-i2c.0", NULL),
+ CLK(fsmc, "fsmc", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(gpio3, "gpio.8", 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(slimclk, "slim", 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, "dma40.0", NULL),
+ CLK(b2r2clk, "b2r2", NULL),
+ CLK(tvclk, "tv", NULL),
+};
+
+static struct clk_lookup u8500_ed_clks[] = {
+ /* Peripheral Cluster #1 */
+ CLK(spi3_ed, "spi3", NULL),
+ CLK(msp1_ed, "msp1", NULL),
+
+ /* Peripheral Cluster #2 */
+ CLK(gpio1_ed, "gpio.6", NULL),
+ CLK(gpio1_ed, "gpio.7", 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(sdi4_ed, "sdi4", NULL),
+ CLK(pwl_ed, "pwl", NULL),
+ CLK(spi1_ed, "spi1", NULL),
+ CLK(spi2_ed, "spi2", NULL),
+ CLK(i2c3_ed, "nmk-i2c.3", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(ssp1_ed, "ssp1", NULL),
+ CLK(ssp0_ed, "ssp0", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(usb_ed, "musb-ux500.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_clks[] = {
+ /* Peripheral Cluster #1 */
+ CLK(i2c4, "nmk-i2c.4", NULL),
+ CLK(spi3_v1, "spi3", NULL),
+ CLK(msp1_v1, "msp1", NULL),
+
+ /* Peripheral Cluster #2 */
+ CLK(gpio1_v1, "gpio.6", NULL),
+ CLK(gpio1_v1, "gpio.7", 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(sdi4_v1, "sdi4", NULL),
+ CLK(pwl_v1, "pwl", NULL),
+ CLK(spi1_v1, "spi1", NULL),
+ CLK(spi2_v1, "spi2", NULL),
+ CLK(i2c3_v1, "nmk-i2c.3", NULL),
+
+ /* Peripheral Cluster #3 */
+ CLK(ssp1_v1, "ssp1", NULL),
+ CLK(ssp0_v1, "ssp0", NULL),
+
+ /* Peripheral Cluster #5 */
+ CLK(usb_v1, "musb-ux500.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(uniproclk, "uniproclk", NULL),
+ CLK(dsialtclk, "dsialt", NULL),
+
+ /* Bank 1 */
+ CLK(rngclk, "rng", NULL),
+ CLK(uiccclk, "uicc", NULL),
+};
+
+#ifdef CONFIG_DEBUG_FS
+/*
+ * debugfs support to trace clock tree hierarchy and attributes with
+ * powerdebug
+ */
+static struct dentry *clk_debugfs_root;
+
+void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
+{
+ while (num--) {
+ /* Check that the clock has not been already registered */
+ if (!(cl->clk->list.prev != cl->clk->list.next))
+ list_add_tail(&cl->clk->list, &clk_list);
+
+ cl++;
+ }
+}
+
+static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ struct clk *clk = file->f_dentry->d_inode->i_private;
+ char cusecount[128];
+ unsigned int len;
+
+ len = sprintf(cusecount, "%u\n", clk->enabled);
+ return simple_read_from_buffer(buf, size, off, cusecount, len);
+}
+
+static ssize_t rate_dbg_read(struct file *file, char __user *buf,
+ size_t size, loff_t *off)
+{
+ struct clk *clk = file->f_dentry->d_inode->i_private;
+ char crate[128];
+ unsigned int rate;
+ unsigned int len;
+
+ rate = clk_get_rate(clk);
+ len = sprintf(crate, "%u\n", rate);
+ return simple_read_from_buffer(buf, size, off, crate, len);
+}
+
+static const struct file_operations usecount_fops = {
+ .read = usecount_dbg_read,
+};
+
+static const struct file_operations set_rate_fops = {
+ .read = rate_dbg_read,
+};
+
+static struct dentry *clk_debugfs_register_dir(struct clk *c,
+ struct dentry *p_dentry)
+{
+ struct dentry *d, *clk_d, *child, *child_tmp;
+ char s[255];
+ char *p = s;
+
+ if (c->name == NULL)
+ p += sprintf(p, "BUG");
+ else
+ p += sprintf(p, "%s", c->name);
+
+ clk_d = debugfs_create_dir(s, p_dentry);
+ if (!clk_d)
+ return NULL;
+
+ d = debugfs_create_file("usecount", S_IRUGO,
+ clk_d, c, &usecount_fops);
+ if (!d)
+ goto err_out;
+ d = debugfs_create_file("rate", S_IRUGO,
+ clk_d, c, &set_rate_fops);
+ if (!d)
+ goto err_out;
+ /*
+ * TODO : not currently available in ux500
+ * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
+ * if (!d)
+ * goto err_out;
+ */
+
+ return clk_d;
+
+err_out:
+ d = clk_d;
+ list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(clk_d);
+ return NULL;
+}
+
+static void clk_debugfs_remove_dir(struct dentry *cdentry)
+{
+ struct dentry *d, *child, *child_tmp;
+
+ d = cdentry;
+ list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(cdentry);
+ return ;
+}
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+ struct clk *pa = c->parent_periph;
+ struct clk *bpa = c->parent_cluster;
+
+ if (!(bpa && !pa)) {
+ c->dent = clk_debugfs_register_dir(c,
+ pa ? pa->dent : clk_debugfs_root);
+ if (!c->dent)
+ return -ENOMEM;
+ }
+
+ if (bpa) {
+ c->dent_bus = clk_debugfs_register_dir(c,
+ bpa->dent_bus ? bpa->dent_bus : bpa->dent);
+ if ((!c->dent_bus) && (c->dent)) {
+ clk_debugfs_remove_dir(c->dent);
+ c->dent = NULL;
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+ int err;
+ struct clk *pa = c->parent_periph;
+ struct clk *bpa = c->parent_cluster;
+
+ if (pa && (!pa->dent && !pa->dent_bus)) {
+ err = clk_debugfs_register(pa);
+ if (err)
+ return err;
+ }
+
+ if (bpa && (!bpa->dent && !bpa->dent_bus)) {
+ err = clk_debugfs_register(bpa);
+ if (err)
+ return err;
+ }
+
+ if ((!c->dent) && (!c->dent_bus)) {
+ err = clk_debugfs_register_one(c);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+ struct clk *c;
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("clock", NULL);
+ if (!d)
+ return -ENOMEM;
+ clk_debugfs_root = d;
+
+ list_for_each_entry(c, &clk_list, list) {
+ err = clk_debugfs_register(c);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+err_out:
+ debugfs_remove_recursive(clk_debugfs_root);
+ return err;
+}
+
+late_initcall(clk_debugfs_init);
+#endif /* defined(CONFIG_DEBUG_FS) */
+
+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;
+ clk_per6clk.rate = 100000000;
+ } else if (cpu_is_u5500()) {
+ /* Clock tree for U5500 not implemented yet */
+ clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
+ clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
+ clk_uartclk.rate = 36360000;
+ clk_sdmmcclk.rate = 99900000;
+ }
+
+ clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
+ if (cpu_is_u8500ed())
+ clkdev_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
+ else
+ clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
+
+#ifdef CONFIG_DEBUG_FS
+ clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
+ if (cpu_is_u8500ed())
+ clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
+ else
+ clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
+#endif
+ return 0;
+}