diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
-rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 101 |
1 files changed, 68 insertions, 33 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index c7642acfd022..207e27699410 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
@@ -22,18 +22,6 @@ | |||
22 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
23 | 23 | ||
24 | 24 | ||
25 | /* | ||
26 | * The EP93xx has two external crystal oscillators. To generate the | ||
27 | * required high-frequency clocks, the processor uses two phase-locked- | ||
28 | * loops (PLLs) to multiply the incoming external clock signal to much | ||
29 | * higher frequencies that are then divided down by programmable dividers | ||
30 | * to produce the needed clocks. The PLLs operate independently of one | ||
31 | * another. | ||
32 | */ | ||
33 | #define EP93XX_EXT_CLK_RATE 14745600 | ||
34 | #define EP93XX_EXT_RTC_RATE 32768 | ||
35 | |||
36 | |||
37 | struct clk { | 25 | struct clk { |
38 | unsigned long rate; | 26 | unsigned long rate; |
39 | int users; | 27 | int users; |
@@ -42,11 +30,14 @@ struct clk { | |||
42 | u32 enable_mask; | 30 | u32 enable_mask; |
43 | 31 | ||
44 | unsigned long (*get_rate)(struct clk *clk); | 32 | unsigned long (*get_rate)(struct clk *clk); |
33 | int (*set_rate)(struct clk *clk, unsigned long rate); | ||
45 | }; | 34 | }; |
46 | 35 | ||
47 | 36 | ||
48 | static unsigned long get_uart_rate(struct clk *clk); | 37 | static unsigned long get_uart_rate(struct clk *clk); |
49 | 38 | ||
39 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate); | ||
40 | |||
50 | 41 | ||
51 | static struct clk clk_uart1 = { | 42 | static struct clk clk_uart1 = { |
52 | .sw_locked = 1, | 43 | .sw_locked = 1, |
@@ -75,6 +66,12 @@ static struct clk clk_usb_host = { | |||
75 | .enable_reg = EP93XX_SYSCON_PWRCNT, | 66 | .enable_reg = EP93XX_SYSCON_PWRCNT, |
76 | .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, | 67 | .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, |
77 | }; | 68 | }; |
69 | static struct clk clk_keypad = { | ||
70 | .sw_locked = 1, | ||
71 | .enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV, | ||
72 | .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN, | ||
73 | .set_rate = set_keytchclk_rate, | ||
74 | }; | ||
78 | 75 | ||
79 | /* DMA Clocks */ | 76 | /* DMA Clocks */ |
80 | static struct clk clk_m2p0 = { | 77 | static struct clk clk_m2p0 = { |
@@ -130,27 +127,28 @@ static struct clk clk_m2m1 = { | |||
130 | { .dev_id = dev, .con_id = con, .clk = ck } | 127 | { .dev_id = dev, .con_id = con, .clk = ck } |
131 | 128 | ||
132 | static struct clk_lookup clocks[] = { | 129 | static struct clk_lookup clocks[] = { |
133 | INIT_CK("apb:uart1", NULL, &clk_uart1), | 130 | INIT_CK("apb:uart1", NULL, &clk_uart1), |
134 | INIT_CK("apb:uart2", NULL, &clk_uart2), | 131 | INIT_CK("apb:uart2", NULL, &clk_uart2), |
135 | INIT_CK("apb:uart3", NULL, &clk_uart3), | 132 | INIT_CK("apb:uart3", NULL, &clk_uart3), |
136 | INIT_CK(NULL, "pll1", &clk_pll1), | 133 | INIT_CK(NULL, "pll1", &clk_pll1), |
137 | INIT_CK(NULL, "fclk", &clk_f), | 134 | INIT_CK(NULL, "fclk", &clk_f), |
138 | INIT_CK(NULL, "hclk", &clk_h), | 135 | INIT_CK(NULL, "hclk", &clk_h), |
139 | INIT_CK(NULL, "pclk", &clk_p), | 136 | INIT_CK(NULL, "pclk", &clk_p), |
140 | INIT_CK(NULL, "pll2", &clk_pll2), | 137 | INIT_CK(NULL, "pll2", &clk_pll2), |
141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), | 138 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), |
142 | INIT_CK(NULL, "m2p0", &clk_m2p0), | 139 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), |
143 | INIT_CK(NULL, "m2p1", &clk_m2p1), | 140 | INIT_CK(NULL, "m2p0", &clk_m2p0), |
144 | INIT_CK(NULL, "m2p2", &clk_m2p2), | 141 | INIT_CK(NULL, "m2p1", &clk_m2p1), |
145 | INIT_CK(NULL, "m2p3", &clk_m2p3), | 142 | INIT_CK(NULL, "m2p2", &clk_m2p2), |
146 | INIT_CK(NULL, "m2p4", &clk_m2p4), | 143 | INIT_CK(NULL, "m2p3", &clk_m2p3), |
147 | INIT_CK(NULL, "m2p5", &clk_m2p5), | 144 | INIT_CK(NULL, "m2p4", &clk_m2p4), |
148 | INIT_CK(NULL, "m2p6", &clk_m2p6), | 145 | INIT_CK(NULL, "m2p5", &clk_m2p5), |
149 | INIT_CK(NULL, "m2p7", &clk_m2p7), | 146 | INIT_CK(NULL, "m2p6", &clk_m2p6), |
150 | INIT_CK(NULL, "m2p8", &clk_m2p8), | 147 | INIT_CK(NULL, "m2p7", &clk_m2p7), |
151 | INIT_CK(NULL, "m2p9", &clk_m2p9), | 148 | INIT_CK(NULL, "m2p8", &clk_m2p8), |
152 | INIT_CK(NULL, "m2m0", &clk_m2m0), | 149 | INIT_CK(NULL, "m2p9", &clk_m2p9), |
153 | INIT_CK(NULL, "m2m1", &clk_m2m1), | 150 | INIT_CK(NULL, "m2m0", &clk_m2m0), |
151 | INIT_CK(NULL, "m2m1", &clk_m2m1), | ||
154 | }; | 152 | }; |
155 | 153 | ||
156 | 154 | ||
@@ -206,6 +204,43 @@ unsigned long clk_get_rate(struct clk *clk) | |||
206 | } | 204 | } |
207 | EXPORT_SYMBOL(clk_get_rate); | 205 | EXPORT_SYMBOL(clk_get_rate); |
208 | 206 | ||
207 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate) | ||
208 | { | ||
209 | u32 val; | ||
210 | u32 div_bit; | ||
211 | |||
212 | val = __raw_readl(clk->enable_reg); | ||
213 | |||
214 | /* | ||
215 | * The Key Matrix and ADC clocks are configured using the same | ||
216 | * System Controller register. The clock used will be either | ||
217 | * 1/4 or 1/16 the external clock rate depending on the | ||
218 | * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV | ||
219 | * bit being set or cleared. | ||
220 | */ | ||
221 | div_bit = clk->enable_mask >> 15; | ||
222 | |||
223 | if (rate == EP93XX_KEYTCHCLK_DIV4) | ||
224 | val |= div_bit; | ||
225 | else if (rate == EP93XX_KEYTCHCLK_DIV16) | ||
226 | val &= ~div_bit; | ||
227 | else | ||
228 | return -EINVAL; | ||
229 | |||
230 | ep93xx_syscon_swlocked_write(val, clk->enable_reg); | ||
231 | clk->rate = rate; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
236 | { | ||
237 | if (clk->set_rate) | ||
238 | return clk->set_rate(clk, rate); | ||
239 | |||
240 | return -EINVAL; | ||
241 | } | ||
242 | EXPORT_SYMBOL(clk_set_rate); | ||
243 | |||
209 | 244 | ||
210 | static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; | 245 | static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; |
211 | static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; | 246 | static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; |