diff options
author | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-01-22 18:13:02 +0000 |
---|---|---|
committer | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-01-22 18:13:02 +0000 |
commit | 15b54dd2c0764032b4a1ac4ad3964bbd2b159fc8 (patch) | |
tree | 81451fdfa8fd3505f92633bd3393b944425ee15f /target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c | |
parent | 08ecc47d814795b113c96127d7be0cb6ed18b303 (diff) |
[xburst] Cleanup clock module a bit and replace last users of __cpm_*
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@19281 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c')
-rw-r--r-- | target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c | 394 |
1 files changed, 238 insertions, 156 deletions
diff --git a/target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c b/target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c index 853c6d867..49ea7171a 100644 --- a/target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c +++ b/target/linux/xburst/files-2.6.32/arch/mips/jz4740/clock.c @@ -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 @@ -22,7 +22,11 @@ #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 @@ -84,16 +88,17 @@ #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(); |