diff options
| author | Sascha Hauer <s.hauer@pengutronix.de> | 2008-07-05 04:02:46 -0400 |
|---|---|---|
| committer | Robert Schwebel <r.schwebel@pengutronix.de> | 2008-07-05 04:02:46 -0400 |
| commit | 38a41fdf94c449c165213e4665c3f8a0d30f8aba (patch) | |
| tree | cde7f6c0da8c9877736a6b66f245e163fa21c2f7 | |
| parent | dbff4e9ea2e83fda89143389bfb229cb29425a32 (diff) | |
IMX: introduce clock API
This patch introduces the clock API for i.MX and converts all
in-Kernel drivers to use it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
| -rw-r--r-- | arch/arm/mach-imx/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-imx/clock.c | 205 | ||||
| -rw-r--r-- | arch/arm/mach-imx/cpufreq.c | 20 | ||||
| -rw-r--r-- | arch/arm/mach-imx/generic.c | 76 | ||||
| -rw-r--r-- | arch/arm/mach-imx/time.c | 23 | ||||
| -rw-r--r-- | drivers/mmc/host/imxmmc.c | 19 | ||||
| -rw-r--r-- | drivers/serial/imx.c | 25 | ||||
| -rw-r--r-- | drivers/spi/spi_imx.c | 38 | ||||
| -rw-r--r-- | include/asm-arm/arch-imx/hardware.h | 8 |
9 files changed, 307 insertions, 109 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 88d5e61a2e13..b047c7e795a9 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | # Object file lists. | 5 | # Object file lists. |
| 6 | 6 | ||
| 7 | obj-y += irq.o time.o dma.o generic.o | 7 | obj-y += irq.o time.o dma.o generic.o clock.o |
| 8 | 8 | ||
| 9 | obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o | 9 | obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o |
| 10 | 10 | ||
diff --git a/arch/arm/mach-imx/clock.c b/arch/arm/mach-imx/clock.c new file mode 100644 index 000000000000..6a90fe5578df --- /dev/null +++ b/arch/arm/mach-imx/clock.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/list.h> | ||
| 22 | #include <linux/math64.h> | ||
| 23 | #include <linux/err.h> | ||
| 24 | |||
| 25 | #include <asm/io.h> | ||
| 26 | #include <asm/arch/imx-regs.h> | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Very simple approach: We can't disable clocks, so we do | ||
| 30 | * not need refcounting | ||
| 31 | */ | ||
| 32 | |||
| 33 | struct clk { | ||
| 34 | struct list_head node; | ||
| 35 | const char *name; | ||
| 36 | unsigned long (*get_rate)(void); | ||
| 37 | }; | ||
| 38 | |||
| 39 | /* | ||
| 40 | * get the system pll clock in Hz | ||
| 41 | * | ||
| 42 | * mfi + mfn / (mfd +1) | ||
| 43 | * f = 2 * f_ref * -------------------- | ||
| 44 | * pd + 1 | ||
| 45 | */ | ||
| 46 | static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref) | ||
| 47 | { | ||
| 48 | unsigned long long ll; | ||
| 49 | unsigned long quot; | ||
| 50 | |||
| 51 | u32 mfi = (pll >> 10) & 0xf; | ||
| 52 | u32 mfn = pll & 0x3ff; | ||
| 53 | u32 mfd = (pll >> 16) & 0x3ff; | ||
| 54 | u32 pd = (pll >> 26) & 0xf; | ||
| 55 | |||
| 56 | mfi = mfi <= 5 ? 5 : mfi; | ||
| 57 | |||
| 58 | ll = 2 * (unsigned long long)f_ref * | ||
| 59 | ((mfi << 16) + (mfn << 16) / (mfd + 1)); | ||
| 60 | quot = (pd + 1) * (1 << 16); | ||
| 61 | ll += quot / 2; | ||
| 62 | do_div(ll, quot); | ||
| 63 | return (unsigned long)ll; | ||
| 64 | } | ||
| 65 | |||
| 66 | static unsigned long imx_get_system_clk(void) | ||
| 67 | { | ||
| 68 | u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512); | ||
| 69 | |||
| 70 | return imx_decode_pll(SPCTL0, f_ref); | ||
| 71 | } | ||
| 72 | |||
| 73 | static unsigned long imx_get_mcu_clk(void) | ||
| 74 | { | ||
| 75 | return imx_decode_pll(MPCTL0, CLK32 * 512); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* | ||
| 79 | * get peripheral clock 1 ( UART[12], Timer[12], PWM ) | ||
| 80 | */ | ||
| 81 | static unsigned long imx_get_perclk1(void) | ||
| 82 | { | ||
| 83 | return imx_get_system_clk() / (((PCDR) & 0xf)+1); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * get peripheral clock 2 ( LCD, SD, SPI[12] ) | ||
| 88 | */ | ||
| 89 | static unsigned long imx_get_perclk2(void) | ||
| 90 | { | ||
| 91 | return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1); | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 95 | * get peripheral clock 3 ( SSI ) | ||
| 96 | */ | ||
| 97 | static unsigned long imx_get_perclk3(void) | ||
| 98 | { | ||
| 99 | return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1); | ||
| 100 | } | ||
| 101 | |||
| 102 | /* | ||
| 103 | * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) | ||
| 104 | */ | ||
| 105 | static unsigned long imx_get_hclk(void) | ||
| 106 | { | ||
| 107 | return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1); | ||
| 108 | } | ||
| 109 | |||
| 110 | static struct clk clk_system_clk = { | ||
| 111 | .name = "system_clk", | ||
| 112 | .get_rate = imx_get_system_clk, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static struct clk clk_hclk = { | ||
| 116 | .name = "hclk", | ||
| 117 | .get_rate = imx_get_hclk, | ||
| 118 | }; | ||
| 119 | |||
| 120 | static struct clk clk_mcu_clk = { | ||
| 121 | .name = "mcu_clk", | ||
| 122 | .get_rate = imx_get_mcu_clk, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct clk clk_perclk1 = { | ||
| 126 | .name = "perclk1", | ||
| 127 | .get_rate = imx_get_perclk1, | ||
| 128 | }; | ||
| 129 | |||
| 130 | static struct clk clk_uart_clk = { | ||
| 131 | .name = "uart_clk", | ||
| 132 | .get_rate = imx_get_perclk1, | ||
| 133 | }; | ||
| 134 | |||
| 135 | static struct clk clk_perclk2 = { | ||
| 136 | .name = "perclk2", | ||
| 137 | .get_rate = imx_get_perclk2, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static struct clk clk_perclk3 = { | ||
| 141 | .name = "perclk3", | ||
| 142 | .get_rate = imx_get_perclk3, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static struct clk *clks[] = { | ||
| 146 | &clk_perclk1, | ||
| 147 | &clk_perclk2, | ||
| 148 | &clk_perclk3, | ||
| 149 | &clk_system_clk, | ||
| 150 | &clk_hclk, | ||
| 151 | &clk_mcu_clk, | ||
| 152 | &clk_uart_clk, | ||
| 153 | }; | ||
| 154 | |||
| 155 | static LIST_HEAD(clocks); | ||
| 156 | static DEFINE_MUTEX(clocks_mutex); | ||
| 157 | |||
| 158 | struct clk *clk_get(struct device *dev, const char *id) | ||
| 159 | { | ||
| 160 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
| 161 | |||
| 162 | mutex_lock(&clocks_mutex); | ||
| 163 | list_for_each_entry(p, &clocks, node) { | ||
| 164 | if (!strcmp(p->name, id)) { | ||
| 165 | clk = p; | ||
| 166 | goto found; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | found: | ||
| 171 | mutex_unlock(&clocks_mutex); | ||
| 172 | |||
| 173 | return clk; | ||
| 174 | } | ||
| 175 | |||
| 176 | void clk_put(struct clk *clk) | ||
| 177 | { | ||
| 178 | } | ||
| 179 | |||
| 180 | int clk_enable(struct clk *clk) | ||
| 181 | { | ||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | void clk_disable(struct clk *clk) | ||
| 186 | { | ||
| 187 | } | ||
| 188 | |||
| 189 | unsigned long clk_get_rate(struct clk *clk) | ||
| 190 | { | ||
| 191 | return clk->get_rate(); | ||
| 192 | } | ||
| 193 | |||
| 194 | int imx_clocks_init(void) | ||
| 195 | { | ||
| 196 | int i; | ||
| 197 | |||
| 198 | mutex_lock(&clocks_mutex); | ||
| 199 | for (i = 0; i < ARRAY_SIZE(clks); i++) | ||
| 200 | list_add(&clks[i]->node, &clocks); | ||
| 201 | mutex_unlock(&clocks_mutex); | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c index e548ba74a4d2..be0809b33e08 100644 --- a/arch/arm/mach-imx/cpufreq.c +++ b/arch/arm/mach-imx/cpufreq.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 34 | #include <linux/cpufreq.h> | 34 | #include <linux/cpufreq.h> |
| 35 | #include <linux/clk.h> | ||
| 36 | #include <linux/err.h> | ||
| 35 | #include <asm/system.h> | 37 | #include <asm/system.h> |
| 36 | 38 | ||
| 37 | #include <asm/hardware.h> | 39 | #include <asm/hardware.h> |
| @@ -52,6 +54,8 @@ | |||
| 52 | static u32 mpctl0_at_boot; | 54 | static u32 mpctl0_at_boot; |
| 53 | static u32 bclk_div_at_boot; | 55 | static u32 bclk_div_at_boot; |
| 54 | 56 | ||
| 57 | static struct clk *system_clk, *mcu_clk; | ||
| 58 | |||
| 55 | static void imx_set_async_mode(void) | 59 | static void imx_set_async_mode(void) |
| 56 | { | 60 | { |
| 57 | adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE); | 61 | adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE); |
| @@ -160,10 +164,10 @@ static unsigned int imx_get_speed(unsigned int cpu) | |||
| 160 | cr = get_cr(); | 164 | cr = get_cr(); |
| 161 | 165 | ||
| 162 | if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) { | 166 | if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) { |
| 163 | freq = imx_get_system_clk(); | 167 | freq = clk_get_rate(system_clk); |
| 164 | freq = (freq + bclk_div/2) / bclk_div; | 168 | freq = (freq + bclk_div/2) / bclk_div; |
| 165 | } else { | 169 | } else { |
| 166 | freq = imx_get_mcu_clk(); | 170 | freq = clk_get_rate(mcu_clk); |
| 167 | if (cscr & CSCR_MPU_PRESC) | 171 | if (cscr & CSCR_MPU_PRESC) |
| 168 | freq /= 2; | 172 | freq /= 2; |
| 169 | } | 173 | } |
| @@ -201,7 +205,7 @@ static int imx_set_target(struct cpufreq_policy *policy, | |||
| 201 | pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n", | 205 | pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n", |
| 202 | freq, mpctl0_at_boot); | 206 | freq, mpctl0_at_boot); |
| 203 | 207 | ||
| 204 | sysclk = imx_get_system_clk(); | 208 | sysclk = clk_get_rate(system_clk); |
| 205 | 209 | ||
| 206 | if (freq > sysclk / bclk_div_at_boot + 1000000) { | 210 | if (freq > sysclk / bclk_div_at_boot + 1000000) { |
| 207 | freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation); | 211 | freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation); |
| @@ -290,6 +294,16 @@ static int __init imx_cpufreq_init(void) | |||
| 290 | bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1; | 294 | bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1; |
| 291 | mpctl0_at_boot = 0; | 295 | mpctl0_at_boot = 0; |
| 292 | 296 | ||
| 297 | system_clk = clk_get(NULL, "system_clk"); | ||
| 298 | if (IS_ERR(system_clk)) | ||
| 299 | return PTR_ERR(system_clk); | ||
| 300 | |||
| 301 | mcu_clk = clk_get(NULL, "mcu_clk"); | ||
| 302 | if (IS_ERR(mcu_clk)) { | ||
| 303 | clk_put(system_clk); | ||
| 304 | return PTR_ERR(mcu_clk); | ||
| 305 | } | ||
| 306 | |||
| 293 | if((CSCR & CSCR_MPEN) && | 307 | if((CSCR & CSCR_MPEN) && |
| 294 | ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE)) | 308 | ((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE)) |
| 295 | mpctl0_at_boot = MPCTL0; | 309 | mpctl0_at_boot = MPCTL0; |
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 4cfc9d3af28a..98ddd8a6d05f 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c | |||
| @@ -214,82 +214,6 @@ int imx_irq_to_gpio(unsigned irq) | |||
| 214 | 214 | ||
| 215 | EXPORT_SYMBOL(imx_irq_to_gpio); | 215 | EXPORT_SYMBOL(imx_irq_to_gpio); |
| 216 | 216 | ||
| 217 | /* | ||
| 218 | * get the system pll clock in Hz | ||
| 219 | * | ||
| 220 | * mfi + mfn / (mfd +1) | ||
| 221 | * f = 2 * f_ref * -------------------- | ||
| 222 | * pd + 1 | ||
| 223 | */ | ||
| 224 | static unsigned int imx_decode_pll(unsigned int pll, u32 f_ref) | ||
| 225 | { | ||
| 226 | unsigned long long ll; | ||
| 227 | unsigned long quot; | ||
| 228 | |||
| 229 | u32 mfi = (pll >> 10) & 0xf; | ||
| 230 | u32 mfn = pll & 0x3ff; | ||
| 231 | u32 mfd = (pll >> 16) & 0x3ff; | ||
| 232 | u32 pd = (pll >> 26) & 0xf; | ||
| 233 | |||
| 234 | mfi = mfi <= 5 ? 5 : mfi; | ||
| 235 | |||
| 236 | ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) ); | ||
| 237 | quot = (pd+1) * (1<<16); | ||
| 238 | ll += quot / 2; | ||
| 239 | do_div(ll, quot); | ||
| 240 | return (unsigned int) ll; | ||
| 241 | } | ||
| 242 | |||
| 243 | unsigned int imx_get_system_clk(void) | ||
| 244 | { | ||
| 245 | u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512); | ||
| 246 | |||
| 247 | return imx_decode_pll(SPCTL0, f_ref); | ||
| 248 | } | ||
| 249 | EXPORT_SYMBOL(imx_get_system_clk); | ||
| 250 | |||
| 251 | unsigned int imx_get_mcu_clk(void) | ||
| 252 | { | ||
| 253 | return imx_decode_pll(MPCTL0, CLK32 * 512); | ||
| 254 | } | ||
| 255 | EXPORT_SYMBOL(imx_get_mcu_clk); | ||
| 256 | |||
| 257 | /* | ||
| 258 | * get peripheral clock 1 ( UART[12], Timer[12], PWM ) | ||
| 259 | */ | ||
| 260 | unsigned int imx_get_perclk1(void) | ||
| 261 | { | ||
| 262 | return imx_get_system_clk() / (((PCDR) & 0xf)+1); | ||
| 263 | } | ||
| 264 | EXPORT_SYMBOL(imx_get_perclk1); | ||
| 265 | |||
| 266 | /* | ||
| 267 | * get peripheral clock 2 ( LCD, SD, SPI[12] ) | ||
| 268 | */ | ||
| 269 | unsigned int imx_get_perclk2(void) | ||
| 270 | { | ||
| 271 | return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1); | ||
| 272 | } | ||
| 273 | EXPORT_SYMBOL(imx_get_perclk2); | ||
| 274 | |||
| 275 | /* | ||
| 276 | * get peripheral clock 3 ( SSI ) | ||
| 277 | */ | ||
| 278 | unsigned int imx_get_perclk3(void) | ||
| 279 | { | ||
| 280 | return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1); | ||
| 281 | } | ||
| 282 | EXPORT_SYMBOL(imx_get_perclk3); | ||
| 283 | |||
| 284 | /* | ||
| 285 | * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) | ||
| 286 | */ | ||
| 287 | unsigned int imx_get_hclk(void) | ||
| 288 | { | ||
| 289 | return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1); | ||
| 290 | } | ||
| 291 | EXPORT_SYMBOL(imx_get_hclk); | ||
| 292 | |||
| 293 | static struct resource imx_mmc_resources[] = { | 217 | static struct resource imx_mmc_resources[] = { |
| 294 | [0] = { | 218 | [0] = { |
| 295 | .start = 0x00214000, | 219 | .start = 0x00214000, |
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index d86d124aea22..5a41e96e8586 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/time.h> | 17 | #include <linux/time.h> |
| 18 | #include <linux/clocksource.h> | 18 | #include <linux/clocksource.h> |
| 19 | #include <linux/clockchips.h> | 19 | #include <linux/clockchips.h> |
| 20 | #include <linux/clk.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/hardware.h> | 22 | #include <asm/hardware.h> |
| 22 | #include <asm/io.h> | 23 | #include <asm/io.h> |
| @@ -86,10 +87,10 @@ static struct clocksource clocksource_imx = { | |||
| 86 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 87 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | static int __init imx_clocksource_init(void) | 90 | static int __init imx_clocksource_init(unsigned long rate) |
| 90 | { | 91 | { |
| 91 | clocksource_imx.mult = | 92 | clocksource_imx.mult = |
| 92 | clocksource_hz2mult(imx_get_perclk1(), clocksource_imx.shift); | 93 | clocksource_hz2mult(rate, clocksource_imx.shift); |
| 93 | clocksource_register(&clocksource_imx); | 94 | clocksource_register(&clocksource_imx); |
| 94 | 95 | ||
| 95 | return 0; | 96 | return 0; |
| @@ -174,9 +175,9 @@ static struct clock_event_device clockevent_imx = { | |||
| 174 | .rating = 200, | 175 | .rating = 200, |
| 175 | }; | 176 | }; |
| 176 | 177 | ||
| 177 | static int __init imx_clockevent_init(void) | 178 | static int __init imx_clockevent_init(unsigned long rate) |
| 178 | { | 179 | { |
| 179 | clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC, | 180 | clockevent_imx.mult = div_sc(rate, NSEC_PER_SEC, |
| 180 | clockevent_imx.shift); | 181 | clockevent_imx.shift); |
| 181 | clockevent_imx.max_delta_ns = | 182 | clockevent_imx.max_delta_ns = |
| 182 | clockevent_delta2ns(0xfffffffe, &clockevent_imx); | 183 | clockevent_delta2ns(0xfffffffe, &clockevent_imx); |
| @@ -190,13 +191,23 @@ static int __init imx_clockevent_init(void) | |||
| 190 | return 0; | 191 | return 0; |
| 191 | } | 192 | } |
| 192 | 193 | ||
| 194 | extern int imx_clocks_init(void); | ||
| 193 | 195 | ||
| 194 | static void __init imx_timer_init(void) | 196 | static void __init imx_timer_init(void) |
| 195 | { | 197 | { |
| 198 | struct clk *clk; | ||
| 199 | unsigned long rate; | ||
| 200 | |||
| 201 | imx_clocks_init(); | ||
| 202 | |||
| 203 | clk = clk_get(NULL, "perclk1"); | ||
| 204 | clk_enable(clk); | ||
| 205 | rate = clk_get_rate(clk); | ||
| 206 | |||
| 196 | imx_timer_hardware_init(); | 207 | imx_timer_hardware_init(); |
| 197 | imx_clocksource_init(); | 208 | imx_clocksource_init(rate); |
| 198 | 209 | ||
| 199 | imx_clockevent_init(); | 210 | imx_clockevent_init(rate); |
| 200 | 211 | ||
| 201 | /* | 212 | /* |
| 202 | * Make irqs happen for the system timer | 213 | * Make irqs happen for the system timer |
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 95f33e87a99c..ef2f6fc86541 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/mmc/host.h> | 42 | #include <linux/mmc/host.h> |
| 43 | #include <linux/mmc/card.h> | 43 | #include <linux/mmc/card.h> |
| 44 | #include <linux/delay.h> | 44 | #include <linux/delay.h> |
| 45 | #include <linux/clk.h> | ||
| 45 | 46 | ||
| 46 | #include <asm/dma.h> | 47 | #include <asm/dma.h> |
| 47 | #include <asm/io.h> | 48 | #include <asm/io.h> |
| @@ -92,6 +93,8 @@ struct imxmci_host { | |||
| 92 | unsigned char actual_bus_width; | 93 | unsigned char actual_bus_width; |
| 93 | 94 | ||
| 94 | int prev_cmd_code; | 95 | int prev_cmd_code; |
| 96 | |||
| 97 | struct clk *clk; | ||
| 95 | }; | 98 | }; |
| 96 | 99 | ||
| 97 | #define IMXMCI_PEND_IRQ_b 0 | 100 | #define IMXMCI_PEND_IRQ_b 0 |
| @@ -841,7 +844,7 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
| 841 | /* The prescaler is 5 for PERCLK2 equal to 96MHz | 844 | /* The prescaler is 5 for PERCLK2 equal to 96MHz |
| 842 | * then 96MHz / 5 = 19.2 MHz | 845 | * then 96MHz / 5 = 19.2 MHz |
| 843 | */ | 846 | */ |
| 844 | clk=imx_get_perclk2(); | 847 | clk = clk_get_rate(host->clk); |
| 845 | prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE; | 848 | prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE; |
| 846 | switch(prescaler) { | 849 | switch(prescaler) { |
| 847 | case 0: | 850 | case 0: |
| @@ -994,6 +997,13 @@ static int imxmci_probe(struct platform_device *pdev) | |||
| 994 | host->res = r; | 997 | host->res = r; |
| 995 | host->irq = irq; | 998 | host->irq = irq; |
| 996 | 999 | ||
| 1000 | host->clk = clk_get(&pdev->dev, "perclk2"); | ||
| 1001 | if (IS_ERR(host->clk)) { | ||
| 1002 | ret = PTR_ERR(host->clk); | ||
| 1003 | goto out; | ||
| 1004 | } | ||
| 1005 | clk_enable(host->clk); | ||
| 1006 | |||
| 997 | imx_gpio_mode(PB8_PF_SD_DAT0); | 1007 | imx_gpio_mode(PB8_PF_SD_DAT0); |
| 998 | imx_gpio_mode(PB9_PF_SD_DAT1); | 1008 | imx_gpio_mode(PB9_PF_SD_DAT1); |
| 999 | imx_gpio_mode(PB10_PF_SD_DAT2); | 1009 | imx_gpio_mode(PB10_PF_SD_DAT2); |
| @@ -1053,6 +1063,10 @@ out: | |||
| 1053 | imx_dma_free(host->dma); | 1063 | imx_dma_free(host->dma); |
| 1054 | host->dma_allocated=0; | 1064 | host->dma_allocated=0; |
| 1055 | } | 1065 | } |
| 1066 | if (host->clk) { | ||
| 1067 | clk_disable(host->clk); | ||
| 1068 | clk_put(host->clk); | ||
| 1069 | } | ||
| 1056 | } | 1070 | } |
| 1057 | if (mmc) | 1071 | if (mmc) |
| 1058 | mmc_free_host(mmc); | 1072 | mmc_free_host(mmc); |
| @@ -1082,6 +1096,9 @@ static int imxmci_remove(struct platform_device *pdev) | |||
| 1082 | 1096 | ||
| 1083 | tasklet_kill(&host->tasklet); | 1097 | tasklet_kill(&host->tasklet); |
| 1084 | 1098 | ||
| 1099 | clk_disable(host->clk); | ||
| 1100 | clk_put(host->clk); | ||
| 1101 | |||
| 1085 | release_resource(host->res); | 1102 | release_resource(host->res); |
| 1086 | 1103 | ||
| 1087 | mmc_free_host(mmc); | 1104 | mmc_free_host(mmc); |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 8d6cb745bd93..9e2162ebf1bb 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <linux/tty_flip.h> | 40 | #include <linux/tty_flip.h> |
| 41 | #include <linux/serial_core.h> | 41 | #include <linux/serial_core.h> |
| 42 | #include <linux/serial.h> | 42 | #include <linux/serial.h> |
| 43 | #include <linux/clk.h> | ||
| 43 | 44 | ||
| 44 | #include <asm/io.h> | 45 | #include <asm/io.h> |
| 45 | #include <asm/irq.h> | 46 | #include <asm/irq.h> |
| @@ -184,6 +185,7 @@ struct imx_port { | |||
| 184 | unsigned int old_status; | 185 | unsigned int old_status; |
| 185 | int txirq,rxirq,rtsirq; | 186 | int txirq,rxirq,rtsirq; |
| 186 | int have_rtscts:1; | 187 | int have_rtscts:1; |
| 188 | struct clk *clk; | ||
| 187 | }; | 189 | }; |
| 188 | 190 | ||
| 189 | /* | 191 | /* |
| @@ -479,7 +481,8 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | |||
| 479 | * RFDIV is set such way to satisfy requested uartclk value | 481 | * RFDIV is set such way to satisfy requested uartclk value |
| 480 | */ | 482 | */ |
| 481 | val = TXTL << 10 | RXTL; | 483 | val = TXTL << 10 | RXTL; |
| 482 | ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk; | 484 | ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2) |
| 485 | / sport->port.uartclk; | ||
| 483 | 486 | ||
| 484 | if(!ufcr_rfdiv) | 487 | if(!ufcr_rfdiv) |
| 485 | ufcr_rfdiv = 1; | 488 | ufcr_rfdiv = 1; |
| @@ -916,7 +919,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, | |||
| 916 | else | 919 | else |
| 917 | ucfr_rfdiv = 6 - ucfr_rfdiv; | 920 | ucfr_rfdiv = 6 - ucfr_rfdiv; |
| 918 | 921 | ||
| 919 | uartclk = imx_get_perclk1(); | 922 | uartclk = clk_get_rate(sport->clk); |
| 920 | uartclk /= ucfr_rfdiv; | 923 | uartclk /= ucfr_rfdiv; |
| 921 | 924 | ||
| 922 | { /* | 925 | { /* |
| @@ -1054,7 +1057,15 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
| 1054 | init_timer(&sport->timer); | 1057 | init_timer(&sport->timer); |
| 1055 | sport->timer.function = imx_timeout; | 1058 | sport->timer.function = imx_timeout; |
| 1056 | sport->timer.data = (unsigned long)sport; | 1059 | sport->timer.data = (unsigned long)sport; |
| 1057 | sport->port.uartclk = imx_get_perclk1(); | 1060 | |
| 1061 | sport->clk = clk_get(&pdev->dev, "uart_clk"); | ||
| 1062 | if (IS_ERR(sport->clk)) { | ||
| 1063 | ret = PTR_ERR(sport->clk); | ||
| 1064 | goto unmap; | ||
| 1065 | } | ||
| 1066 | clk_enable(sport->clk); | ||
| 1067 | |||
| 1068 | sport->port.uartclk = clk_get_rate(sport->clk); | ||
| 1058 | 1069 | ||
| 1059 | imx_ports[pdev->id] = sport; | 1070 | imx_ports[pdev->id] = sport; |
| 1060 | 1071 | ||
| @@ -1069,6 +1080,8 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
| 1069 | platform_set_drvdata(pdev, &sport->port); | 1080 | platform_set_drvdata(pdev, &sport->port); |
| 1070 | 1081 | ||
| 1071 | return 0; | 1082 | return 0; |
| 1083 | unmap: | ||
| 1084 | iounmap(sport->port.membase); | ||
| 1072 | free: | 1085 | free: |
| 1073 | kfree(sport); | 1086 | kfree(sport); |
| 1074 | 1087 | ||
| @@ -1084,8 +1097,12 @@ static int serial_imx_remove(struct platform_device *pdev) | |||
| 1084 | 1097 | ||
| 1085 | platform_set_drvdata(pdev, NULL); | 1098 | platform_set_drvdata(pdev, NULL); |
| 1086 | 1099 | ||
| 1087 | if (sport) | 1100 | if (sport) { |
| 1088 | uart_remove_one_port(&imx_reg, &sport->port); | 1101 | uart_remove_one_port(&imx_reg, &sport->port); |
| 1102 | clk_put(sport->clk); | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | clk_disable(sport->clk); | ||
| 1089 | 1106 | ||
| 1090 | if (pdata->exit) | 1107 | if (pdata->exit) |
| 1091 | pdata->exit(pdev); | 1108 | pdata->exit(pdev); |
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index c730d05bfeb6..bd0729b6b6ed 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/spi/spi.h> | 29 | #include <linux/spi/spi.h> |
| 30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
| 31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
| 32 | #include <linux/clk.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
| 34 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
| @@ -250,6 +251,8 @@ struct driver_data { | |||
| 250 | int tx_dma_needs_unmap; | 251 | int tx_dma_needs_unmap; |
| 251 | size_t tx_map_len; | 252 | size_t tx_map_len; |
| 252 | u32 dummy_dma_buf ____cacheline_aligned; | 253 | u32 dummy_dma_buf ____cacheline_aligned; |
| 254 | |||
| 255 | struct clk *clk; | ||
| 253 | }; | 256 | }; |
| 254 | 257 | ||
| 255 | /* Runtime state */ | 258 | /* Runtime state */ |
| @@ -855,15 +858,15 @@ static irqreturn_t spi_int(int irq, void *dev_id) | |||
| 855 | return drv_data->transfer_handler(drv_data); | 858 | return drv_data->transfer_handler(drv_data); |
| 856 | } | 859 | } |
| 857 | 860 | ||
| 858 | static inline u32 spi_speed_hz(u32 data_rate) | 861 | static inline u32 spi_speed_hz(struct driver_data *drv_data, u32 data_rate) |
| 859 | { | 862 | { |
| 860 | return imx_get_perclk2() / (4 << ((data_rate) >> 13)); | 863 | return clk_get_rate(drv_data->clk) / (4 << ((data_rate) >> 13)); |
| 861 | } | 864 | } |
| 862 | 865 | ||
| 863 | static u32 spi_data_rate(u32 speed_hz) | 866 | static u32 spi_data_rate(struct driver_data *drv_data, u32 speed_hz) |
| 864 | { | 867 | { |
| 865 | u32 div; | 868 | u32 div; |
| 866 | u32 quantized_hz = imx_get_perclk2() >> 2; | 869 | u32 quantized_hz = clk_get_rate(drv_data->clk) >> 2; |
| 867 | 870 | ||
| 868 | for (div = SPI_PERCLK2_DIV_MIN; | 871 | for (div = SPI_PERCLK2_DIV_MIN; |
| 869 | div <= SPI_PERCLK2_DIV_MAX; | 872 | div <= SPI_PERCLK2_DIV_MAX; |
| @@ -947,7 +950,7 @@ static void pump_transfers(unsigned long data) | |||
| 947 | tmp = transfer->speed_hz; | 950 | tmp = transfer->speed_hz; |
| 948 | if (tmp == 0) | 951 | if (tmp == 0) |
| 949 | tmp = chip->max_speed_hz; | 952 | tmp = chip->max_speed_hz; |
| 950 | tmp = spi_data_rate(tmp); | 953 | tmp = spi_data_rate(drv_data, tmp); |
| 951 | u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); | 954 | u32_EDIT(control, SPI_CONTROL_DATARATE, tmp); |
| 952 | 955 | ||
| 953 | writel(control, regs + SPI_CONTROL); | 956 | writel(control, regs + SPI_CONTROL); |
| @@ -1109,7 +1112,7 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) | |||
| 1109 | msg->actual_length = 0; | 1112 | msg->actual_length = 0; |
| 1110 | 1113 | ||
| 1111 | /* Per transfer setup check */ | 1114 | /* Per transfer setup check */ |
| 1112 | min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN); | 1115 | min_speed_hz = spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN); |
| 1113 | max_speed_hz = spi->max_speed_hz; | 1116 | max_speed_hz = spi->max_speed_hz; |
| 1114 | list_for_each_entry(trans, &msg->transfers, transfer_list) { | 1117 | list_for_each_entry(trans, &msg->transfers, transfer_list) { |
| 1115 | tmp = trans->bits_per_word; | 1118 | tmp = trans->bits_per_word; |
| @@ -1176,6 +1179,7 @@ msg_rejected: | |||
| 1176 | applied and notified to the calling driver. */ | 1179 | applied and notified to the calling driver. */ |
| 1177 | static int setup(struct spi_device *spi) | 1180 | static int setup(struct spi_device *spi) |
| 1178 | { | 1181 | { |
| 1182 | struct driver_data *drv_data = spi_master_get_devdata(spi->master); | ||
| 1179 | struct spi_imx_chip *chip_info; | 1183 | struct spi_imx_chip *chip_info; |
| 1180 | struct chip_data *chip; | 1184 | struct chip_data *chip; |
| 1181 | int first_setup = 0; | 1185 | int first_setup = 0; |
| @@ -1304,14 +1308,14 @@ static int setup(struct spi_device *spi) | |||
| 1304 | chip->n_bytes = (tmp <= 8) ? 1 : 2; | 1308 | chip->n_bytes = (tmp <= 8) ? 1 : 2; |
| 1305 | 1309 | ||
| 1306 | /* SPI datarate */ | 1310 | /* SPI datarate */ |
| 1307 | tmp = spi_data_rate(spi->max_speed_hz); | 1311 | tmp = spi_data_rate(drv_data, spi->max_speed_hz); |
| 1308 | if (tmp == SPI_CONTROL_DATARATE_BAD) { | 1312 | if (tmp == SPI_CONTROL_DATARATE_BAD) { |
| 1309 | status = -EINVAL; | 1313 | status = -EINVAL; |
| 1310 | dev_err(&spi->dev, | 1314 | dev_err(&spi->dev, |
| 1311 | "setup - " | 1315 | "setup - " |
| 1312 | "HW min speed (%d Hz) exceeds required " | 1316 | "HW min speed (%d Hz) exceeds required " |
| 1313 | "max speed (%d Hz)\n", | 1317 | "max speed (%d Hz)\n", |
| 1314 | spi_speed_hz(SPI_CONTROL_DATARATE_MIN), | 1318 | spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), |
| 1315 | spi->max_speed_hz); | 1319 | spi->max_speed_hz); |
| 1316 | if (first_setup) | 1320 | if (first_setup) |
| 1317 | goto err_first_setup; | 1321 | goto err_first_setup; |
| @@ -1321,7 +1325,7 @@ static int setup(struct spi_device *spi) | |||
| 1321 | } else { | 1325 | } else { |
| 1322 | u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); | 1326 | u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp); |
| 1323 | /* Actual rounded max_speed_hz */ | 1327 | /* Actual rounded max_speed_hz */ |
| 1324 | tmp = spi_speed_hz(tmp); | 1328 | tmp = spi_speed_hz(drv_data, tmp); |
| 1325 | spi->max_speed_hz = tmp; | 1329 | spi->max_speed_hz = tmp; |
| 1326 | chip->max_speed_hz = tmp; | 1330 | chip->max_speed_hz = tmp; |
| 1327 | } | 1331 | } |
| @@ -1352,7 +1356,7 @@ static int setup(struct spi_device *spi) | |||
| 1352 | chip->period & SPI_PERIOD_WAIT, | 1356 | chip->period & SPI_PERIOD_WAIT, |
| 1353 | spi->mode, | 1357 | spi->mode, |
| 1354 | spi->bits_per_word, | 1358 | spi->bits_per_word, |
| 1355 | spi_speed_hz(SPI_CONTROL_DATARATE_MIN), | 1359 | spi_speed_hz(drv_data, SPI_CONTROL_DATARATE_MIN), |
| 1356 | spi->max_speed_hz); | 1360 | spi->max_speed_hz); |
| 1357 | return status; | 1361 | return status; |
| 1358 | 1362 | ||
| @@ -1465,6 +1469,14 @@ static int __init spi_imx_probe(struct platform_device *pdev) | |||
| 1465 | goto err_no_pdata; | 1469 | goto err_no_pdata; |
| 1466 | } | 1470 | } |
| 1467 | 1471 | ||
| 1472 | drv_data->clk = clk_get(&pdev->dev, "perclk2"); | ||
| 1473 | if (IS_ERR(drv_data->clk)) { | ||
| 1474 | dev_err(&pdev->dev, "probe - cannot get get\n"); | ||
| 1475 | status = PTR_ERR(drv_data->clk); | ||
| 1476 | goto err_no_clk; | ||
| 1477 | } | ||
| 1478 | clk_enable(drv_data->clk); | ||
| 1479 | |||
| 1468 | /* Allocate master with space for drv_data */ | 1480 | /* Allocate master with space for drv_data */ |
| 1469 | master = spi_alloc_master(dev, sizeof(struct driver_data)); | 1481 | master = spi_alloc_master(dev, sizeof(struct driver_data)); |
| 1470 | if (!master) { | 1482 | if (!master) { |
| @@ -1623,6 +1635,9 @@ err_no_iores: | |||
| 1623 | spi_master_put(master); | 1635 | spi_master_put(master); |
| 1624 | 1636 | ||
| 1625 | err_no_pdata: | 1637 | err_no_pdata: |
| 1638 | clk_disable(drv_data->clk); | ||
| 1639 | clk_put(drv_data->clk); | ||
| 1640 | err_no_clk: | ||
| 1626 | err_no_mem: | 1641 | err_no_mem: |
| 1627 | return status; | 1642 | return status; |
| 1628 | } | 1643 | } |
| @@ -1662,6 +1677,9 @@ static int __exit spi_imx_remove(struct platform_device *pdev) | |||
| 1662 | if (irq >= 0) | 1677 | if (irq >= 0) |
| 1663 | free_irq(irq, drv_data); | 1678 | free_irq(irq, drv_data); |
| 1664 | 1679 | ||
| 1680 | clk_disable(drv_data->clk); | ||
| 1681 | clk_put(drv_data->clk); | ||
| 1682 | |||
| 1665 | /* Release map resources */ | 1683 | /* Release map resources */ |
| 1666 | iounmap(drv_data->regs); | 1684 | iounmap(drv_data->regs); |
| 1667 | release_resource(drv_data->ioarea); | 1685 | release_resource(drv_data->ioarea); |
diff --git a/include/asm-arm/arch-imx/hardware.h b/include/asm-arm/arch-imx/hardware.h index adffb6acf42a..6542ca5e8c33 100644 --- a/include/asm-arm/arch-imx/hardware.h +++ b/include/asm-arm/arch-imx/hardware.h | |||
| @@ -73,14 +73,6 @@ | |||
| 73 | */ | 73 | */ |
| 74 | extern void imx_gpio_mode( int gpio_mode ); | 74 | extern void imx_gpio_mode( int gpio_mode ); |
| 75 | 75 | ||
| 76 | /* get frequencies in Hz */ | ||
| 77 | extern unsigned int imx_get_system_clk(void); | ||
| 78 | extern unsigned int imx_get_mcu_clk(void); | ||
| 79 | extern unsigned int imx_get_perclk1(void); /* UART[12], Timer[12], PWM */ | ||
| 80 | extern unsigned int imx_get_perclk2(void); /* LCD, SD, SPI[12] */ | ||
| 81 | extern unsigned int imx_get_perclk3(void); /* SSI */ | ||
| 82 | extern unsigned int imx_get_hclk(void); /* SDRAM, CSI, Memory Stick,*/ | ||
| 83 | /* I2C, DMA */ | ||
| 84 | #endif | 76 | #endif |
| 85 | 77 | ||
| 86 | #define MAXIRQNUM 62 | 78 | #define MAXIRQNUM 62 |
