diff options
author | Florian Fainelli <florian@openwrt.org> | 2010-01-27 03:10:06 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-02-27 06:53:16 -0500 |
commit | 780019ddf02f214ad61e641b57b8ac30c837e2a7 (patch) | |
tree | 2d0a01efc4d508057bcfaa7b3df5b3e490c249ed /arch/mips/ar7 | |
parent | 5f3c909881d5deebb9a3ddc836a15937e76daefc (diff) |
MIPS: AR7: Implement clock API
This patch makes the ar7 clock code implement the Linux clk API. Drivers
using the various clocks available in the SoC are updated accordingly.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Acked-by: Wim Van Sebroeck <wim@iguana.be>
To: linux-mips@linux-mips.org
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: netdev@vger.kernel.org
Cc: David Miller <davem@davemloft.net>
Patchwork: http://patchwork.linux-mips.org/patch/881/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/ar7')
-rw-r--r-- | arch/mips/ar7/clock.c | 109 | ||||
-rw-r--r-- | arch/mips/ar7/platform.c | 10 | ||||
-rw-r--r-- | arch/mips/ar7/time.c | 12 |
3 files changed, 99 insertions, 32 deletions
diff --git a/arch/mips/ar7/clock.c b/arch/mips/ar7/clock.c index cc65c8eb391b..fc0e7154e8d6 100644 --- a/arch/mips/ar7/clock.c +++ b/arch/mips/ar7/clock.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> | 2 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> |
3 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> | 3 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> |
4 | * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -24,6 +25,8 @@ | |||
24 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
25 | #include <linux/gcd.h> | 26 | #include <linux/gcd.h> |
26 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/err.h> | ||
29 | #include <linux/clk.h> | ||
27 | 30 | ||
28 | #include <asm/addrspace.h> | 31 | #include <asm/addrspace.h> |
29 | #include <asm/mach-ar7/ar7.h> | 32 | #include <asm/mach-ar7/ar7.h> |
@@ -94,12 +97,16 @@ struct tnetd7200_clocks { | |||
94 | struct tnetd7200_clock usb; | 97 | struct tnetd7200_clock usb; |
95 | }; | 98 | }; |
96 | 99 | ||
97 | int ar7_cpu_clock = 150000000; | 100 | static struct clk bus_clk = { |
98 | EXPORT_SYMBOL(ar7_cpu_clock); | 101 | .rate = 125000000, |
99 | int ar7_bus_clock = 125000000; | 102 | }; |
100 | EXPORT_SYMBOL(ar7_bus_clock); | 103 | |
101 | int ar7_dsp_clock; | 104 | static struct clk cpu_clk = { |
102 | EXPORT_SYMBOL(ar7_dsp_clock); | 105 | .rate = 150000000, |
106 | }; | ||
107 | |||
108 | static struct clk dsp_clk; | ||
109 | static struct clk vbus_clk; | ||
103 | 110 | ||
104 | static void approximate(int base, int target, int *prediv, | 111 | static void approximate(int base, int target, int *prediv, |
105 | int *postdiv, int *mul) | 112 | int *postdiv, int *mul) |
@@ -185,7 +192,7 @@ static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock, | |||
185 | base_clock = AR7_XTAL_CLOCK; | 192 | base_clock = AR7_XTAL_CLOCK; |
186 | break; | 193 | break; |
187 | case BOOT_PLL_SOURCE_CPU: | 194 | case BOOT_PLL_SOURCE_CPU: |
188 | base_clock = ar7_cpu_clock; | 195 | base_clock = cpu_clk.rate; |
189 | break; | 196 | break; |
190 | } | 197 | } |
191 | 198 | ||
@@ -212,11 +219,11 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock, | |||
212 | u32 *bootcr, u32 frequency) | 219 | u32 *bootcr, u32 frequency) |
213 | { | 220 | { |
214 | int prediv, postdiv, mul; | 221 | int prediv, postdiv, mul; |
215 | int base_clock = ar7_bus_clock; | 222 | int base_clock = bus_clk.rate; |
216 | 223 | ||
217 | switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { | 224 | switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { |
218 | case BOOT_PLL_SOURCE_BUS: | 225 | case BOOT_PLL_SOURCE_BUS: |
219 | base_clock = ar7_bus_clock; | 226 | base_clock = bus_clk.rate; |
220 | break; | 227 | break; |
221 | case BOOT_PLL_SOURCE_REF: | 228 | case BOOT_PLL_SOURCE_REF: |
222 | base_clock = AR7_REF_CLOCK; | 229 | base_clock = AR7_REF_CLOCK; |
@@ -225,7 +232,7 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock, | |||
225 | base_clock = AR7_XTAL_CLOCK; | 232 | base_clock = AR7_XTAL_CLOCK; |
226 | break; | 233 | break; |
227 | case BOOT_PLL_SOURCE_CPU: | 234 | case BOOT_PLL_SOURCE_CPU: |
228 | base_clock = ar7_cpu_clock; | 235 | base_clock = cpu_clk.rate; |
229 | break; | 236 | break; |
230 | } | 237 | } |
231 | 238 | ||
@@ -247,18 +254,18 @@ static void __init tnetd7300_init_clocks(void) | |||
247 | ioremap_nocache(UR8_REGS_CLOCKS, | 254 | ioremap_nocache(UR8_REGS_CLOCKS, |
248 | sizeof(struct tnetd7300_clocks)); | 255 | sizeof(struct tnetd7300_clocks)); |
249 | 256 | ||
250 | ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT, | 257 | bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT, |
251 | &clocks->bus, bootcr, AR7_AFE_CLOCK); | 258 | &clocks->bus, bootcr, AR7_AFE_CLOCK); |
252 | 259 | ||
253 | if (*bootcr & BOOT_PLL_ASYNC_MODE) | 260 | if (*bootcr & BOOT_PLL_ASYNC_MODE) |
254 | ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT, | 261 | cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT, |
255 | &clocks->cpu, bootcr, AR7_AFE_CLOCK); | 262 | &clocks->cpu, bootcr, AR7_AFE_CLOCK); |
256 | else | 263 | else |
257 | ar7_cpu_clock = ar7_bus_clock; | 264 | cpu_clk.rate = bus_clk.rate; |
258 | 265 | ||
259 | if (ar7_dsp_clock == 250000000) | 266 | if (dsp_clk.rate == 250000000) |
260 | tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp, | 267 | tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp, |
261 | bootcr, ar7_dsp_clock); | 268 | bootcr, dsp_clk.rate); |
262 | 269 | ||
263 | iounmap(clocks); | 270 | iounmap(clocks); |
264 | iounmap(bootcr); | 271 | iounmap(bootcr); |
@@ -343,20 +350,20 @@ static void __init tnetd7200_init_clocks(void) | |||
343 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | 350 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); |
344 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, | 351 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, |
345 | &dsp_prediv, &dsp_postdiv, &dsp_mul); | 352 | &dsp_prediv, &dsp_postdiv, &dsp_mul); |
346 | ar7_bus_clock = | 353 | bus_clk.rate = |
347 | ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv; | 354 | ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv; |
348 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | 355 | tnetd7200_set_clock(dsp_base, &clocks->dsp, |
349 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2, | 356 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2, |
350 | ar7_bus_clock); | 357 | bus_clk.rate); |
351 | 358 | ||
352 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); | 359 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); |
353 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, | 360 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, |
354 | &cpu_postdiv, &cpu_mul); | 361 | &cpu_postdiv, &cpu_mul); |
355 | ar7_cpu_clock = | 362 | cpu_clk.rate = |
356 | ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv; | 363 | ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv; |
357 | tnetd7200_set_clock(cpu_base, &clocks->cpu, | 364 | tnetd7200_set_clock(cpu_base, &clocks->cpu, |
358 | cpu_prediv, cpu_postdiv, -1, cpu_mul, | 365 | cpu_prediv, cpu_postdiv, -1, cpu_mul, |
359 | ar7_cpu_clock); | 366 | cpu_clk.rate); |
360 | 367 | ||
361 | } else | 368 | } else |
362 | if (*bootcr & BOOT_PLL_2TO1_MODE) { | 369 | if (*bootcr & BOOT_PLL_2TO1_MODE) { |
@@ -365,48 +372,90 @@ static void __init tnetd7200_init_clocks(void) | |||
365 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); | 372 | printk(KERN_INFO "Clocks: Setting CPU clock\n"); |
366 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, | 373 | calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, |
367 | &cpu_postdiv, &cpu_mul); | 374 | &cpu_postdiv, &cpu_mul); |
368 | ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul) | 375 | cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul) |
369 | / cpu_postdiv; | 376 | / cpu_postdiv; |
370 | tnetd7200_set_clock(cpu_base, &clocks->cpu, | 377 | tnetd7200_set_clock(cpu_base, &clocks->cpu, |
371 | cpu_prediv, cpu_postdiv, -1, cpu_mul, | 378 | cpu_prediv, cpu_postdiv, -1, cpu_mul, |
372 | ar7_cpu_clock); | 379 | cpu_clk.rate); |
373 | 380 | ||
374 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | 381 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); |
375 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, | 382 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, |
376 | &dsp_postdiv, &dsp_mul); | 383 | &dsp_postdiv, &dsp_mul); |
377 | ar7_bus_clock = ar7_cpu_clock / 2; | 384 | bus_clk.rate = cpu_clk.rate / 2; |
378 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | 385 | tnetd7200_set_clock(dsp_base, &clocks->dsp, |
379 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, | 386 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, |
380 | dsp_mul * 2, ar7_bus_clock); | 387 | dsp_mul * 2, bus_clk.rate); |
381 | } else { | 388 | } else { |
382 | printk(KERN_INFO "Clocks: Sync 1:1 mode\n"); | 389 | printk(KERN_INFO "Clocks: Sync 1:1 mode\n"); |
383 | 390 | ||
384 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); | 391 | printk(KERN_INFO "Clocks: Setting DSP clock\n"); |
385 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, | 392 | calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, |
386 | &dsp_postdiv, &dsp_mul); | 393 | &dsp_postdiv, &dsp_mul); |
387 | ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul) | 394 | bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul) |
388 | / dsp_postdiv; | 395 | / dsp_postdiv; |
389 | tnetd7200_set_clock(dsp_base, &clocks->dsp, | 396 | tnetd7200_set_clock(dsp_base, &clocks->dsp, |
390 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, | 397 | dsp_prediv, dsp_postdiv * 2, dsp_postdiv, |
391 | dsp_mul * 2, ar7_bus_clock); | 398 | dsp_mul * 2, bus_clk.rate); |
392 | 399 | ||
393 | ar7_cpu_clock = ar7_bus_clock; | 400 | cpu_clk.rate = bus_clk.rate; |
394 | } | 401 | } |
395 | 402 | ||
396 | printk(KERN_INFO "Clocks: Setting USB clock\n"); | 403 | printk(KERN_INFO "Clocks: Setting USB clock\n"); |
397 | usb_base = ar7_bus_clock; | 404 | usb_base = bus_clk.rate; |
398 | calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv, | 405 | calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv, |
399 | &usb_postdiv, &usb_mul); | 406 | &usb_postdiv, &usb_mul); |
400 | tnetd7200_set_clock(usb_base, &clocks->usb, | 407 | tnetd7200_set_clock(usb_base, &clocks->usb, |
401 | usb_prediv, usb_postdiv, -1, usb_mul, | 408 | usb_prediv, usb_postdiv, -1, usb_mul, |
402 | TNETD7200_DEF_USB_CLK); | 409 | TNETD7200_DEF_USB_CLK); |
403 | 410 | ||
404 | ar7_dsp_clock = ar7_cpu_clock; | 411 | dsp_clk.rate = cpu_clk.rate; |
405 | 412 | ||
406 | iounmap(clocks); | 413 | iounmap(clocks); |
407 | iounmap(bootcr); | 414 | iounmap(bootcr); |
408 | } | 415 | } |
409 | 416 | ||
417 | /* | ||
418 | * Linux clock API | ||
419 | */ | ||
420 | int clk_enable(struct clk *clk) | ||
421 | { | ||
422 | return 0; | ||
423 | } | ||
424 | EXPORT_SYMBOL(clk_enable); | ||
425 | |||
426 | void clk_disable(struct clk *clk) | ||
427 | { | ||
428 | } | ||
429 | EXPORT_SYMBOL(clk_disable); | ||
430 | |||
431 | unsigned long clk_get_rate(struct clk *clk) | ||
432 | { | ||
433 | return clk->rate; | ||
434 | } | ||
435 | EXPORT_SYMBOL(clk_get_rate); | ||
436 | |||
437 | struct clk *clk_get(struct device *dev, const char *id) | ||
438 | { | ||
439 | if (!strcmp(id, "bus")) | ||
440 | return &bus_clk; | ||
441 | /* cpmac and vbus share the same rate */ | ||
442 | if (!strcmp(id, "cpmac")) | ||
443 | return &vbus_clk; | ||
444 | if (!strcmp(id, "cpu")) | ||
445 | return &cpu_clk; | ||
446 | if (!strcmp(id, "dsp")); | ||
447 | return &dsp_clk; | ||
448 | if (!strcmp(id, "vbus")) | ||
449 | return &vbus_clk; | ||
450 | return ERR_PTR(-ENOENT); | ||
451 | } | ||
452 | EXPORT_SYMBOL(clk_get); | ||
453 | |||
454 | void clk_put(struct clk *clk) | ||
455 | { | ||
456 | } | ||
457 | EXPORT_SYMBOL(clk_put); | ||
458 | |||
410 | int __init ar7_init_clocks(void) | 459 | int __init ar7_init_clocks(void) |
411 | { | 460 | { |
412 | switch (ar7_chip_id()) { | 461 | switch (ar7_chip_id()) { |
@@ -415,12 +464,14 @@ int __init ar7_init_clocks(void) | |||
415 | tnetd7200_init_clocks(); | 464 | tnetd7200_init_clocks(); |
416 | break; | 465 | break; |
417 | case AR7_CHIP_7300: | 466 | case AR7_CHIP_7300: |
418 | ar7_dsp_clock = tnetd7300_dsp_clock(); | 467 | dsp_clk.rate = tnetd7300_dsp_clock(); |
419 | tnetd7300_init_clocks(); | 468 | tnetd7300_init_clocks(); |
420 | break; | 469 | break; |
421 | default: | 470 | default: |
422 | break; | 471 | break; |
423 | } | 472 | } |
473 | /* adjust vbus clock rate */ | ||
474 | vbus_clk.rate = bus_clk.rate / 2; | ||
424 | 475 | ||
425 | return 0; | 476 | return 0; |
426 | } | 477 | } |
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index 5a3fa9407710..1db191cd49c3 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/phy.h> | 35 | #include <linux/phy.h> |
36 | #include <linux/phy_fixed.h> | 36 | #include <linux/phy_fixed.h> |
37 | #include <linux/gpio.h> | 37 | #include <linux/gpio.h> |
38 | #include <linux/clk.h> | ||
38 | 39 | ||
39 | #include <asm/addrspace.h> | 40 | #include <asm/addrspace.h> |
40 | #include <asm/mach-ar7/ar7.h> | 41 | #include <asm/mach-ar7/ar7.h> |
@@ -507,13 +508,18 @@ static int __init ar7_register_devices(void) | |||
507 | u32 *bootcr, val; | 508 | u32 *bootcr, val; |
508 | #ifdef CONFIG_SERIAL_8250 | 509 | #ifdef CONFIG_SERIAL_8250 |
509 | static struct uart_port uart_port[2] __initdata; | 510 | static struct uart_port uart_port[2] __initdata; |
511 | struct clk *bus_clk; | ||
510 | 512 | ||
511 | memset(uart_port, 0, sizeof(struct uart_port) * 2); | 513 | memset(uart_port, 0, sizeof(struct uart_port) * 2); |
512 | 514 | ||
515 | bus_clk = clk_get(NULL, "bus"); | ||
516 | if (IS_ERR(bus_clk)) | ||
517 | panic("unable to get bus clk\n"); | ||
518 | |||
513 | uart_port[0].type = PORT_16550A; | 519 | uart_port[0].type = PORT_16550A; |
514 | uart_port[0].line = 0; | 520 | uart_port[0].line = 0; |
515 | uart_port[0].irq = AR7_IRQ_UART0; | 521 | uart_port[0].irq = AR7_IRQ_UART0; |
516 | uart_port[0].uartclk = ar7_bus_freq() / 2; | 522 | uart_port[0].uartclk = clk_get_rate(bus_clk) / 2; |
517 | uart_port[0].iotype = UPIO_MEM32; | 523 | uart_port[0].iotype = UPIO_MEM32; |
518 | uart_port[0].mapbase = AR7_REGS_UART0; | 524 | uart_port[0].mapbase = AR7_REGS_UART0; |
519 | uart_port[0].membase = ioremap(uart_port[0].mapbase, 256); | 525 | uart_port[0].membase = ioremap(uart_port[0].mapbase, 256); |
@@ -528,7 +534,7 @@ static int __init ar7_register_devices(void) | |||
528 | uart_port[1].type = PORT_16550A; | 534 | uart_port[1].type = PORT_16550A; |
529 | uart_port[1].line = 1; | 535 | uart_port[1].line = 1; |
530 | uart_port[1].irq = AR7_IRQ_UART1; | 536 | uart_port[1].irq = AR7_IRQ_UART1; |
531 | uart_port[1].uartclk = ar7_bus_freq() / 2; | 537 | uart_port[1].uartclk = clk_get_rate(bus_clk) / 2; |
532 | uart_port[1].iotype = UPIO_MEM32; | 538 | uart_port[1].iotype = UPIO_MEM32; |
533 | uart_port[1].mapbase = UR8_REGS_UART1; | 539 | uart_port[1].mapbase = UR8_REGS_UART1; |
534 | uart_port[1].membase = ioremap(uart_port[1].mapbase, 256); | 540 | uart_port[1].membase = ioremap(uart_port[1].mapbase, 256); |
diff --git a/arch/mips/ar7/time.c b/arch/mips/ar7/time.c index a1fba894daa2..5fb8a0134085 100644 --- a/arch/mips/ar7/time.c +++ b/arch/mips/ar7/time.c | |||
@@ -20,11 +20,21 @@ | |||
20 | 20 | ||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include <linux/err.h> | ||
24 | #include <linux/clk.h> | ||
23 | 25 | ||
24 | #include <asm/time.h> | 26 | #include <asm/time.h> |
25 | #include <asm/mach-ar7/ar7.h> | 27 | #include <asm/mach-ar7/ar7.h> |
26 | 28 | ||
27 | void __init plat_time_init(void) | 29 | void __init plat_time_init(void) |
28 | { | 30 | { |
29 | mips_hpt_frequency = ar7_cpu_freq() / 2; | 31 | struct clk *cpu_clk; |
32 | |||
33 | cpu_clk = clk_get(NULL, "cpu"); | ||
34 | if (IS_ERR(cpu_clk)) { | ||
35 | printk(KERN_ERR "unable to get cpu clock\n"); | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | mips_hpt_frequency = clk_get_rate(cpu_clk) / 2; | ||
30 | } | 40 | } |