aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-10-20 22:19:58 -0400
committerColin Cross <ccross@android.com>2011-02-22 14:22:24 -0500
commit78f379b574dcbe656fa21ea72e95f8dff232e233 (patch)
treef76ccb9312f911d51c9c4d168f6ce706fd2df148 /arch
parent9c7dc562cd78784f54261b9bedb44e8b0056f729 (diff)
ARM: tegra: clock: Refcount periph clock enables
Some peripheral clocks share enable bits. Refcount the enables so that calling clk_disable on one clock will not turn off another clock. Signed-off-by: Colin Cross <ccross@android.com> Acked-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 59e77ba9580..2ca8b74ec07 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -159,6 +159,12 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
159 */ 159 */
160static DEFINE_SPINLOCK(clock_register_lock); 160static DEFINE_SPINLOCK(clock_register_lock);
161 161
162/*
163 * Some peripheral clocks share an enable bit, so refcount the enable bits
164 * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
165 */
166static int tegra_periph_clk_enable_refcount[3 * 32];
167
162#define clk_writel(value, reg) \ 168#define clk_writel(value, reg) \
163 __raw_writel(value, (u32)reg_clk_base + (reg)) 169 __raw_writel(value, (u32)reg_clk_base + (reg))
164#define clk_readl(reg) \ 170#define clk_readl(reg) \
@@ -952,8 +958,17 @@ static void tegra2_periph_clk_init(struct clk *c)
952static int tegra2_periph_clk_enable(struct clk *c) 958static int tegra2_periph_clk_enable(struct clk *c)
953{ 959{
954 u32 val; 960 u32 val;
961 unsigned long flags;
962 int refcount;
955 pr_debug("%s on clock %s\n", __func__, c->name); 963 pr_debug("%s on clock %s\n", __func__, c->name);
956 964
965 spin_lock_irqsave(&clock_register_lock, flags);
966
967 refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
968
969 if (refcount > 1)
970 goto out;
971
957 clk_writel(PERIPH_CLK_TO_ENB_BIT(c), 972 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
958 CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c)); 973 CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
959 if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET)) 974 if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
@@ -966,15 +981,29 @@ static int tegra2_periph_clk_enable(struct clk *c)
966 val |= 0x3 << 24; 981 val |= 0x3 << 24;
967 clk_writel(val, c->reg); 982 clk_writel(val, c->reg);
968 } 983 }
984
985out:
986 spin_unlock_irqrestore(&clock_register_lock, flags);
987
969 return 0; 988 return 0;
970} 989}
971 990
972static void tegra2_periph_clk_disable(struct clk *c) 991static void tegra2_periph_clk_disable(struct clk *c)
973{ 992{
993 unsigned long flags;
994
974 pr_debug("%s on clock %s\n", __func__, c->name); 995 pr_debug("%s on clock %s\n", __func__, c->name);
975 996
976 clk_writel(PERIPH_CLK_TO_ENB_BIT(c), 997 spin_lock_irqsave(&clock_register_lock, flags);
977 CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); 998
999 if (c->refcnt)
1000 tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
1001
1002 if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
1003 clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
1004 CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
1005
1006 spin_unlock_irqrestore(&clock_register_lock, flags);
978} 1007}
979 1008
980static void tegra2_periph_clk_reset(struct clk *c, bool assert) 1009static void tegra2_periph_clk_reset(struct clk *c, bool assert)
@@ -2076,7 +2105,6 @@ struct clk tegra_list_clks[] = {
2076 PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0), 2105 PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
2077 PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), 2106 PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
2078 PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), 2107 PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
2079 /* FIXME: spdif has 2 clocks but 1 enable */
2080 PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), 2108 PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
2081 PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71), 2109 PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
2082 PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71), 2110 PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
@@ -2089,7 +2117,6 @@ struct clk tegra_list_clks[] = {
2089 PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), 2117 PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
2090 PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */ 2118 PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
2091 PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ 2119 PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
2092 /* FIXME: vfir shares an enable with uartb */
2093 PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), 2120 PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
2094 PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ 2121 PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
2095 PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ 2122 PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
@@ -2120,13 +2147,11 @@ struct clk tegra_list_clks[] = {
2120 PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX), 2147 PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
2121 PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */ 2148 PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
2122 PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ 2149 PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
2123 /* FIXME: vi and vi_sensor share an enable */
2124 PERIPH_CLK("vi", "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ 2150 PERIPH_CLK("vi", "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
2125 PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */ 2151 PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
2126 PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ 2152 PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
2127 PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ 2153 PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
2128 PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ 2154 PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
2129 /* FIXME: cve and tvo share an enable */
2130 PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ 2155 PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
2131 PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ 2156 PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
2132 PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ 2157 PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */