diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index c7642acfd02..207e2769941 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -22,18 +22,6 @@ #include -/* - * 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 }; diff --git a/arch/arm/mach-ep93xx/include/mach/hardware.h b/arch/arm/mach-ep93xx/include/mach/hardware.h index 2866297310b..587c07bdec5 100644 --- a/arch/arm/mach-ep93xx/include/mach/hardware.h +++ b/arch/arm/mach-ep93xx/include/mach/hardware.h @@ -12,4 +12,18 @@ #include "ts72xx.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 + +#define EP93XX_KEYTCHCLK_DIV4 (EP93XX_EXT_CLK_RATE / 4) +#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16) + #endif