[ARM] 5578/1: ep93xx: add ep93xx-keypad clock
[deliverable/linux.git] / arch / arm / mach-ep93xx / clock.c
index c7642acfd0224e9882f548358f712f2efb520f89..207e27699410eb61f1b50d393f4dcb919c163c76 100644 (file)
 #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;
@@ -42,11 +30,14 @@ struct clk {
        u32             enable_mask;
 
        unsigned long   (*get_rate)(struct clk *clk);
+       int             (*set_rate)(struct clk *clk, unsigned long rate);
 };
 
 
 static unsigned long get_uart_rate(struct clk *clk);
 
+static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
+
 
 static struct clk clk_uart1 = {
        .sw_locked      = 1,
@@ -75,6 +66,12 @@ static struct clk clk_usb_host = {
        .enable_reg     = EP93XX_SYSCON_PWRCNT,
        .enable_mask    = EP93XX_SYSCON_PWRCNT_USH_EN,
 };
+static struct clk clk_keypad = {
+       .sw_locked      = 1,
+       .enable_reg     = EP93XX_SYSCON_KEYTCHCLKDIV,
+       .enable_mask    = EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
+       .set_rate       = set_keytchclk_rate,
+};
 
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
@@ -130,27 +127,28 @@ static struct clk clk_m2m1 = {
        { .dev_id = dev, .con_id = con, .clk = ck }
 
 static struct clk_lookup clocks[] = {
-       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("ep93xx-ohci", NULL, &clk_usb_host),
-       INIT_CK(NULL, "m2p0", &clk_m2p0),
-       INIT_CK(NULL, "m2p1", &clk_m2p1),
-       INIT_CK(NULL, "m2p2", &clk_m2p2),
-       INIT_CK(NULL, "m2p3", &clk_m2p3),
-       INIT_CK(NULL, "m2p4", &clk_m2p4),
-       INIT_CK(NULL, "m2p5", &clk_m2p5),
-       INIT_CK(NULL, "m2p6", &clk_m2p6),
-       INIT_CK(NULL, "m2p7", &clk_m2p7),
-       INIT_CK(NULL, "m2p8", &clk_m2p8),
-       INIT_CK(NULL, "m2p9", &clk_m2p9),
-       INIT_CK(NULL, "m2m0", &clk_m2m0),
-       INIT_CK(NULL, "m2m1", &clk_m2m1),
+       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("ep93xx-ohci",          NULL,           &clk_usb_host),
+       INIT_CK("ep93xx-keypad",        NULL,           &clk_keypad),
+       INIT_CK(NULL,                   "m2p0",         &clk_m2p0),
+       INIT_CK(NULL,                   "m2p1",         &clk_m2p1),
+       INIT_CK(NULL,                   "m2p2",         &clk_m2p2),
+       INIT_CK(NULL,                   "m2p3",         &clk_m2p3),
+       INIT_CK(NULL,                   "m2p4",         &clk_m2p4),
+       INIT_CK(NULL,                   "m2p5",         &clk_m2p5),
+       INIT_CK(NULL,                   "m2p6",         &clk_m2p6),
+       INIT_CK(NULL,                   "m2p7",         &clk_m2p7),
+       INIT_CK(NULL,                   "m2p8",         &clk_m2p8),
+       INIT_CK(NULL,                   "m2p9",         &clk_m2p9),
+       INIT_CK(NULL,                   "m2m0",         &clk_m2m0),
+       INIT_CK(NULL,                   "m2m1",         &clk_m2m1),
 };
 
 
@@ -206,6 +204,43 @@ unsigned long clk_get_rate(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_get_rate);
 
+static int set_keytchclk_rate(struct clk *clk, unsigned long rate)
+{
+       u32 val;
+       u32 div_bit;
+
+       val = __raw_readl(clk->enable_reg);
+
+       /*
+        * The Key Matrix and ADC clocks are configured using the same
+        * System Controller register.  The clock used will be either
+        * 1/4 or 1/16 the external clock rate depending on the
+        * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV
+        * bit being set or cleared.
+        */
+       div_bit = clk->enable_mask >> 15;
+
+       if (rate == EP93XX_KEYTCHCLK_DIV4)
+               val |= div_bit;
+       else if (rate == EP93XX_KEYTCHCLK_DIV16)
+               val &= ~div_bit;
+       else
+               return -EINVAL;
+
+       ep93xx_syscon_swlocked_write(val, clk->enable_reg);
+       clk->rate = rate;
+       return 0;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       if (clk->set_rate)
+               return clk->set_rate(clk, rate);
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
 
 static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
 static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
This page took 0.027335 seconds and 5 git commands to generate.