diff options
| author | Colin Cross <ccross@android.com> | 2010-10-20 19:19:58 -0700 | 
|---|---|---|
| committer | Colin Cross <ccross@android.com> | 2011-02-22 11:22:24 -0800 | 
| commit | 78f379b574dcbe656fa21ea72e95f8dff232e233 (patch) | |
| tree | f76ccb9312f911d51c9c4d168f6ce706fd2df148 | |
| parent | 9c7dc562cd78784f54261b9bedb44e8b0056f729 (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>
| -rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 37 | 
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 59e77ba95802..2ca8b74ec07e 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);   */  static DEFINE_SPINLOCK(clock_register_lock); +/* + * Some peripheral clocks share an enable bit, so refcount the enable bits + * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U + */ +static int tegra_periph_clk_enable_refcount[3 * 32]; +  #define clk_writel(value, reg) \  	__raw_writel(value, (u32)reg_clk_base + (reg))  #define clk_readl(reg) \ @@ -952,8 +958,17 @@ static void tegra2_periph_clk_init(struct clk *c)  static int tegra2_periph_clk_enable(struct clk *c)  {  	u32 val; +	unsigned long flags; +	int refcount;  	pr_debug("%s on clock %s\n", __func__, c->name); +	spin_lock_irqsave(&clock_register_lock, flags); + +	refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++; + +	if (refcount > 1) +		goto out; +  	clk_writel(PERIPH_CLK_TO_ENB_BIT(c),  		CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));  	if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET)) @@ -966,15 +981,29 @@ static int tegra2_periph_clk_enable(struct clk *c)  		val |= 0x3 << 24;  		clk_writel(val, c->reg);  	} + +out: +	spin_unlock_irqrestore(&clock_register_lock, flags); +  	return 0;  }  static void tegra2_periph_clk_disable(struct clk *c)  { +	unsigned long flags; +  	pr_debug("%s on clock %s\n", __func__, c->name); -	clk_writel(PERIPH_CLK_TO_ENB_BIT(c), -		CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); +	spin_lock_irqsave(&clock_register_lock, flags); + +	if (c->refcnt) +		tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--; + +	if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) +		clk_writel(PERIPH_CLK_TO_ENB_BIT(c), +			CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c)); + +	spin_unlock_irqrestore(&clock_register_lock, flags);  }  static void tegra2_periph_clk_reset(struct clk *c, bool assert) @@ -2076,7 +2105,6 @@ struct clk tegra_list_clks[] = {  	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),  	PERIPH_CLK("i2s1",	"i2s.0",		NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),  	PERIPH_CLK("i2s2",	"i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71), -	/* FIXME: spdif has 2 clocks but 1 enable */  	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),  	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),  	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[] = {  	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),  	PERIPH_CLK("ide",	"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */  	PERIPH_CLK("ndflash",	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */ -	/* FIXME: vfir shares an enable with uartb */  	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),  	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */  	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[] = {  	PERIPH_CLK("uarte",	"uart.4",		NULL,	66,	0x1c4,	600000000, mux_pllp_pllc_pllm_clkm,	MUX),  	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 */  	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */ -	/* FIXME: vi and vi_sensor share an enable */  	PERIPH_CLK("vi",	"tegra_camera",		"vi",	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */  	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 */  	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */  	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */  	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */ -	/* FIXME: cve and tvo share an enable	*/  	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */  	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */  	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	600000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */ | 
