]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/mips/ar7/clock.c
MIPS: AR7: Implement clock API
[mv-sheeva.git] / arch / mips / ar7 / clock.c
index cc65c8eb391b06ef8a42bfe88542ed25a36de0da..fc0e7154e8d69835c56eb45891a9e98beca0e82f 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;
 }