OMAP3+: VP: move SoC-specific sys clock rate retreival late init
[pandora-kernel.git] / arch / arm / mach-omap2 / voltage.c
1 /*
2  * OMAP3/OMAP4 Voltage Management Routines
3  *
4  * Author: Thara Gopinath       <thara@ti.com>
5  *
6  * Copyright (C) 2007 Texas Instruments, Inc.
7  * Rajendra Nayak <rnayak@ti.com>
8  * Lesly A M <x0080970@ti.com>
9  *
10  * Copyright (C) 2008, 2011 Nokia Corporation
11  * Kalle Jokiniemi
12  * Paul Walmsley
13  *
14  * Copyright (C) 2010 Texas Instruments, Inc.
15  * Thara Gopinath <thara@ti.com>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License version 2 as
19  * published by the Free Software Foundation.
20  */
21
22 #include <linux/delay.h>
23 #include <linux/io.h>
24 #include <linux/err.h>
25 #include <linux/debugfs.h>
26 #include <linux/slab.h>
27 #include <linux/clk.h>
28
29 #include <plat/common.h>
30
31 #include "prm-regbits-34xx.h"
32 #include "prm-regbits-44xx.h"
33 #include "prm44xx.h"
34 #include "prcm44xx.h"
35 #include "prminst44xx.h"
36 #include "control.h"
37
38 #include "voltage.h"
39 #include "powerdomain.h"
40
41 #include "vc.h"
42 #include "vp.h"
43
44 static LIST_HEAD(voltdm_list);
45
46 static int __init _config_common_vdd_data(struct voltagedomain *voltdm)
47 {
48         struct omap_vdd_info *vdd = voltdm->vdd;
49         u32 sys_clk_rate, timeout_val, waittime;
50
51         /* Divide to avoid overflow */
52         sys_clk_rate = voltdm->sys_clk.rate / 1000;
53         WARN_ON(!sys_clk_rate);
54
55         /* Generic voltage parameters */
56         vdd->volt_scale = omap_vp_forceupdate_scale;
57         voltdm->vp->enabled = false;
58
59         vdd->vp_rt_data.vpconfig_erroroffset =
60                 (voltdm->pmic->vp_erroroffset <<
61                  __ffs(voltdm->vp->common->vpconfig_erroroffset_mask));
62
63         timeout_val = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000;
64         vdd->vp_rt_data.vlimitto_timeout = timeout_val;
65         vdd->vp_rt_data.vlimitto_vddmin = voltdm->pmic->vp_vddmin;
66         vdd->vp_rt_data.vlimitto_vddmax = voltdm->pmic->vp_vddmax;
67
68         waittime = ((voltdm->pmic->step_size / voltdm->pmic->slew_rate) *
69                     sys_clk_rate) / 1000;
70         vdd->vp_rt_data.vstepmin_smpswaittimemin = waittime;
71         vdd->vp_rt_data.vstepmax_smpswaittimemax = waittime;
72         vdd->vp_rt_data.vstepmin_stepmin = voltdm->pmic->vp_vstepmin;
73         vdd->vp_rt_data.vstepmax_stepmax = voltdm->pmic->vp_vstepmax;
74
75         return 0;
76 }
77
78 static int __init omap_vdd_data_configure(struct voltagedomain *voltdm)
79 {
80         int ret = -EINVAL;
81
82         if (!voltdm->pmic) {
83                 pr_err("%s: PMIC info requried to configure vdd_%s not"
84                         "populated.Hence cannot initialize vdd_%s\n",
85                         __func__, voltdm->name, voltdm->name);
86                 goto ovdc_out;
87         }
88
89         if (IS_ERR_VALUE(_config_common_vdd_data(voltdm)))
90                 goto ovdc_out;
91
92         ret = 0;
93
94 ovdc_out:
95         return ret;
96 }
97
98 /* Public functions */
99 /**
100  * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
101  * @voltdm:     pointer to the VDD for which current voltage info is needed
102  *
103  * API to get the current non-auto-compensated voltage for a VDD.
104  * Returns 0 in case of error else returns the current voltage for the VDD.
105  */
106 unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
107 {
108         struct omap_vdd_info *vdd;
109
110         if (!voltdm || IS_ERR(voltdm)) {
111                 pr_warning("%s: VDD specified does not exist!\n", __func__);
112                 return 0;
113         }
114
115         vdd = voltdm->vdd;
116
117         return vdd->curr_volt;
118 }
119
120 /**
121  * omap_voltage_scale_vdd() - API to scale voltage of a particular
122  *                              voltage domain.
123  * @voltdm:     pointer to the VDD which is to be scaled.
124  * @target_volt:        The target voltage of the voltage domain
125  *
126  * This API should be called by the kernel to do the voltage scaling
127  * for a particular voltage domain during dvfs or any other situation.
128  */
129 int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
130                 unsigned long target_volt)
131 {
132         struct omap_vdd_info *vdd;
133
134         if (!voltdm || IS_ERR(voltdm)) {
135                 pr_warning("%s: VDD specified does not exist!\n", __func__);
136                 return -EINVAL;
137         }
138
139         vdd = voltdm->vdd;
140
141         if (!vdd->volt_scale) {
142                 pr_err("%s: No voltage scale API registered for vdd_%s\n",
143                         __func__, voltdm->name);
144                 return -ENODATA;
145         }
146
147         return vdd->volt_scale(voltdm, target_volt);
148 }
149
150 /**
151  * omap_voltage_reset() - Resets the voltage of a particular voltage domain
152  *                      to that of the current OPP.
153  * @voltdm:     pointer to the VDD whose voltage is to be reset.
154  *
155  * This API finds out the correct voltage the voltage domain is supposed
156  * to be at and resets the voltage to that level. Should be used especially
157  * while disabling any voltage compensation modules.
158  */
159 void omap_voltage_reset(struct voltagedomain *voltdm)
160 {
161         unsigned long target_uvdc;
162
163         if (!voltdm || IS_ERR(voltdm)) {
164                 pr_warning("%s: VDD specified does not exist!\n", __func__);
165                 return;
166         }
167
168         target_uvdc = omap_voltage_get_nom_volt(voltdm);
169         if (!target_uvdc) {
170                 pr_err("%s: unable to find current voltage for vdd_%s\n",
171                         __func__, voltdm->name);
172                 return;
173         }
174
175         omap_voltage_scale_vdd(voltdm, target_uvdc);
176 }
177
178 /**
179  * omap_voltage_get_volttable() - API to get the voltage table associated with a
180  *                              particular voltage domain.
181  * @voltdm:     pointer to the VDD for which the voltage table is required
182  * @volt_data:  the voltage table for the particular vdd which is to be
183  *              populated by this API
184  *
185  * This API populates the voltage table associated with a VDD into the
186  * passed parameter pointer. Returns the count of distinct voltages
187  * supported by this vdd.
188  *
189  */
190 void omap_voltage_get_volttable(struct voltagedomain *voltdm,
191                 struct omap_volt_data **volt_data)
192 {
193         struct omap_vdd_info *vdd;
194
195         if (!voltdm || IS_ERR(voltdm)) {
196                 pr_warning("%s: VDD specified does not exist!\n", __func__);
197                 return;
198         }
199
200         vdd = voltdm->vdd;
201
202         *volt_data = vdd->volt_data;
203 }
204
205 /**
206  * omap_voltage_get_voltdata() - API to get the voltage table entry for a
207  *                              particular voltage
208  * @voltdm:     pointer to the VDD whose voltage table has to be searched
209  * @volt:       the voltage to be searched in the voltage table
210  *
211  * This API searches through the voltage table for the required voltage
212  * domain and tries to find a matching entry for the passed voltage volt.
213  * If a matching entry is found volt_data is populated with that entry.
214  * This API searches only through the non-compensated voltages int the
215  * voltage table.
216  * Returns pointer to the voltage table entry corresponding to volt on
217  * success. Returns -ENODATA if no voltage table exisits for the passed voltage
218  * domain or if there is no matching entry.
219  */
220 struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
221                 unsigned long volt)
222 {
223         struct omap_vdd_info *vdd;
224         int i;
225
226         if (!voltdm || IS_ERR(voltdm)) {
227                 pr_warning("%s: VDD specified does not exist!\n", __func__);
228                 return ERR_PTR(-EINVAL);
229         }
230
231         vdd = voltdm->vdd;
232
233         if (!vdd->volt_data) {
234                 pr_warning("%s: voltage table does not exist for vdd_%s\n",
235                         __func__, voltdm->name);
236                 return ERR_PTR(-ENODATA);
237         }
238
239         for (i = 0; vdd->volt_data[i].volt_nominal != 0; i++) {
240                 if (vdd->volt_data[i].volt_nominal == volt)
241                         return &vdd->volt_data[i];
242         }
243
244         pr_notice("%s: Unable to match the current voltage with the voltage"
245                 "table for vdd_%s\n", __func__, voltdm->name);
246
247         return ERR_PTR(-ENODATA);
248 }
249
250 /**
251  * omap_voltage_register_pmic() - API to register PMIC specific data
252  * @voltdm:     pointer to the VDD for which the PMIC specific data is
253  *              to be registered
254  * @pmic:       the structure containing pmic info
255  *
256  * This API is to be called by the SOC/PMIC file to specify the
257  * pmic specific info as present in omap_voltdm_pmic structure.
258  */
259 int omap_voltage_register_pmic(struct voltagedomain *voltdm,
260                                struct omap_voltdm_pmic *pmic)
261 {
262         if (!voltdm || IS_ERR(voltdm)) {
263                 pr_warning("%s: VDD specified does not exist!\n", __func__);
264                 return -EINVAL;
265         }
266
267         voltdm->pmic = pmic;
268
269         return 0;
270 }
271
272 /**
273  * omap_change_voltscale_method() - API to change the voltage scaling method.
274  * @voltdm:     pointer to the VDD whose voltage scaling method
275  *              has to be changed.
276  * @voltscale_method:   the method to be used for voltage scaling.
277  *
278  * This API can be used by the board files to change the method of voltage
279  * scaling between vpforceupdate and vcbypass. The parameter values are
280  * defined in voltage.h
281  */
282 void omap_change_voltscale_method(struct voltagedomain *voltdm,
283                 int voltscale_method)
284 {
285         struct omap_vdd_info *vdd;
286
287         if (!voltdm || IS_ERR(voltdm)) {
288                 pr_warning("%s: VDD specified does not exist!\n", __func__);
289                 return;
290         }
291
292         vdd = voltdm->vdd;
293
294         switch (voltscale_method) {
295         case VOLTSCALE_VPFORCEUPDATE:
296                 vdd->volt_scale = omap_vp_forceupdate_scale;
297                 return;
298         case VOLTSCALE_VCBYPASS:
299                 vdd->volt_scale = omap_vc_bypass_scale;
300                 return;
301         default:
302                 pr_warning("%s: Trying to change the method of voltage scaling"
303                         "to an unsupported one!\n", __func__);
304         }
305 }
306
307 /**
308  * omap_voltage_late_init() - Init the various voltage parameters
309  *
310  * This API is to be called in the later stages of the
311  * system boot to init the voltage controller and
312  * voltage processors.
313  */
314 int __init omap_voltage_late_init(void)
315 {
316         struct voltagedomain *voltdm;
317
318         if (list_empty(&voltdm_list)) {
319                 pr_err("%s: Voltage driver support not added\n",
320                         __func__);
321                 return -EINVAL;
322         }
323
324         list_for_each_entry(voltdm, &voltdm_list, node) {
325                 struct clk *sys_ck;
326
327                 if (!voltdm->scalable)
328                         continue;
329
330                 sys_ck = clk_get(NULL, voltdm->sys_clk.name);
331                 if (IS_ERR(sys_ck)) {
332                         pr_warning("%s: Could not get sys clk.\n", __func__);
333                         return -EINVAL;
334                 }
335                 voltdm->sys_clk.rate = clk_get_rate(sys_ck);
336                 WARN_ON(!voltdm->sys_clk.rate);
337                 clk_put(sys_ck);
338
339                 if (voltdm->vc) {
340                         voltdm->vdd->volt_scale = omap_vc_bypass_scale;
341                         omap_vc_init_channel(voltdm);
342                 }
343
344                 if (voltdm->vdd) {
345                         if (omap_vdd_data_configure(voltdm))
346                                 continue;
347                         omap_vp_init(voltdm);
348                 }
349         }
350
351         return 0;
352 }
353
354 static struct voltagedomain *_voltdm_lookup(const char *name)
355 {
356         struct voltagedomain *voltdm, *temp_voltdm;
357
358         voltdm = NULL;
359
360         list_for_each_entry(temp_voltdm, &voltdm_list, node) {
361                 if (!strcmp(name, temp_voltdm->name)) {
362                         voltdm = temp_voltdm;
363                         break;
364                 }
365         }
366
367         return voltdm;
368 }
369
370 /**
371  * voltdm_add_pwrdm - add a powerdomain to a voltagedomain
372  * @voltdm: struct voltagedomain * to add the powerdomain to
373  * @pwrdm: struct powerdomain * to associate with a voltagedomain
374  *
375  * Associate the powerdomain @pwrdm with a voltagedomain @voltdm.  This
376  * enables the use of voltdm_for_each_pwrdm().  Returns -EINVAL if
377  * presented with invalid pointers; -ENOMEM if memory could not be allocated;
378  * or 0 upon success.
379  */
380 int voltdm_add_pwrdm(struct voltagedomain *voltdm, struct powerdomain *pwrdm)
381 {
382         if (!voltdm || !pwrdm)
383                 return -EINVAL;
384
385         pr_debug("voltagedomain: associating powerdomain %s with voltagedomain "
386                  "%s\n", pwrdm->name, voltdm->name);
387
388         list_add(&pwrdm->voltdm_node, &voltdm->pwrdm_list);
389
390         return 0;
391 }
392
393 /**
394  * voltdm_for_each_pwrdm - call function for each pwrdm in a voltdm
395  * @voltdm: struct voltagedomain * to iterate over
396  * @fn: callback function *
397  *
398  * Call the supplied function @fn for each powerdomain in the
399  * voltagedomain @voltdm.  Returns -EINVAL if presented with invalid
400  * pointers; or passes along the last return value of the callback
401  * function, which should be 0 for success or anything else to
402  * indicate failure.
403  */
404 int voltdm_for_each_pwrdm(struct voltagedomain *voltdm,
405                           int (*fn)(struct voltagedomain *voltdm,
406                                     struct powerdomain *pwrdm))
407 {
408         struct powerdomain *pwrdm;
409         int ret = 0;
410
411         if (!fn)
412                 return -EINVAL;
413
414         list_for_each_entry(pwrdm, &voltdm->pwrdm_list, voltdm_node)
415                 ret = (*fn)(voltdm, pwrdm);
416
417         return ret;
418 }
419
420 /**
421  * voltdm_for_each - call function on each registered voltagedomain
422  * @fn: callback function *
423  *
424  * Call the supplied function @fn for each registered voltagedomain.
425  * The callback function @fn can return anything but 0 to bail out
426  * early from the iterator.  Returns the last return value of the
427  * callback function, which should be 0 for success or anything else
428  * to indicate failure; or -EINVAL if the function pointer is null.
429  */
430 int voltdm_for_each(int (*fn)(struct voltagedomain *voltdm, void *user),
431                     void *user)
432 {
433         struct voltagedomain *temp_voltdm;
434         int ret = 0;
435
436         if (!fn)
437                 return -EINVAL;
438
439         list_for_each_entry(temp_voltdm, &voltdm_list, node) {
440                 ret = (*fn)(temp_voltdm, user);
441                 if (ret)
442                         break;
443         }
444
445         return ret;
446 }
447
448 static int _voltdm_register(struct voltagedomain *voltdm)
449 {
450         if (!voltdm || !voltdm->name)
451                 return -EINVAL;
452
453         INIT_LIST_HEAD(&voltdm->pwrdm_list);
454         list_add(&voltdm->node, &voltdm_list);
455
456         pr_debug("voltagedomain: registered %s\n", voltdm->name);
457
458         return 0;
459 }
460
461 /**
462  * voltdm_lookup - look up a voltagedomain by name, return a pointer
463  * @name: name of voltagedomain
464  *
465  * Find a registered voltagedomain by its name @name.  Returns a pointer
466  * to the struct voltagedomain if found, or NULL otherwise.
467  */
468 struct voltagedomain *voltdm_lookup(const char *name)
469 {
470         struct voltagedomain *voltdm ;
471
472         if (!name)
473                 return NULL;
474
475         voltdm = _voltdm_lookup(name);
476
477         return voltdm;
478 }
479
480 /**
481  * voltdm_init - set up the voltagedomain layer
482  * @voltdm_list: array of struct voltagedomain pointers to register
483  *
484  * Loop through the array of voltagedomains @voltdm_list, registering all
485  * that are available on the current CPU. If voltdm_list is supplied
486  * and not null, all of the referenced voltagedomains will be
487  * registered.  No return value.
488  */
489 void voltdm_init(struct voltagedomain **voltdms)
490 {
491         struct voltagedomain **v;
492
493         if (voltdms) {
494                 for (v = voltdms; *v; v++)
495                         _voltdm_register(*v);
496         }
497 }