[ARM] 5552/1: ep93xx get_uart_rate(): use EP93XX_SYSCON_PWRCNT and EP93XX_SYSCON_PWRCN
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / arch / arm / mach-ep93xx / clock.c
index e8ebeaea6c48c78ed9eda599e512d0d152c73349..6c4c1633ed123c8457fd20a4f1c51c6bafe39534 100644 (file)
 #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 {