ARM: tegra: dvfs: Get rid of dvfs_lock and move init later

Get rid of dvfs_lock, replacing it with the cansleep flag on clocks.
Clocks with the cansleep flag set will lock a mutex before calling
into dvfs.

Also does the regulator api calls during late init, after the
regulators have been probed.

Signed-off-by: Colin Cross <ccross@android.com>
Change-Id: I5b8bd249bd4f3ae495f2076f1e6d2bfb38737f29
This commit is contained in:
Colin Cross
2010-11-01 17:27:29 -07:00
parent c95714d0ba
commit a1d72a522d
4 changed files with 49 additions and 43 deletions

View File

@@ -568,6 +568,7 @@ int __init tegra_disable_boot_clocks(void)
int __init tegra_late_init_clock(void)
{
tegra_dvfs_late_init();
tegra_disable_boot_clocks();
tegra_clk_set_dvfs_rates();
return 0;

View File

@@ -42,21 +42,11 @@ struct dvfs_reg {
int millivolts;
};
static LIST_HEAD(dvfs_list);
static LIST_HEAD(dvfs_debug_list);
static LIST_HEAD(dvfs_reg_list);
static DEFINE_MUTEX(dvfs_lock);
void lock_dvfs(void)
{
mutex_lock(&dvfs_lock);
}
void unlock_dvfs(void)
{
mutex_unlock(&dvfs_lock);
}
static DEFINE_MUTEX(dvfs_debug_list_lock);
static DEFINE_MUTEX(dvfs_reg_list_lock);
static int dvfs_reg_set_voltage(struct dvfs_reg *dvfs_reg)
{
@@ -71,46 +61,53 @@ static int dvfs_reg_set_voltage(struct dvfs_reg *dvfs_reg)
dvfs_reg->millivolts = millivolts;
if (!dvfs_reg->reg) {
pr_warn("dvfs set voltage on %s ignored\n", dvfs_reg->reg_id);
return 0;
}
return regulator_set_voltage(dvfs_reg->reg,
millivolts * 1000, dvfs_reg->max_millivolts * 1000);
}
static int dvfs_reg_get_voltage(struct dvfs_reg *dvfs_reg)
static int dvfs_reg_connect_to_regulator(struct dvfs_reg *dvfs_reg)
{
int ret = regulator_get_voltage(dvfs_reg->reg);
struct regulator *reg;
if (ret > 0)
return ret / 1000;
if (!dvfs_reg->reg) {
reg = regulator_get(NULL, dvfs_reg->reg_id);
if (IS_ERR(reg))
return -EINVAL;
}
return ret;
dvfs_reg->reg = reg;
return 0;
}
static struct dvfs_reg *get_dvfs_reg(struct dvfs *d)
{
struct dvfs_reg *dvfs_reg;
struct regulator *reg;
mutex_lock(&dvfs_reg_list_lock);
list_for_each_entry(dvfs_reg, &dvfs_reg_list, node)
if (!strcmp(d->reg_id, dvfs_reg->reg_id))
return dvfs_reg;
reg = regulator_get(NULL, d->reg_id);
if (IS_ERR(reg))
return NULL;
goto out;
dvfs_reg = kzalloc(sizeof(struct dvfs_reg), GFP_KERNEL);
if (!dvfs_reg) {
pr_err("%s: Failed to allocate dvfs_reg\n", __func__);
regulator_put(reg);
return NULL;
goto out;
}
INIT_LIST_HEAD(&dvfs_reg->dvfs);
dvfs_reg->reg = reg;
dvfs_reg->reg_id = kstrdup(d->reg_id, GFP_KERNEL);
list_add_tail(&dvfs_reg->node, &dvfs_reg_list);
out:
mutex_unlock(&dvfs_reg_list_lock);
return dvfs_reg;
}
@@ -127,7 +124,7 @@ static struct dvfs_reg *attach_dvfs_reg(struct dvfs *d)
if (d->max_millivolts > d->dvfs_reg->max_millivolts)
d->dvfs_reg->max_millivolts = d->max_millivolts;
d->cur_millivolts = dvfs_reg_get_voltage(d->dvfs_reg);
d->cur_millivolts = d->max_millivolts;
return dvfs_reg;
}
@@ -177,7 +174,7 @@ int tegra_dvfs_set_rate(struct clk *c, unsigned long rate)
c->dvfs_rate = rate;
freq_up = (c->refcnt == 0) || (rate > c->rate);
freq_up = (c->refcnt == 0) || (rate > clk_get_rate_locked(c));
list_for_each_entry(d, &c->dvfs, node) {
if (d->higher == freq_up)
@@ -197,7 +194,8 @@ int tegra_dvfs_set_rate(struct clk *c, unsigned long rate)
}
EXPORT_SYMBOL(tegra_dvfs_set_rate);
int tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
/* May only be called during clock init, does not take any locks on clock c. */
int __init tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
{
int i;
struct dvfs_reg *dvfs_reg;
@@ -221,30 +219,38 @@ int tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
}
d->num_freqs = i;
if (d->auto_dvfs)
if (d->auto_dvfs) {
c->auto_dvfs = true;
clk_set_cansleep(c);
}
c->is_dvfs = true;
smp_wmb();
list_add_tail(&d->node, &c->dvfs);
mutex_lock(&dvfs_debug_list_lock);
list_add_tail(&d->debug_node, &dvfs_debug_list);
mutex_unlock(&dvfs_debug_list_lock);
return 0;
}
int __init tegra_init_dvfs(void)
/*
* Iterate through all the dvfs regulators, finding the regulator exported
* by the regulator api for each one. Must be called in late init, after
* all the regulator api's regulators are initialized.
*/
int __init tegra_dvfs_late_init(void)
{
lock_dvfs();
tegra2_init_dvfs();
struct dvfs_reg *dvfs_reg;
tegra_clk_set_dvfs_rates();
unlock_dvfs();
mutex_lock(&dvfs_reg_list_lock);
list_for_each_entry(dvfs_reg, &dvfs_reg_list, node)
dvfs_reg_connect_to_regulator(dvfs_reg);
mutex_unlock(&dvfs_reg_list_lock);
return 0;
}
late_initcall(tegra_init_dvfs);
#ifdef CONFIG_DEBUG_FS
static int dvfs_tree_sort_cmp(void *p, struct list_head *a, struct list_head *b)
@@ -273,7 +279,7 @@ static int dvfs_tree_show(struct seq_file *s, void *data)
seq_printf(s, " clock rate mV\n");
seq_printf(s, "--------------------------------\n");
lock_dvfs();
mutex_lock(&dvfs_debug_list_lock);
list_sort(NULL, &dvfs_debug_list, dvfs_tree_sort_cmp);
@@ -288,7 +294,7 @@ static int dvfs_tree_show(struct seq_file *s, void *data)
d->cur_rate, d->cur_millivolts);
}
unlock_dvfs();
mutex_unlock(&dvfs_debug_list_lock);
return 0;
}

View File

@@ -49,11 +49,9 @@ struct dvfs {
struct list_head reg_node;
};
void lock_dvfs(void);
void unlock_dvfs(void);
void tegra2_init_dvfs(void);
int tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d);
int dvfs_debugfs_init(struct dentry *clk_debugfs_root);
int tegra_dvfs_late_init(void);
#endif

View File

@@ -18,6 +18,7 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include "clock.h"
@@ -132,7 +133,7 @@ static struct dvfs dvfs_init[] = {
CORE_DVFS("NVRM_DEVID_CLK_SRC", 1, MHZ, 480, 600, 800, 1067, 1067),
};
void tegra2_init_dvfs(void)
void __init tegra2_init_dvfs(void)
{
int i;
struct clk *c;