summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ep93xx/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
-rw-r--r--arch/arm/mach-ep93xx/clock.c123
1 files changed, 88 insertions, 35 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index e8ebeae..6c4c163 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -21,15 +21,50 @@
#include <asm/div64.h>
#include <mach/hardware.h>
+
+/*
+ * The EP93xx has two external crystal oscillators. To generate the
+ * required high-frequency clocks, the processor uses two phase-locked-
+ * loops (PLLs) to multiply the incoming external clock signal to much
+ * higher frequencies that are then divided down by programmable dividers
+ * to produce the needed clocks. The PLLs operate independently of one
+ * another.
+ */
+#define EP93XX_EXT_CLK_RATE 14745600
+#define EP93XX_EXT_RTC_RATE 32768
+
+
struct clk {
unsigned long rate;
int users;
+ int sw_locked;
u32 enable_reg;
u32 enable_mask;
+
+ unsigned long (*get_rate)(struct clk *clk);
};
-static struct clk clk_uart = {
- .rate = 14745600,
+
+static unsigned long get_uart_rate(struct clk *clk);
+
+
+static struct clk clk_uart1 = {
+ .sw_locked = 1,
+ .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
+ .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN,
+ .get_rate = get_uart_rate,
+};
+static struct clk clk_uart2 = {
+ .sw_locked = 1,
+ .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
+ .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN,
+ .get_rate = get_uart_rate,
+};
+static struct clk clk_uart3 = {
+ .sw_locked = 1,
+ .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG,
+ .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN,
+ .get_rate = get_uart_rate,
};
static struct clk clk_pll1;
static struct clk clk_f;
@@ -37,73 +72,73 @@ static struct clk clk_h;
static struct clk clk_p;
static struct clk clk_pll2;
static struct clk clk_usb_host = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN,
};
/* DMA Clocks */
static struct clk clk_m2p0 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00020000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0,
};
static struct clk clk_m2p1 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00010000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1,
};
static struct clk clk_m2p2 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00080000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2,
};
static struct clk clk_m2p3 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00040000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3,
};
static struct clk clk_m2p4 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00200000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4,
};
static struct clk clk_m2p5 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00100000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5,
};
static struct clk clk_m2p6 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00800000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6,
};
static struct clk clk_m2p7 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x00400000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7,
};
static struct clk clk_m2p8 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x02000000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8,
};
static struct clk clk_m2p9 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x01000000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9,
};
static struct clk clk_m2m0 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x04000000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0,
};
static struct clk clk_m2m1 = {
- .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
- .enable_mask = 0x08000000,
+ .enable_reg = EP93XX_SYSCON_PWRCNT,
+ .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1,
};
#define INIT_CK(dev,con,ck) \
{ .dev_id = dev, .con_id = con, .clk = ck }
static struct clk_lookup clocks[] = {
- INIT_CK("apb:uart1", NULL, &clk_uart),
- INIT_CK("apb:uart2", NULL, &clk_uart),
- INIT_CK("apb:uart3", NULL, &clk_uart),
+ INIT_CK("apb:uart1", NULL, &clk_uart1),
+ INIT_CK("apb:uart2", NULL, &clk_uart2),
+ INIT_CK("apb:uart3", NULL, &clk_uart3),
INIT_CK(NULL, "pll1", &clk_pll1),
INIT_CK(NULL, "fclk", &clk_f),
INIT_CK(NULL, "hclk", &clk_h),
INIT_CK(NULL, "pclk", &clk_p),
INIT_CK(NULL, "pll2", &clk_pll2),
- INIT_CK(NULL, "usb_host", &clk_usb_host),
+ INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
INIT_CK(NULL, "m2p0", &clk_m2p0),
INIT_CK(NULL, "m2p1", &clk_m2p1),
INIT_CK(NULL, "m2p2", &clk_m2p2),
@@ -125,6 +160,8 @@ int clk_enable(struct clk *clk)
u32 value;
value = __raw_readl(clk->enable_reg);
+ if (clk->sw_locked)
+ __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(value | clk->enable_mask, clk->enable_reg);
}
@@ -138,13 +175,29 @@ void clk_disable(struct clk *clk)
u32 value;
value = __raw_readl(clk->enable_reg);
+ if (clk->sw_locked)
+ __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
__raw_writel(value & ~clk->enable_mask, clk->enable_reg);
}
}
EXPORT_SYMBOL(clk_disable);
+static unsigned long get_uart_rate(struct clk *clk)
+{
+ u32 value;
+
+ value = __raw_readl(EP93XX_SYSCON_PWRCNT);
+ if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
+ return EP93XX_EXT_CLK_RATE;
+ else
+ return EP93XX_EXT_CLK_RATE / 2;
+}
+
unsigned long clk_get_rate(struct clk *clk)
{
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);
@@ -162,7 +215,7 @@ static unsigned long calc_pll_rate(u32 config_word)
unsigned long long rate;
int i;
- rate = 14745600;
+ rate = EP93XX_EXT_CLK_RATE;
rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
@@ -195,7 +248,7 @@ static int __init ep93xx_clock_init(void)
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
if (!(value & 0x00800000)) { /* PLL1 bypassed? */
- clk_pll1.rate = 14745600;
+ clk_pll1.rate = EP93XX_EXT_CLK_RATE;
} else {
clk_pll1.rate = calc_pll_rate(value);
}
@@ -206,7 +259,7 @@ static int __init ep93xx_clock_init(void)
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
if (!(value & 0x00080000)) { /* PLL2 bypassed? */
- clk_pll2.rate = 14745600;
+ clk_pll2.rate = EP93XX_EXT_CLK_RATE;
} else if (value & 0x00040000) { /* PLL2 enabled? */
clk_pll2.rate = calc_pll_rate(value);
} else {
OpenPOWER on IntegriCloud