[xburst] Cleanup clock module a bit and replace last users of __cpm_*
[openwrt/svn-archive/archive.git] / target / linux / xburst / files-2.6.32 / arch / mips / jz4740 / clock.c
index 853c6d8675305a6e474e660b8fea20425db488d3..49ea7171a393e58a3cf4ed45abacd0bd16fd551a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *     JZ4740 SoC TCU support
+ *     JZ4740 SoC clock support
  *
  *  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 the
 #include <linux/list.h>
 #include <linux/err.h>
 
+#include <asm/mach-jz4740/clock.h>
+
 #define JZ_REG_CLOCK_CTRL      0x00
+#define JZ_REG_CLOCK_LOW_POWER 0x04
+#define JZ_REG_CLOCK_SLEEP_CTRL        0x08
 #define JZ_REG_CLOCK_PLL       0x10
 #define JZ_REG_CLOCK_GATE      0x20
 #define JZ_REG_CLOCK_I2S       0x60
 #define JZ_CLOCK_PLL_N_OFFSET          18
 #define JZ_CLOCK_PLL_OD_OFFSET         16
 
+#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
+#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
+
+#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
+#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
+
 static void __iomem *jz_clock_base;
 static spinlock_t jz_clock_lock;
 static LIST_HEAD(jz_clocks);
 
-struct clk {
-       const char *name;
-       struct clk* parent;
-
-       uint32_t gate_bit;
-
+struct clk_ops {
        unsigned long (*get_rate)(struct clk* clk);
        unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
        int (*set_rate)(struct clk* clk, unsigned long rate);
@@ -101,6 +106,16 @@ struct clk {
        int (*disable)(struct clk* clk);
 
        int (*set_parent)(struct clk* clk, struct clk *parent);
+};
+
+struct clk {
+       const char *name;
+       struct clk* parent;
+
+       uint32_t gate_bit;
+
+       const struct clk_ops *ops;
+
        struct list_head list;
 };
 
@@ -220,8 +235,6 @@ static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
        return jz_clk_pll_get_rate(clk->parent) >> 1;
 }
 
-
-
 static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
 
 static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
@@ -276,33 +289,51 @@ static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
+static struct clk_ops jz_clk_static_ops = {
+       .get_rate = jz_clk_static_get_rate,
+       .enable = jz_clk_enable_gating,
+       .disable = jz_clk_disable_gating,
+};
 
 static struct static_clk jz_clk_ext = {
        .clk = {
                .name = "ext",
-               .get_rate = jz_clk_static_get_rate,
+               .gate_bit = (uint32_t)-1,
+               .ops = &jz_clk_static_ops,
        },
 };
 
+static struct clk_ops jz_clk_pll_ops = {
+       .get_rate = jz_clk_static_get_rate,
+};
+
 static struct clk jz_clk_pll = {
        .name = "pll",
        .parent = &jz_clk_ext.clk,
-       .get_rate = jz_clk_pll_get_rate,
+       .ops = &jz_clk_pll_ops,
+};
+
+static struct clk_ops jz_clk_pll_half_ops = {
+       .get_rate = jz_clk_pll_half_get_rate,
 };
 
 static struct clk jz_clk_pll_half = {
        .name = "pll half",
        .parent = &jz_clk_pll,
-       .get_rate = jz_clk_pll_half_get_rate,
+       .ops = &jz_clk_pll_half_ops,
+};
+
+static const struct clk_ops jz_clk_main_ops = {
+       .get_rate = jz_clk_main_get_rate,
+       .set_rate = jz_clk_main_set_rate,
+       .round_rate = jz_clk_main_round_rate,
 };
 
 static struct main_clk jz_clk_cpu = {
        .clk = {
                .name = "cclk",
                .parent = &jz_clk_pll,
-               .get_rate = jz_clk_main_get_rate,
-               .set_rate = jz_clk_main_set_rate,
-               .round_rate = jz_clk_main_round_rate,
+               .ops = &jz_clk_main_ops,
        },
        .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
 };
@@ -311,9 +342,7 @@ static struct main_clk jz_clk_memory = {
        .clk = {
                .name = "mclk",
                .parent = &jz_clk_pll,
-               .get_rate = jz_clk_main_get_rate,
-               .set_rate = jz_clk_main_set_rate,
-               .round_rate = jz_clk_main_round_rate,
+               .ops = &jz_clk_main_ops,
        },
        .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
 };
@@ -322,9 +351,7 @@ static struct main_clk jz_clk_high_speed_peripheral = {
        .clk = {
                .name = "hclk",
                .parent = &jz_clk_pll,
-               .get_rate = jz_clk_main_get_rate,
-               .set_rate = jz_clk_main_set_rate,
-               .round_rate = jz_clk_main_round_rate,
+               .ops = &jz_clk_main_ops,
        },
        .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
 };
@@ -334,17 +361,20 @@ static struct main_clk jz_clk_low_speed_peripheral = {
        .clk = {
                .name = "pclk",
                .parent = &jz_clk_pll,
-               .get_rate = jz_clk_main_get_rate,
-               .set_rate = jz_clk_main_set_rate,
+               .ops = &jz_clk_main_ops,
        },
        .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
 };
 
+static const struct clk_ops jz_clk_ko_ops = {
+       .enable = jz_clk_ko_enable,
+       .disable = jz_clk_ko_disable,
+};
+
 static struct clk jz_clk_ko = {
        .name = "cko",
        .parent = &jz_clk_memory.clk,
-       .enable = jz_clk_ko_enable,
-       .disable = jz_clk_ko_disable,
+       .ops = &jz_clk_ko_ops,
 };
 
 static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
@@ -375,6 +405,22 @@ static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
        return 0;
 }
 
+static int jz_clk_udc_disable(struct clk *clk)
+{
+       jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
+                       JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
+
+       return 0;
+}
+
+static int jz_clk_udc_enable(struct clk *clk)
+{
+       jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
+                       JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
+
+       return 0;
+}
+
 static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
 {
        if (parent == &jz_clk_pll_half)
@@ -501,14 +547,18 @@ static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
        return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
 }
 
-static struct clk jz_clk_ld = {
-       .name = "lcd",
-       .parent = &jz_clk_pll_half,
+static const struct clk_ops jz_clk_ops_ld = {
        .set_rate = jz_clk_ldclk_set_rate,
        .get_rate = jz_clk_ldclk_get_rate,
        .round_rate = jz_clk_ldclk_round_rate,
 };
 
+static struct clk jz_clk_ld = {
+       .name = "lcd",
+       .parent = &jz_clk_pll_half,
+       .ops= &jz_clk_ops_ld,
+};
+
 static struct divided_clk jz_clk_lp = {
        .clk = {
                .name = "lcd_pclk",
@@ -527,156 +577,165 @@ static struct static_clk jz_clk_cim_pclk = {
        .clk = {
                .name = "cim_pclk",
                .gate_bit = JZ_CLOCK_GATE_CIM,
-               .get_rate = jz_clk_static_get_rate,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
-       },
-};
-
-static struct divided_clk jz_clk_i2s = {
-       .clk = {
-               .name = "i2s",
-               .parent = &jz_clk_ext.clk,
-               .gate_bit = JZ_CLOCK_GATE_AIC,
-               .set_rate = jz_clk_divided_set_rate,
-               .get_rate = jz_clk_divided_get_rate,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
-               .set_parent = jz_clk_i2s_set_parent,
-       },
-       .reg = JZ_REG_CLOCK_I2S,
-       .mask = JZ_CLOCK_I2S_DIV_MASK,
-};
-
-static struct  divided_clk jz_clk_mmc = {
-       .clk = {
-               .name = "mmc",
-               .parent = &jz_clk_pll_half,
-               .gate_bit = JZ_CLOCK_GATE_MMC,
-               .set_rate = jz_clk_divided_set_rate,
-               .get_rate = jz_clk_divided_get_rate,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
+               .ops = &jz_clk_static_ops,
        },
-       .reg = JZ_REG_CLOCK_MMC,
-       .mask = JZ_CLOCK_MMC_DIV_MASK,
 };
 
-static struct divided_clk jz_clk_uhc = {
-       .clk = {
-               .name = "uhc",
-               .parent = &jz_clk_pll_half,
-               .gate_bit = JZ_CLOCK_GATE_UHC,
-               .set_rate = jz_clk_divided_set_rate,
-               .get_rate = jz_clk_divided_get_rate,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
-       },
-       .reg = JZ_REG_CLOCK_UHC,
-       .mask = JZ_CLOCK_UHC_DIV_MASK,
-};
-
-static struct clk jz_clk_udc = {
-       .name = "udc",
-       .parent = &jz_clk_ext.clk,
-       .set_parent = jz_clk_udc_set_parent,
-       .set_rate = jz_clk_udc_set_rate,
-       .get_rate = jz_clk_udc_get_rate,
-};
-
-static struct divided_clk jz_clk_spi = {
-       .clk = {
-               .name = "spi",
-               .parent = &jz_clk_ext.clk,
-               .gate_bit = JZ_CLOCK_GATE_SPI,
-               .set_rate = jz_clk_divided_set_rate,
-               .get_rate = jz_clk_divided_get_rate,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
-               .set_parent = jz_clk_spi_set_parent,
-       },
-       .reg = JZ_REG_CLOCK_SPI,
-       .mask = JZ_CLOCK_SPI_DIV_MASK,
-};
-
-static struct clk jz_clk_uart0 = {
-       .name = "uart0",
-       .parent = &jz_clk_ext.clk,
-       .gate_bit = JZ_CLOCK_GATE_UART0,
+static const struct clk_ops jz_clk_i2s_ops = 
+{
+       .set_rate = jz_clk_divided_set_rate,
+       .get_rate = jz_clk_divided_get_rate,
        .enable = jz_clk_enable_gating,
        .disable = jz_clk_disable_gating,
+       .set_parent = jz_clk_i2s_set_parent,
 };
 
-static struct clk jz_clk_uart1 = {
-       .name = "uart1",
-       .parent = &jz_clk_ext.clk,
-       .gate_bit = JZ_CLOCK_GATE_UART1,
+static const struct clk_ops jz_clk_spi_ops = 
+{
+       .set_rate = jz_clk_divided_set_rate,
+       .get_rate = jz_clk_divided_get_rate,
        .enable = jz_clk_enable_gating,
        .disable = jz_clk_disable_gating,
+       .set_parent = jz_clk_spi_set_parent,
 };
 
-static struct clk jz_clk_dma = {
-       .name = "dma",
-       .parent = &jz_clk_high_speed_peripheral.clk,
-       .gate_bit = JZ_CLOCK_GATE_UART0,
+static const struct clk_ops jz_clk_divided_ops = 
+{
+       .set_rate = jz_clk_divided_set_rate,
+       .get_rate = jz_clk_divided_get_rate,
        .enable = jz_clk_enable_gating,
        .disable = jz_clk_disable_gating,
 };
 
-static struct clk jz_clk_ipu = {
-       .name = "ipu",
-       .parent = &jz_clk_high_speed_peripheral.clk,
-       .gate_bit = JZ_CLOCK_GATE_IPU,
-       .enable = jz_clk_enable_gating,
-       .disable = jz_clk_disable_gating,
+static struct divided_clk jz4740_clock_divided_clks[] = {
+       {
+               .clk = {
+                       .name = "i2s",
+                       .parent = &jz_clk_ext.clk,
+                       .gate_bit = JZ_CLOCK_GATE_AIC,
+                       .ops = &jz_clk_i2s_ops,
+               },
+               .reg = JZ_REG_CLOCK_I2S,
+               .mask = JZ_CLOCK_I2S_DIV_MASK,
+       },
+       {
+               .clk = {
+                       .name = "spi",
+                       .parent = &jz_clk_ext.clk,
+                       .gate_bit = JZ_CLOCK_GATE_SPI,
+                       .ops = &jz_clk_spi_ops,
+               },
+               .reg = JZ_REG_CLOCK_SPI,
+               .mask = JZ_CLOCK_SPI_DIV_MASK,
+       },
+       {
+               .clk = {
+                       .name = "mmc",
+                       .parent = &jz_clk_pll_half,
+                       .gate_bit = JZ_CLOCK_GATE_MMC,
+                       .ops = &jz_clk_divided_ops,
+               },
+               .reg = JZ_REG_CLOCK_MMC,
+               .mask = JZ_CLOCK_MMC_DIV_MASK,
+       },
+       {
+               .clk = {
+                       .name = "uhc",
+                       .parent = &jz_clk_pll_half,
+                       .gate_bit = JZ_CLOCK_GATE_UHC,
+                       .ops = &jz_clk_divided_ops,
+               },
+               .reg = JZ_REG_CLOCK_UHC,
+               .mask = JZ_CLOCK_UHC_DIV_MASK,
+       },
 };
 
-static struct clk jz_clk_adc = {
-       .name = "adc",
-       .parent = &jz_clk_ext.clk,
-       .gate_bit = JZ_CLOCK_GATE_ADC,
-       .enable = jz_clk_enable_gating,
-       .disable = jz_clk_disable_gating,
+static const struct clk_ops jz_clk_udc_ops = {
+       .set_parent = jz_clk_udc_set_parent,
+       .set_rate = jz_clk_udc_set_rate,
+       .get_rate = jz_clk_udc_get_rate,
+       .enable = jz_clk_udc_enable,
+       .disable = jz_clk_udc_disable,
 };
 
-static struct clk jz_clk_i2c = {
-       .name = "i2c",
-       .parent = &jz_clk_ext.clk,
-       .gate_bit = JZ_CLOCK_GATE_I2C,
+static const struct clk_ops jz_clk_simple_ops = {
        .enable = jz_clk_enable_gating,
        .disable = jz_clk_disable_gating,
 };
 
+static struct clk jz4740_clock_simple_clks[] = {
+       {
+               .name = "udc",
+               .parent = &jz_clk_ext.clk,
+               .ops = &jz_clk_udc_ops,
+       },
+       {
+               .name = "uart0",
+               .parent = &jz_clk_ext.clk,
+               .gate_bit = JZ_CLOCK_GATE_UART0,
+               .ops = &jz_clk_simple_ops,
+       },
+       {
+               .name = "uart1",
+               .parent = &jz_clk_ext.clk,
+               .gate_bit = JZ_CLOCK_GATE_UART1,
+               .ops = &jz_clk_simple_ops,
+       },
+       {
+               .name = "dma",
+               .parent = &jz_clk_high_speed_peripheral.clk,
+               .gate_bit = JZ_CLOCK_GATE_UART0,
+               .ops = &jz_clk_simple_ops,
+       },
+       {
+               .name = "ipu",
+               .parent = &jz_clk_high_speed_peripheral.clk,
+               .gate_bit = JZ_CLOCK_GATE_IPU,
+               .ops = &jz_clk_simple_ops,
+       },
+       {
+               .name = "adc",
+               .parent = &jz_clk_ext.clk,
+               .gate_bit = JZ_CLOCK_GATE_ADC,
+               .ops = &jz_clk_simple_ops,
+       },
+       {
+               .name = "i2c",
+               .parent = &jz_clk_ext.clk,
+               .gate_bit = JZ_CLOCK_GATE_I2C,
+               .ops = &jz_clk_simple_ops,
+       },
+};
+
 static struct static_clk jz_clk_rtc = {
        .clk = {
                .name = "rtc",
                .gate_bit = JZ_CLOCK_GATE_RTC,
-               .enable = jz_clk_enable_gating,
-               .disable = jz_clk_disable_gating,
+               .ops = &jz_clk_static_ops,
        },
        .rate = 32768,
 };
 
 int clk_enable(struct clk *clk)
 {
-       if (!clk->enable)
+       if (!clk->ops->enable)
                return -EINVAL;
 
-       return clk->enable(clk);
+       return clk->ops->enable(clk);
 }
 EXPORT_SYMBOL_GPL(clk_enable);
 
 void clk_disable(struct clk *clk)
 {
-       if (clk->disable)
-               clk->disable(clk);
+       if (clk->ops->disable)
+               clk->ops->disable(clk);
 }
 EXPORT_SYMBOL_GPL(clk_disable);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-       if (clk->get_rate)
-               return clk->get_rate(clk);
+       if (clk->ops->get_rate)
+               return clk->ops->get_rate(clk);
        if (clk->parent)
                return clk_get_rate(clk->parent);
 
@@ -686,16 +745,16 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-       if (!clk->set_rate)
+       if (!clk->ops->set_rate)
                return -EINVAL;
-       return clk->set_rate(clk, rate);
+       return clk->ops->set_rate(clk, rate);
 }
 EXPORT_SYMBOL_GPL(clk_set_rate);
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->round_rate)
-               return clk->round_rate(clk, rate);
+       if (clk->ops->round_rate)
+               return clk->ops->round_rate(clk, rate);
 
        return -EINVAL;
 }
@@ -705,18 +764,17 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 {
        int ret;
 
-       if (!clk->set_parent)
+       if (!clk->ops->set_parent)
                return -EINVAL;
 
-       clk->disable(clk);
-       ret = clk->set_parent(clk, parent);
-       clk->enable(clk);
+       clk_disable(clk);
+       ret = clk->ops->set_parent(clk, parent);
+       clk_enable(clk);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(clk_set_parent);
 
-
 struct clk *clk_get(struct device *dev, const char *name)
 {
        struct clk *clk;
@@ -741,6 +799,8 @@ inline static void clk_add(struct clk *clk)
 
 static void clk_register_clks(void)
 {
+       size_t i;
+
     clk_add(&jz_clk_ext.clk);
     clk_add(&jz_clk_pll);
     clk_add(&jz_clk_pll_half);
@@ -752,41 +812,63 @@ static void clk_register_clks(void)
     clk_add(&jz_clk_lp.clk);
     clk_add(&jz_clk_cim_mclk);
     clk_add(&jz_clk_cim_pclk.clk);
-    clk_add(&jz_clk_i2s.clk);
-    clk_add(&jz_clk_mmc.clk);
-    clk_add(&jz_clk_uhc.clk);
-    clk_add(&jz_clk_udc);
-    clk_add(&jz_clk_uart0);
-    clk_add(&jz_clk_uart1);
-    clk_add(&jz_clk_dma);
-    clk_add(&jz_clk_ipu);
-    clk_add(&jz_clk_adc);
-    clk_add(&jz_clk_i2c);
     clk_add(&jz_clk_rtc.clk);
+
+       for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
+               clk_add(&jz4740_clock_divided_clks[i].clk);
+
+       for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
+               clk_add(&jz4740_clock_simple_clks[i]);
+}
+
+void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
+{
+       switch (mode) {
+       case JZ4740_WAIT_MODE_IDLE:
+               jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
+               break;
+       case JZ4740_WAIT_MODE_SLEEP:
+               jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
+               break;
+       }
+}
+
+void jz4740_clock_udc_disable_auto_suspend(void)
+{
+       jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
 }
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
+
+void jz4740_clock_udc_enable_auto_suspend(void)
+{
+       jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
+}
+EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
 
 int jz_init_clocks(unsigned long ext_rate)
 {
        uint32_t val;
 
-       jz_clock_base = ioremap(0x10000000, 0x100);
+       jz_clock_base = ioremap(CPHYSADDR(CPM_BASE), 0x100);
        if (!jz_clock_base)
                return -EBUSY;
 
+       spin_lock_init(&jz_clock_lock);
+
        jz_clk_ext.rate = ext_rate;
 
        val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
 
        if (val & JZ_CLOCK_SPI_SRC_PLL)
-               jz_clk_spi.clk.parent = &jz_clk_pll_half;
+               jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
 
        val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
 
        if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
-               jz_clk_i2s.clk.parent = &jz_clk_pll_half;
+               jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
 
        if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
-               jz_clk_udc.parent = &jz_clk_pll_half;
+               jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
 
        clk_register_clks();