diff options
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 83358f920e4c..d849e0071b94 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | ||
16 | 17 | ||
17 | #include <plat/omap-pm.h> | 18 | #include <plat/omap-pm.h> |
18 | #include <plat/omap_device.h> | 19 | #include <plat/omap_device.h> |
@@ -156,6 +157,76 @@ err: | |||
156 | return ret; | 157 | return ret; |
157 | } | 158 | } |
158 | 159 | ||
160 | /* | ||
161 | * This API is to be called during init to put the various voltage | ||
162 | * domains to the voltage as per the opp table. Typically we boot up | ||
163 | * at the nominal voltage. So this function finds out the rate of | ||
164 | * the clock associated with the voltage domain, finds out the correct | ||
165 | * opp entry and puts the voltage domain to the voltage specifies | ||
166 | * in the opp entry | ||
167 | */ | ||
168 | static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | ||
169 | struct device *dev) | ||
170 | { | ||
171 | struct voltagedomain *voltdm; | ||
172 | struct clk *clk; | ||
173 | struct opp *opp; | ||
174 | unsigned long freq, bootup_volt; | ||
175 | |||
176 | if (!vdd_name || !clk_name || !dev) { | ||
177 | printk(KERN_ERR "%s: Invalid parameters!\n", __func__); | ||
178 | goto exit; | ||
179 | } | ||
180 | |||
181 | voltdm = omap_voltage_domain_lookup(vdd_name); | ||
182 | if (IS_ERR(voltdm)) { | ||
183 | printk(KERN_ERR "%s: Unable to get vdd pointer for vdd_%s\n", | ||
184 | __func__, vdd_name); | ||
185 | goto exit; | ||
186 | } | ||
187 | |||
188 | clk = clk_get(NULL, clk_name); | ||
189 | if (IS_ERR(clk)) { | ||
190 | printk(KERN_ERR "%s: unable to get clk %s\n", | ||
191 | __func__, clk_name); | ||
192 | goto exit; | ||
193 | } | ||
194 | |||
195 | freq = clk->rate; | ||
196 | clk_put(clk); | ||
197 | |||
198 | opp = opp_find_freq_ceil(dev, &freq); | ||
199 | if (IS_ERR(opp)) { | ||
200 | printk(KERN_ERR "%s: unable to find boot up OPP for vdd_%s\n", | ||
201 | __func__, vdd_name); | ||
202 | goto exit; | ||
203 | } | ||
204 | |||
205 | bootup_volt = opp_get_voltage(opp); | ||
206 | if (!bootup_volt) { | ||
207 | printk(KERN_ERR "%s: unable to find voltage corresponding" | ||
208 | "to the bootup OPP for vdd_%s\n", __func__, vdd_name); | ||
209 | goto exit; | ||
210 | } | ||
211 | |||
212 | omap_voltage_scale_vdd(voltdm, bootup_volt); | ||
213 | return 0; | ||
214 | |||
215 | exit: | ||
216 | printk(KERN_ERR "%s: Unable to put vdd_%s to its init voltage\n\n", | ||
217 | __func__, vdd_name); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | static void __init omap3_init_voltages(void) | ||
222 | { | ||
223 | if (!cpu_is_omap34xx()) | ||
224 | return; | ||
225 | |||
226 | omap2_set_init_voltage("mpu", "dpll1_ck", mpu_dev); | ||
227 | omap2_set_init_voltage("core", "l3_ick", l3_dev); | ||
228 | } | ||
229 | |||
159 | static int __init omap2_common_pm_init(void) | 230 | static int __init omap2_common_pm_init(void) |
160 | { | 231 | { |
161 | omap2_init_processor_devices(); | 232 | omap2_init_processor_devices(); |
@@ -169,8 +240,13 @@ static int __init omap2_common_pm_late_init(void) | |||
169 | { | 240 | { |
170 | /* Init the OMAP TWL parameters */ | 241 | /* Init the OMAP TWL parameters */ |
171 | omap3_twl_init(); | 242 | omap3_twl_init(); |
243 | |||
172 | /* Init the voltage layer */ | 244 | /* Init the voltage layer */ |
173 | omap_voltage_late_init(); | 245 | omap_voltage_late_init(); |
246 | |||
247 | /* Initialize the voltages */ | ||
248 | omap3_init_voltages(); | ||
249 | |||
174 | /* Smartreflex device init */ | 250 | /* Smartreflex device init */ |
175 | omap_devinit_smartreflex(); | 251 | omap_devinit_smartreflex(); |
176 | 252 | ||