MIPS: AR7: Implement clock API
authorFlorian Fainelli <florian@openwrt.org>
Wed, 27 Jan 2010 08:10:06 +0000 (09:10 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Sat, 27 Feb 2010 11:53:16 +0000 (12:53 +0100)
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>
arch/mips/ar7/clock.c
arch/mips/ar7/platform.c
arch/mips/ar7/time.c
arch/mips/include/asm/mach-ar7/ar7.h
drivers/net/cpmac.c
drivers/watchdog/ar7_wdt.c

index cc65c8e..fc0e715 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
  * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
+ * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,6 +25,8 @@
 #include <linux/delay.h>
 #include <linux/gcd.h>
 #include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
 
 #include <asm/addrspace.h>
 #include <asm/mach-ar7/ar7.h>
@@ -94,12 +97,16 @@ struct tnetd7200_clocks {
        struct tnetd7200_clock usb;
 };
 
-int ar7_cpu_clock = 150000000;
-EXPORT_SYMBOL(ar7_cpu_clock);
-int ar7_bus_clock = 125000000;
-EXPORT_SYMBOL(ar7_bus_clock);
-int ar7_dsp_clock;
-EXPORT_SYMBOL(ar7_dsp_clock);
+static struct clk bus_clk = {
+       .rate   = 125000000,
+};
+
+static struct clk cpu_clk = {
+       .rate   = 150000000,
+};
+
+static struct clk dsp_clk;
+static struct clk vbus_clk;
 
 static void approximate(int base, int target, int *prediv,
                        int *postdiv, int *mul)
@@ -185,7 +192,7 @@ static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
                base_clock = AR7_XTAL_CLOCK;
                break;
        case BOOT_PLL_SOURCE_CPU:
-               base_clock = ar7_cpu_clock;
+               base_clock = cpu_clk.rate;
                break;
        }
 
@@ -212,11 +219,11 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
        u32 *bootcr, u32 frequency)
 {
        int prediv, postdiv, mul;
-       int base_clock = ar7_bus_clock;
+       int base_clock = bus_clk.rate;
 
        switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
        case BOOT_PLL_SOURCE_BUS:
-               base_clock = ar7_bus_clock;
+               base_clock = bus_clk.rate;
                break;
        case BOOT_PLL_SOURCE_REF:
                base_clock = AR7_REF_CLOCK;
@@ -225,7 +232,7 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
                base_clock = AR7_XTAL_CLOCK;
                break;
        case BOOT_PLL_SOURCE_CPU:
-               base_clock = ar7_cpu_clock;
+               base_clock = cpu_clk.rate;
                break;
        }
 
@@ -247,18 +254,18 @@ static void __init tnetd7300_init_clocks(void)
                                        ioremap_nocache(UR8_REGS_CLOCKS,
                                        sizeof(struct tnetd7300_clocks));
 
-       ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
+       bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
                &clocks->bus, bootcr, AR7_AFE_CLOCK);
 
        if (*bootcr & BOOT_PLL_ASYNC_MODE)
-               ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
+               cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
                        &clocks->cpu, bootcr, AR7_AFE_CLOCK);
        else
-               ar7_cpu_clock = ar7_bus_clock;
+               cpu_clk.rate = bus_clk.rate;
 
-       if (ar7_dsp_clock == 250000000)
+       if (dsp_clk.rate == 250000000)
                tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
-                       bootcr, ar7_dsp_clock);
+                       bootcr, dsp_clk.rate);
 
        iounmap(clocks);
        iounmap(bootcr);
@@ -343,20 +350,20 @@ static void __init tnetd7200_init_clocks(void)
                printk(KERN_INFO "Clocks: Setting DSP clock\n");
                calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
                        &dsp_prediv, &dsp_postdiv, &dsp_mul);
-               ar7_bus_clock =
+               bus_clk.rate =
                        ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
                tnetd7200_set_clock(dsp_base, &clocks->dsp,
                        dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
-                       ar7_bus_clock);
+                       bus_clk.rate);
 
                printk(KERN_INFO "Clocks: Setting CPU clock\n");
                calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
                        &cpu_postdiv, &cpu_mul);
-               ar7_cpu_clock =
+               cpu_clk.rate =
                        ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
                tnetd7200_set_clock(cpu_base, &clocks->cpu,
                        cpu_prediv, cpu_postdiv, -1, cpu_mul,
-                       ar7_cpu_clock);
+                       cpu_clk.rate);
 
        } else
                if (*bootcr & BOOT_PLL_2TO1_MODE) {
@@ -365,48 +372,90 @@ static void __init tnetd7200_init_clocks(void)
                        printk(KERN_INFO "Clocks: Setting CPU clock\n");
                        calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
                                &cpu_postdiv, &cpu_mul);
-                       ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
+                       cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul)
                                                                / cpu_postdiv;
                        tnetd7200_set_clock(cpu_base, &clocks->cpu,
                                cpu_prediv, cpu_postdiv, -1, cpu_mul,
-                               ar7_cpu_clock);
+                               cpu_clk.rate);
 
                        printk(KERN_INFO "Clocks: Setting DSP clock\n");
                        calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
                                &dsp_postdiv, &dsp_mul);
-                       ar7_bus_clock = ar7_cpu_clock / 2;
+                       bus_clk.rate = cpu_clk.rate / 2;
                        tnetd7200_set_clock(dsp_base, &clocks->dsp,
                                dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
-                               dsp_mul * 2, ar7_bus_clock);
+                               dsp_mul * 2, bus_clk.rate);
                } else {
                        printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
 
                        printk(KERN_INFO "Clocks: Setting DSP clock\n");
                        calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
                                &dsp_postdiv, &dsp_mul);
-                       ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
+                       bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul)
                                                                / dsp_postdiv;
                        tnetd7200_set_clock(dsp_base, &clocks->dsp,
                                dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
-                               dsp_mul * 2, ar7_bus_clock);
+                               dsp_mul * 2, bus_clk.rate);
 
-                       ar7_cpu_clock = ar7_bus_clock;
+                       cpu_clk.rate = bus_clk.rate;
                }
 
        printk(KERN_INFO "Clocks: Setting USB clock\n");
-       usb_base = ar7_bus_clock;
+       usb_base = bus_clk.rate;
        calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
                &usb_postdiv, &usb_mul);
        tnetd7200_set_clock(usb_base, &clocks->usb,
                usb_prediv, usb_postdiv, -1, usb_mul,
                TNETD7200_DEF_USB_CLK);
 
-       ar7_dsp_clock = ar7_cpu_clock;
+       dsp_clk.rate = cpu_clk.rate;
 
        iounmap(clocks);
        iounmap(bootcr);
 }
 
+/*
+ * Linux clock API
+ */
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       if (!strcmp(id, "bus"))
+               return &bus_clk;
+       /* cpmac and vbus share the same rate */
+       if (!strcmp(id, "cpmac"))
+               return &vbus_clk;
+       if (!strcmp(id, "cpu"))
+               return &cpu_clk;
+       if (!strcmp(id, "dsp"));
+               return &dsp_clk;
+       if (!strcmp(id, "vbus"))
+               return &vbus_clk;
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
 int __init ar7_init_clocks(void)
 {
        switch (ar7_chip_id()) {
@@ -415,12 +464,14 @@ int __init ar7_init_clocks(void)
                tnetd7200_init_clocks();
                break;
        case AR7_CHIP_7300:
-               ar7_dsp_clock = tnetd7300_dsp_clock();
+               dsp_clk.rate = tnetd7300_dsp_clock();
                tnetd7300_init_clocks();
                break;
        default:
                break;
        }
+       /* adjust vbus clock rate */
+       vbus_clk.rate = bus_clk.rate / 2;
 
        return 0;
 }
index 5a3fa94..1db191c 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/phy.h>
 #include <linux/phy_fixed.h>
 #include <linux/gpio.h>
+#include <linux/clk.h>
 
 #include <asm/addrspace.h>
 #include <asm/mach-ar7/ar7.h>
@@ -507,13 +508,18 @@ static int __init ar7_register_devices(void)
        u32 *bootcr, val;
 #ifdef CONFIG_SERIAL_8250
        static struct uart_port uart_port[2] __initdata;
+       struct clk *bus_clk;
 
        memset(uart_port, 0, sizeof(struct uart_port) * 2);
 
+       bus_clk = clk_get(NULL, "bus");
+       if (IS_ERR(bus_clk))
+               panic("unable to get bus clk\n");
+
        uart_port[0].type = PORT_16550A;
        uart_port[0].line = 0;
        uart_port[0].irq = AR7_IRQ_UART0;
-       uart_port[0].uartclk = ar7_bus_freq() / 2;
+       uart_port[0].uartclk = clk_get_rate(bus_clk) / 2;
        uart_port[0].iotype = UPIO_MEM32;
        uart_port[0].mapbase = AR7_REGS_UART0;
        uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
@@ -528,7 +534,7 @@ static int __init ar7_register_devices(void)
                uart_port[1].type = PORT_16550A;
                uart_port[1].line = 1;
                uart_port[1].irq = AR7_IRQ_UART1;
-               uart_port[1].uartclk = ar7_bus_freq() / 2;
+               uart_port[1].uartclk = clk_get_rate(bus_clk) / 2;
                uart_port[1].iotype = UPIO_MEM32;
                uart_port[1].mapbase = UR8_REGS_UART1;
                uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
index a1fba89..5fb8a01 100644 (file)
 
 #include <linux/init.h>
 #include <linux/time.h>
+#include <linux/err.h>
+#include <linux/clk.h>
 
 #include <asm/time.h>
 #include <asm/mach-ar7/ar7.h>
 
 void __init plat_time_init(void)
 {
-       mips_hpt_frequency = ar7_cpu_freq() / 2;
+       struct clk *cpu_clk;
+
+       cpu_clk = clk_get(NULL, "cpu");
+       if (IS_ERR(cpu_clk)) {
+               printk(KERN_ERR "unable to get cpu clock\n");
+               return;
+       }
+
+       mips_hpt_frequency = clk_get_rate(cpu_clk) / 2;
 }
index 21cbbc7..f1cf389 100644 (file)
@@ -105,26 +105,9 @@ static inline u8 ar7_chip_rev(void)
        return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) >> 16) & 0xff;
 }
 
-static inline int ar7_cpu_freq(void)
-{
-       return ar7_cpu_clock;
-}
-
-static inline int ar7_bus_freq(void)
-{
-       return ar7_bus_clock;
-}
-
-static inline int ar7_vbus_freq(void)
-{
-       return ar7_bus_clock / 2;
-}
-#define ar7_cpmac_freq ar7_vbus_freq
-
-static inline int ar7_dsp_freq(void)
-{
-       return ar7_dsp_clock;
-}
+struct clk {
+       unsigned int    rate;
+};
 
 static inline int ar7_has_high_cpmac(void)
 {
index 8d0be26..bf2072e 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/phy_fixed.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/clk.h>
 #include <asm/gpio.h>
 #include <asm/atomic.h>
 
@@ -294,9 +295,16 @@ static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
 
 static int cpmac_mdio_reset(struct mii_bus *bus)
 {
+       struct clk *cpmac_clk;
+
+       cpmac_clk = clk_get(&bus->dev, "cpmac");
+       if (IS_ERR(cpmac_clk)) {
+               printk(KERN_ERR "unable to get cpmac clock\n");
+               return -1;
+       }
        ar7_device_reset(AR7_RESET_BIT_MDIO);
        cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
-                   MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
+                   MDIOC_CLKDIV(clk_get_rate(cpmac_clk) / 2200000 - 1));
        return 0;
 }
 
index 2e94b71..2bb95cd 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/clk.h>
 
 #include <asm/addrspace.h>
 #include <asm/mach-ar7/ar7.h>
@@ -80,6 +81,8 @@ static struct resource *ar7_regs_wdt;
 /* Pointer to the remapped WDT IO space */
 static struct ar7_wdt *ar7_wdt;
 
+static struct clk *vbus_clk;
+
 static void ar7_wdt_kick(u32 value)
 {
        WRITE_REG(ar7_wdt->kick_lock, 0x5555);
@@ -138,17 +141,19 @@ static void ar7_wdt_disable(u32 value)
 static void ar7_wdt_update_margin(int new_margin)
 {
        u32 change;
+       u32 vbus_rate;
 
-       change = new_margin * (ar7_vbus_freq() / prescale_value);
+       vbus_rate = clk_get_rate(vbus_clk);
+       change = new_margin * (vbus_rate / prescale_value);
        if (change < 1)
                change = 1;
        if (change > 0xffff)
                change = 0xffff;
        ar7_wdt_change(change);
-       margin = change * prescale_value / ar7_vbus_freq();
+       margin = change * prescale_value / vbus_rate;
        printk(KERN_INFO DRVNAME
               ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
-              margin, prescale_value, change, ar7_vbus_freq());
+              margin, prescale_value, change, vbus_rate);
 }
 
 static void ar7_wdt_enable_wdt(void)
@@ -298,6 +303,13 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
                goto out_mem_region;
        }
 
+       vbus_clk = clk_get(NULL, "vbus");
+       if (IS_ERR(vbus_clk)) {
+               printk(KERN_ERR DRVNAME ": could not get vbus clock\n");
+               rc = PTR_ERR(vbus_clk);
+               goto out_mem_region;
+       }
+
        ar7_wdt_disable_wdt();
        ar7_wdt_prescale(prescale_value);
        ar7_wdt_update_margin(margin);