diff options
Diffstat (limited to 'arch/arm/mach-ep93xx/clock.c')
| -rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 131 |
1 files changed, 87 insertions, 44 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 6c4c1633ed12..3dd0e2a23095 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
| @@ -22,48 +22,39 @@ | |||
| 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; |
| 40 | int sw_locked; | 28 | int sw_locked; |
| 41 | u32 enable_reg; | 29 | void __iomem *enable_reg; |
| 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, |
| 53 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | 44 | .enable_reg = EP93XX_SYSCON_DEVCFG, |
| 54 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U1EN, | 45 | .enable_mask = EP93XX_SYSCON_DEVCFG_U1EN, |
| 55 | .get_rate = get_uart_rate, | 46 | .get_rate = get_uart_rate, |
| 56 | }; | 47 | }; |
| 57 | static struct clk clk_uart2 = { | 48 | static struct clk clk_uart2 = { |
| 58 | .sw_locked = 1, | 49 | .sw_locked = 1, |
| 59 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | 50 | .enable_reg = EP93XX_SYSCON_DEVCFG, |
| 60 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U2EN, | 51 | .enable_mask = EP93XX_SYSCON_DEVCFG_U2EN, |
| 61 | .get_rate = get_uart_rate, | 52 | .get_rate = get_uart_rate, |
| 62 | }; | 53 | }; |
| 63 | static struct clk clk_uart3 = { | 54 | static struct clk clk_uart3 = { |
| 64 | .sw_locked = 1, | 55 | .sw_locked = 1, |
| 65 | .enable_reg = EP93XX_SYSCON_DEVICE_CONFIG, | 56 | .enable_reg = EP93XX_SYSCON_DEVCFG, |
| 66 | .enable_mask = EP93XX_SYSCON_DEVICE_CONFIG_U3EN, | 57 | .enable_mask = EP93XX_SYSCON_DEVCFG_U3EN, |
| 67 | .get_rate = get_uart_rate, | 58 | .get_rate = get_uart_rate, |
| 68 | }; | 59 | }; |
| 69 | static struct clk clk_pll1; | 60 | static struct clk clk_pll1; |
| @@ -75,6 +66,15 @@ 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 | }; | ||
| 75 | static struct clk clk_pwm = { | ||
| 76 | .rate = EP93XX_EXT_CLK_RATE, | ||
| 77 | }; | ||
| 78 | 78 | ||
| 79 | /* DMA Clocks */ | 79 | /* DMA Clocks */ |
| 80 | static struct clk clk_m2p0 = { | 80 | static struct clk clk_m2p0 = { |
| @@ -130,27 +130,29 @@ static struct clk clk_m2m1 = { | |||
| 130 | { .dev_id = dev, .con_id = con, .clk = ck } | 130 | { .dev_id = dev, .con_id = con, .clk = ck } |
| 131 | 131 | ||
| 132 | static struct clk_lookup clocks[] = { | 132 | static struct clk_lookup clocks[] = { |
| 133 | INIT_CK("apb:uart1", NULL, &clk_uart1), | 133 | INIT_CK("apb:uart1", NULL, &clk_uart1), |
| 134 | INIT_CK("apb:uart2", NULL, &clk_uart2), | 134 | INIT_CK("apb:uart2", NULL, &clk_uart2), |
| 135 | INIT_CK("apb:uart3", NULL, &clk_uart3), | 135 | INIT_CK("apb:uart3", NULL, &clk_uart3), |
| 136 | INIT_CK(NULL, "pll1", &clk_pll1), | 136 | INIT_CK(NULL, "pll1", &clk_pll1), |
| 137 | INIT_CK(NULL, "fclk", &clk_f), | 137 | INIT_CK(NULL, "fclk", &clk_f), |
| 138 | INIT_CK(NULL, "hclk", &clk_h), | 138 | INIT_CK(NULL, "hclk", &clk_h), |
| 139 | INIT_CK(NULL, "pclk", &clk_p), | 139 | INIT_CK(NULL, "pclk", &clk_p), |
| 140 | INIT_CK(NULL, "pll2", &clk_pll2), | 140 | INIT_CK(NULL, "pll2", &clk_pll2), |
| 141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), | 141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), |
| 142 | INIT_CK(NULL, "m2p0", &clk_m2p0), | 142 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), |
| 143 | INIT_CK(NULL, "m2p1", &clk_m2p1), | 143 | INIT_CK(NULL, "pwm_clk", &clk_pwm), |
| 144 | INIT_CK(NULL, "m2p2", &clk_m2p2), | 144 | INIT_CK(NULL, "m2p0", &clk_m2p0), |
| 145 | INIT_CK(NULL, "m2p3", &clk_m2p3), | 145 | INIT_CK(NULL, "m2p1", &clk_m2p1), |
| 146 | INIT_CK(NULL, "m2p4", &clk_m2p4), | 146 | INIT_CK(NULL, "m2p2", &clk_m2p2), |
| 147 | INIT_CK(NULL, "m2p5", &clk_m2p5), | 147 | INIT_CK(NULL, "m2p3", &clk_m2p3), |
| 148 | INIT_CK(NULL, "m2p6", &clk_m2p6), | 148 | INIT_CK(NULL, "m2p4", &clk_m2p4), |
| 149 | INIT_CK(NULL, "m2p7", &clk_m2p7), | 149 | INIT_CK(NULL, "m2p5", &clk_m2p5), |
| 150 | INIT_CK(NULL, "m2p8", &clk_m2p8), | 150 | INIT_CK(NULL, "m2p6", &clk_m2p6), |
| 151 | INIT_CK(NULL, "m2p9", &clk_m2p9), | 151 | INIT_CK(NULL, "m2p7", &clk_m2p7), |
| 152 | INIT_CK(NULL, "m2m0", &clk_m2m0), | 152 | INIT_CK(NULL, "m2p8", &clk_m2p8), |
| 153 | INIT_CK(NULL, "m2m1", &clk_m2m1), | 153 | INIT_CK(NULL, "m2p9", &clk_m2p9), |
| 154 | INIT_CK(NULL, "m2m0", &clk_m2m0), | ||
| 155 | INIT_CK(NULL, "m2m1", &clk_m2m1), | ||
| 154 | }; | 156 | }; |
| 155 | 157 | ||
| 156 | 158 | ||
| @@ -160,9 +162,11 @@ int clk_enable(struct clk *clk) | |||
| 160 | u32 value; | 162 | u32 value; |
| 161 | 163 | ||
| 162 | value = __raw_readl(clk->enable_reg); | 164 | value = __raw_readl(clk->enable_reg); |
| 165 | value |= clk->enable_mask; | ||
| 163 | if (clk->sw_locked) | 166 | if (clk->sw_locked) |
| 164 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | 167 | ep93xx_syscon_swlocked_write(value, clk->enable_reg); |
| 165 | __raw_writel(value | clk->enable_mask, clk->enable_reg); | 168 | else |
| 169 | __raw_writel(value, clk->enable_reg); | ||
| 166 | } | 170 | } |
| 167 | 171 | ||
| 168 | return 0; | 172 | return 0; |
| @@ -175,9 +179,11 @@ void clk_disable(struct clk *clk) | |||
| 175 | u32 value; | 179 | u32 value; |
| 176 | 180 | ||
| 177 | value = __raw_readl(clk->enable_reg); | 181 | value = __raw_readl(clk->enable_reg); |
| 182 | value &= ~clk->enable_mask; | ||
| 178 | if (clk->sw_locked) | 183 | if (clk->sw_locked) |
| 179 | __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK); | 184 | ep93xx_syscon_swlocked_write(value, clk->enable_reg); |
| 180 | __raw_writel(value & ~clk->enable_mask, clk->enable_reg); | 185 | else |
| 186 | __raw_writel(value, clk->enable_reg); | ||
| 181 | } | 187 | } |
| 182 | } | 188 | } |
| 183 | EXPORT_SYMBOL(clk_disable); | 189 | EXPORT_SYMBOL(clk_disable); |
| @@ -202,6 +208,43 @@ unsigned long clk_get_rate(struct clk *clk) | |||
| 202 | } | 208 | } |
| 203 | EXPORT_SYMBOL(clk_get_rate); | 209 | EXPORT_SYMBOL(clk_get_rate); |
| 204 | 210 | ||
| 211 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate) | ||
| 212 | { | ||
| 213 | u32 val; | ||
| 214 | u32 div_bit; | ||
| 215 | |||
| 216 | val = __raw_readl(clk->enable_reg); | ||
| 217 | |||
| 218 | /* | ||
| 219 | * The Key Matrix and ADC clocks are configured using the same | ||
| 220 | * System Controller register. The clock used will be either | ||
| 221 | * 1/4 or 1/16 the external clock rate depending on the | ||
| 222 | * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV | ||
| 223 | * bit being set or cleared. | ||
| 224 | */ | ||
| 225 | div_bit = clk->enable_mask >> 15; | ||
| 226 | |||
| 227 | if (rate == EP93XX_KEYTCHCLK_DIV4) | ||
| 228 | val |= div_bit; | ||
| 229 | else if (rate == EP93XX_KEYTCHCLK_DIV16) | ||
| 230 | val &= ~div_bit; | ||
| 231 | else | ||
| 232 | return -EINVAL; | ||
| 233 | |||
| 234 | ep93xx_syscon_swlocked_write(val, clk->enable_reg); | ||
| 235 | clk->rate = rate; | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
| 240 | { | ||
| 241 | if (clk->set_rate) | ||
| 242 | return clk->set_rate(clk, rate); | ||
| 243 | |||
| 244 | return -EINVAL; | ||
| 245 | } | ||
| 246 | EXPORT_SYMBOL(clk_set_rate); | ||
| 247 | |||
| 205 | 248 | ||
| 206 | static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; | 249 | static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; |
| 207 | static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; | 250 | static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; |
