Commit 9b839ec0 authored by Amit Kucheria's avatar Amit Kucheria Committed by Sascha Hauer

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.htmlSigned-off-by: default avatarAmit Kucheria <amit.kucheria@canonical.com>
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
parent c45dd814
...@@ -52,13 +52,14 @@ static void __clk_disable(struct clk *clk) ...@@ -52,13 +52,14 @@ static void __clk_disable(struct clk *clk)
{ {
if (clk == NULL || IS_ERR(clk)) if (clk == NULL || IS_ERR(clk))
return; return;
WARN_ON(!clk->usecount);
if (!(--clk->usecount)) {
if (clk->disable)
clk->disable(clk);
__clk_disable(clk->parent); __clk_disable(clk->parent);
__clk_disable(clk->secondary); __clk_disable(clk->secondary);
}
WARN_ON(!clk->usecount);
if (!(--clk->usecount) && clk->disable)
clk->disable(clk);
} }
static int __clk_enable(struct clk *clk) static int __clk_enable(struct clk *clk)
...@@ -66,12 +67,13 @@ static int __clk_enable(struct clk *clk) ...@@ -66,12 +67,13 @@ static int __clk_enable(struct clk *clk)
if (clk == NULL || IS_ERR(clk)) if (clk == NULL || IS_ERR(clk))
return -EINVAL; return -EINVAL;
if (clk->usecount++ == 0) {
__clk_enable(clk->parent); __clk_enable(clk->parent);
__clk_enable(clk->secondary); __clk_enable(clk->secondary);
if (clk->usecount++ == 0 && clk->enable) if (clk->enable)
clk->enable(clk); clk->enable(clk);
}
return 0; return 0;
} }
...@@ -160,17 +162,28 @@ EXPORT_SYMBOL(clk_set_rate); ...@@ -160,17 +162,28 @@ EXPORT_SYMBOL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent) int clk_set_parent(struct clk *clk, struct clk *parent)
{ {
int ret = -EINVAL; int ret = -EINVAL;
struct clk *old;
if (clk == NULL || IS_ERR(clk) || parent == NULL || if (clk == NULL || IS_ERR(clk) || parent == NULL ||
IS_ERR(parent) || clk->set_parent == NULL) IS_ERR(parent) || clk->set_parent == NULL)
return ret; return ret;
if (clk->usecount)
clk_enable(parent);
mutex_lock(&clocks_mutex); mutex_lock(&clocks_mutex);
ret = clk->set_parent(clk, parent); ret = clk->set_parent(clk, parent);
if (ret == 0) if (ret == 0) {
old = clk->parent;
clk->parent = parent; clk->parent = parent;
} else {
old = parent;
}
mutex_unlock(&clocks_mutex); mutex_unlock(&clocks_mutex);
if (clk->usecount)
clk_disable(old);
return ret; return ret;
} }
EXPORT_SYMBOL(clk_set_parent); EXPORT_SYMBOL(clk_set_parent);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment