From: Amit Kucheria Date: Fri, 28 May 2010 08:29:09 +0000 (+0300) Subject: arm: mxc: utilise usecount field in clock operations X-Git-Tag: v2.6.36-rc1~591^2^2~1^2~55 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=9b839ec0a880977d05ec4d25028ca4a0c3216c61;p=karo-tx-linux.git arm: mxc: utilise usecount field in clock operations This patch fixes the clock refcounting when reparenting is used. Boot-tested on imx51 babbage board. Sascha pointed out a good explanation of refcounting here: http://www.spinics.net/lists/arm-kernel/msg85879.html Signed-off-by: Amit Kucheria Signed-off-by: Sascha Hauer --- diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 323ff8ccc877..2ed3ab173add 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -52,13 +52,14 @@ static void __clk_disable(struct clk *clk) { if (clk == NULL || IS_ERR(clk)) return; - - __clk_disable(clk->parent); - __clk_disable(clk->secondary); - WARN_ON(!clk->usecount); - if (!(--clk->usecount) && clk->disable) - clk->disable(clk); + + if (!(--clk->usecount)) { + if (clk->disable) + clk->disable(clk); + __clk_disable(clk->parent); + __clk_disable(clk->secondary); + } } static int __clk_enable(struct clk *clk) @@ -66,12 +67,13 @@ static int __clk_enable(struct clk *clk) if (clk == NULL || IS_ERR(clk)) return -EINVAL; - __clk_enable(clk->parent); - __clk_enable(clk->secondary); - - if (clk->usecount++ == 0 && clk->enable) - clk->enable(clk); + if (clk->usecount++ == 0) { + __clk_enable(clk->parent); + __clk_enable(clk->secondary); + if (clk->enable) + clk->enable(clk); + } return 0; } @@ -160,17 +162,28 @@ EXPORT_SYMBOL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { int ret = -EINVAL; + struct clk *old; if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent) || clk->set_parent == NULL) return ret; + if (clk->usecount) + clk_enable(parent); + mutex_lock(&clocks_mutex); ret = clk->set_parent(clk, parent); - if (ret == 0) + if (ret == 0) { + old = clk->parent; clk->parent = parent; + } else { + old = parent; + } mutex_unlock(&clocks_mutex); + if (clk->usecount) + clk_disable(old); + return ret; } EXPORT_SYMBOL(clk_set_parent);