3 * Copyright (C) 2010 Google, Inc.
6 * Colin Cross <ccross@google.com>
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
19 #include <linux/kernel.h>
20 #include <linux/clk.h>
21 #include <linux/list.h>
22 #include <linux/init.h>
23 #include <linux/list_sort.h>
24 #include <linux/module.h>
25 #include <linux/debugfs.h>
26 #include <linux/slab.h>
27 #include <linux/seq_file.h>
28 #include <linux/regulator/consumer.h>
29 #include <asm/clkdev.h>
37 struct list_head node; /* node in dvfs_reg_list */
38 struct list_head dvfs; /* list head of attached dvfs clocks */
40 struct regulator *reg;
46 static LIST_HEAD(dvfs_debug_list);
47 static LIST_HEAD(dvfs_reg_list);
49 static DEFINE_MUTEX(dvfs_debug_list_lock);
50 static DEFINE_MUTEX(dvfs_reg_list_lock);
52 static int dvfs_reg_set_voltage(struct dvfs_reg *dvfs_reg)
58 mutex_lock(&dvfs_reg->lock);
60 list_for_each_entry(d, &dvfs_reg->dvfs, reg_node)
61 millivolts = max(d->cur_millivolts, millivolts);
63 if (millivolts == dvfs_reg->millivolts)
66 dvfs_reg->millivolts = millivolts;
69 pr_warn("dvfs set voltage on %s ignored\n", dvfs_reg->reg_id);
73 ret = regulator_set_voltage(dvfs_reg->reg,
74 millivolts * 1000, dvfs_reg->max_millivolts * 1000);
77 mutex_unlock(&dvfs_reg->lock);
81 static int dvfs_reg_connect_to_regulator(struct dvfs_reg *dvfs_reg)
83 struct regulator *reg;
86 reg = regulator_get(NULL, dvfs_reg->reg_id);
96 static struct dvfs_reg *get_dvfs_reg(struct dvfs *d)
98 struct dvfs_reg *dvfs_reg;
100 mutex_lock(&dvfs_reg_list_lock);
102 list_for_each_entry(dvfs_reg, &dvfs_reg_list, node)
103 if (!strcmp(d->reg_id, dvfs_reg->reg_id))
106 dvfs_reg = kzalloc(sizeof(struct dvfs_reg), GFP_KERNEL);
108 pr_err("%s: Failed to allocate dvfs_reg\n", __func__);
112 mutex_init(&dvfs_reg->lock);
113 INIT_LIST_HEAD(&dvfs_reg->dvfs);
114 dvfs_reg->reg_id = kstrdup(d->reg_id, GFP_KERNEL);
116 list_add_tail(&dvfs_reg->node, &dvfs_reg_list);
119 mutex_unlock(&dvfs_reg_list_lock);
123 static struct dvfs_reg *attach_dvfs_reg(struct dvfs *d)
125 struct dvfs_reg *dvfs_reg;
127 dvfs_reg = get_dvfs_reg(d);
131 mutex_lock(&dvfs_reg->lock);
132 list_add_tail(&d->reg_node, &dvfs_reg->dvfs);
134 d->dvfs_reg = dvfs_reg;
135 if (d->max_millivolts > d->dvfs_reg->max_millivolts)
136 d->dvfs_reg->max_millivolts = d->max_millivolts;
138 d->cur_millivolts = d->max_millivolts;
139 mutex_unlock(&dvfs_reg->lock);
145 __tegra_dvfs_set_rate(struct clk *c, struct dvfs *d, unsigned long rate)
150 if (d->freqs == NULL || d->millivolts == NULL)
153 if (rate > d->freqs[d->num_freqs - 1]) {
154 pr_warn("tegra_dvfs: rate %lu too high for dvfs on %s\n", rate,
160 d->cur_millivolts = 0;
162 while (i < d->num_freqs && rate > d->freqs[i])
165 d->cur_millivolts = d->millivolts[i];
173 ret = dvfs_reg_set_voltage(d->dvfs_reg);
175 pr_err("Failed to set regulator %s for clock %s to %d mV\n",
176 d->dvfs_reg->reg_id, c->name, d->cur_millivolts);
181 int tegra_dvfs_set_rate_locked(struct clk *c, unsigned long rate)
189 freq_up = (c->refcnt == 0) || (rate > clk_get_rate_locked(c));
191 list_for_each_entry(d, &c->dvfs, node) {
192 if (d->higher == freq_up)
193 ret = __tegra_dvfs_set_rate(c, d, rate);
198 list_for_each_entry(d, &c->dvfs, node) {
199 if (d->higher != freq_up)
200 ret = __tegra_dvfs_set_rate(c, d, rate);
208 /* May only be called during clock init, does not take any locks on clock c. */
209 int __init tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d)
212 struct dvfs_reg *dvfs_reg;
214 dvfs_reg = attach_dvfs_reg(d);
216 pr_err("Failed to get regulator %s for clock %s\n",
221 for (i = 0; i < MAX_DVFS_FREQS; i++) {
222 if (d->millivolts[i] == 0)
225 d->freqs[i] *= d->freqs_mult;
227 /* If final frequencies are 0, pad with previous frequency */
228 if (d->freqs[i] == 0 && i > 1)
229 d->freqs[i] = d->freqs[i - 1];
240 list_add_tail(&d->node, &c->dvfs);
242 mutex_lock(&dvfs_debug_list_lock);
243 list_add_tail(&d->debug_node, &dvfs_debug_list);
244 mutex_unlock(&dvfs_debug_list_lock);
250 * Iterate through all the dvfs regulators, finding the regulator exported
251 * by the regulator api for each one. Must be called in late init, after
252 * all the regulator api's regulators are initialized.
254 int __init tegra_dvfs_late_init(void)
256 struct dvfs_reg *dvfs_reg;
258 mutex_lock(&dvfs_reg_list_lock);
259 list_for_each_entry(dvfs_reg, &dvfs_reg_list, node)
260 dvfs_reg_connect_to_regulator(dvfs_reg);
261 mutex_unlock(&dvfs_reg_list_lock);
266 #ifdef CONFIG_DEBUG_FS
267 static int dvfs_tree_sort_cmp(void *p, struct list_head *a, struct list_head *b)
269 struct dvfs *da = list_entry(a, struct dvfs, debug_node);
270 struct dvfs *db = list_entry(b, struct dvfs, debug_node);
273 ret = strcmp(da->reg_id, db->reg_id);
277 if (da->cur_millivolts < db->cur_millivolts)
279 if (da->cur_millivolts > db->cur_millivolts)
282 return strcmp(da->clk_name, db->clk_name);
285 static int dvfs_tree_show(struct seq_file *s, void *data)
288 const char *last_reg = "";
290 seq_printf(s, " clock rate mV\n");
291 seq_printf(s, "--------------------------------\n");
293 mutex_lock(&dvfs_debug_list_lock);
295 list_sort(NULL, &dvfs_debug_list, dvfs_tree_sort_cmp);
297 list_for_each_entry(d, &dvfs_debug_list, debug_node) {
298 if (strcmp(last_reg, d->dvfs_reg->reg_id) != 0) {
299 last_reg = d->dvfs_reg->reg_id;
300 seq_printf(s, "%s %d mV:\n", d->dvfs_reg->reg_id,
301 d->dvfs_reg->millivolts);
304 seq_printf(s, " %-10s %-10lu %-4d mV\n", d->clk_name,
305 d->cur_rate, d->cur_millivolts);
308 mutex_unlock(&dvfs_debug_list_lock);
313 static int dvfs_tree_open(struct inode *inode, struct file *file)
315 return single_open(file, dvfs_tree_show, inode->i_private);
318 static const struct file_operations dvfs_tree_fops = {
319 .open = dvfs_tree_open,
322 .release = single_release,
325 int __init dvfs_debugfs_init(struct dentry *clk_debugfs_root)
329 d = debugfs_create_file("dvfs", S_IRUGO, clk_debugfs_root, NULL,