]> Pileus Git - ~andy/linux/blob - arch/arm/mach-omap2/vp.c
OMAP3+: VP: struct omap_vp_common: replace shift with __ffs(mask)
[~andy/linux] / arch / arm / mach-omap2 / vp.c
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3
4 #include <plat/common.h>
5
6 #include "voltage.h"
7 #include "vp.h"
8 #include "prm-regbits-34xx.h"
9 #include "prm-regbits-44xx.h"
10 #include "prm44xx.h"
11
12 static void vp_latch_vsel(struct voltagedomain *voltdm)
13 {
14         struct omap_vp_instance *vp = voltdm->vp;
15         u32 vpconfig;
16         unsigned long uvdc;
17         char vsel;
18
19         uvdc = omap_voltage_get_nom_volt(voltdm);
20         if (!uvdc) {
21                 pr_warning("%s: unable to find current voltage for vdd_%s\n",
22                         __func__, voltdm->name);
23                 return;
24         }
25
26         if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) {
27                 pr_warning("%s: PMIC function to convert voltage in uV to"
28                         " vsel not registered\n", __func__);
29                 return;
30         }
31
32         vsel = voltdm->pmic->uv_to_vsel(uvdc);
33
34         vpconfig = voltdm->read(vp->vpconfig);
35         vpconfig &= ~(vp->common->vpconfig_initvoltage_mask |
36                         vp->common->vpconfig_initvdd);
37         vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask);
38         voltdm->write(vpconfig, vp->vpconfig);
39
40         /* Trigger initVDD value copy to voltage processor */
41         voltdm->write((vpconfig | vp->common->vpconfig_initvdd),
42                        vp->vpconfig);
43
44         /* Clear initVDD copy trigger bit */
45         voltdm->write(vpconfig, vp->vpconfig);
46 }
47
48 /* Generic voltage init functions */
49 void __init omap_vp_init(struct voltagedomain *voltdm)
50 {
51         struct omap_vp_instance *vp = voltdm->vp;
52         struct omap_vdd_info *vdd = voltdm->vdd;
53         u32 vp_val;
54
55         if (!voltdm->read || !voltdm->write) {
56                 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
57                         __func__, voltdm->name);
58                 return;
59         }
60
61         vp_val = vdd->vp_rt_data.vpconfig_erroroffset |
62                 (vdd->vp_rt_data.vpconfig_errorgain <<
63                  __ffs(vp->common->vpconfig_errorgain_mask)) |
64                 vp->common->vpconfig_timeouten;
65         voltdm->write(vp_val, vp->vpconfig);
66
67         vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin <<
68                    vp->common->vstepmin_smpswaittimemin_shift) |
69                   (vdd->vp_rt_data.vstepmin_stepmin <<
70                    vp->common->vstepmin_stepmin_shift));
71         voltdm->write(vp_val, vp->vstepmin);
72
73         vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax <<
74                    vp->common->vstepmax_smpswaittimemax_shift) |
75                   (vdd->vp_rt_data.vstepmax_stepmax <<
76                    vp->common->vstepmax_stepmax_shift));
77         voltdm->write(vp_val, vp->vstepmax);
78
79         vp_val = ((vdd->vp_rt_data.vlimitto_vddmax <<
80                    vp->common->vlimitto_vddmax_shift) |
81                   (vdd->vp_rt_data.vlimitto_vddmin <<
82                    vp->common->vlimitto_vddmin_shift) |
83                   (vdd->vp_rt_data.vlimitto_timeout <<
84                    vp->common->vlimitto_timeout_shift));
85         voltdm->write(vp_val, vp->vlimitto);
86 }
87
88 /* VP force update method of voltage scaling */
89 int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
90                               unsigned long target_volt)
91 {
92         struct omap_vp_instance *vp = voltdm->vp;
93         u32 vpconfig;
94         u8 target_vsel, current_vsel;
95         int ret, timeout = 0;
96
97         ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, &current_vsel);
98         if (ret)
99                 return ret;
100
101         /*
102          * Clear all pending TransactionDone interrupt/status. Typical latency
103          * is <3us
104          */
105         while (timeout++ < VP_TRANXDONE_TIMEOUT) {
106                 vp->common->ops->clear_txdone(vp->id);
107                 if (!vp->common->ops->check_txdone(vp->id))
108                         break;
109                 udelay(1);
110         }
111         if (timeout >= VP_TRANXDONE_TIMEOUT) {
112                 pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
113                         "Voltage change aborted", __func__, voltdm->name);
114                 return -ETIMEDOUT;
115         }
116
117         /* Configure for VP-Force Update */
118         vpconfig = voltdm->read(vp->vpconfig);
119         vpconfig &= ~(vp->common->vpconfig_initvdd |
120                         vp->common->vpconfig_forceupdate |
121                         vp->common->vpconfig_initvoltage_mask);
122         vpconfig |= ((target_vsel <<
123                       __ffs(vp->common->vpconfig_initvoltage_mask)));
124         voltdm->write(vpconfig, vp->vpconfig);
125
126         /* Trigger initVDD value copy to voltage processor */
127         vpconfig |= vp->common->vpconfig_initvdd;
128         voltdm->write(vpconfig, vp->vpconfig);
129
130         /* Force update of voltage */
131         vpconfig |= vp->common->vpconfig_forceupdate;
132         voltdm->write(vpconfig, vp->vpconfig);
133
134         /*
135          * Wait for TransactionDone. Typical latency is <200us.
136          * Depends on SMPSWAITTIMEMIN/MAX and voltage change
137          */
138         timeout = 0;
139         omap_test_timeout(vp->common->ops->check_txdone(vp->id),
140                           VP_TRANXDONE_TIMEOUT, timeout);
141         if (timeout >= VP_TRANXDONE_TIMEOUT)
142                 pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
143                         "TRANXDONE never got set after the voltage update\n",
144                         __func__, voltdm->name);
145
146         omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);
147
148         /*
149          * Disable TransactionDone interrupt , clear all status, clear
150          * control registers
151          */
152         timeout = 0;
153         while (timeout++ < VP_TRANXDONE_TIMEOUT) {
154                 vp->common->ops->clear_txdone(vp->id);
155                 if (!vp->common->ops->check_txdone(vp->id))
156                         break;
157                 udelay(1);
158         }
159
160         if (timeout >= VP_TRANXDONE_TIMEOUT)
161                 pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
162                         "to clear the TRANXDONE status\n",
163                         __func__, voltdm->name);
164
165         vpconfig = voltdm->read(vp->vpconfig);
166         /* Clear initVDD copy trigger bit */
167         vpconfig &= ~vp->common->vpconfig_initvdd;
168         voltdm->write(vpconfig, vp->vpconfig);
169         /* Clear force bit */
170         vpconfig &= ~vp->common->vpconfig_forceupdate;
171         voltdm->write(vpconfig, vp->vpconfig);
172
173         return 0;
174 }
175
176 /**
177  * omap_vp_get_curr_volt() - API to get the current vp voltage.
178  * @voltdm:     pointer to the VDD.
179  *
180  * This API returns the current voltage for the specified voltage processor
181  */
182 unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
183 {
184         struct omap_vp_instance *vp = voltdm->vp;
185         u8 curr_vsel;
186
187         if (!voltdm || IS_ERR(voltdm)) {
188                 pr_warning("%s: VDD specified does not exist!\n", __func__);
189                 return 0;
190         }
191
192         if (!voltdm->read) {
193                 pr_err("%s: No read API for reading vdd_%s regs\n",
194                         __func__, voltdm->name);
195                 return 0;
196         }
197
198         curr_vsel = voltdm->read(vp->voltage);
199
200         if (!voltdm->pmic || !voltdm->pmic->vsel_to_uv) {
201                 pr_warning("%s: PMIC function to convert vsel to voltage"
202                         "in uV not registerd\n", __func__);
203                 return 0;
204         }
205
206         return voltdm->pmic->vsel_to_uv(curr_vsel);
207 }
208
209 /**
210  * omap_vp_enable() - API to enable a particular VP
211  * @voltdm:     pointer to the VDD whose VP is to be enabled.
212  *
213  * This API enables a particular voltage processor. Needed by the smartreflex
214  * class drivers.
215  */
216 void omap_vp_enable(struct voltagedomain *voltdm)
217 {
218         struct omap_vp_instance *vp;
219         u32 vpconfig;
220
221         if (!voltdm || IS_ERR(voltdm)) {
222                 pr_warning("%s: VDD specified does not exist!\n", __func__);
223                 return;
224         }
225
226         vp = voltdm->vp;
227         if (!voltdm->read || !voltdm->write) {
228                 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
229                         __func__, voltdm->name);
230                 return;
231         }
232
233         /* If VP is already enabled, do nothing. Return */
234         if (vp->enabled)
235                 return;
236
237         vp_latch_vsel(voltdm);
238
239         /* Enable VP */
240         vpconfig = voltdm->read(vp->vpconfig);
241         vpconfig |= vp->common->vpconfig_vpenable;
242         voltdm->write(vpconfig, vp->vpconfig);
243         vp->enabled = true;
244 }
245
246 /**
247  * omap_vp_disable() - API to disable a particular VP
248  * @voltdm:     pointer to the VDD whose VP is to be disabled.
249  *
250  * This API disables a particular voltage processor. Needed by the smartreflex
251  * class drivers.
252  */
253 void omap_vp_disable(struct voltagedomain *voltdm)
254 {
255         struct omap_vp_instance *vp;
256         u32 vpconfig;
257         int timeout;
258
259         if (!voltdm || IS_ERR(voltdm)) {
260                 pr_warning("%s: VDD specified does not exist!\n", __func__);
261                 return;
262         }
263
264         vp = voltdm->vp;
265         if (!voltdm->read || !voltdm->write) {
266                 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
267                         __func__, voltdm->name);
268                 return;
269         }
270
271         /* If VP is already disabled, do nothing. Return */
272         if (!vp->enabled) {
273                 pr_warning("%s: Trying to disable VP for vdd_%s when"
274                         "it is already disabled\n", __func__, voltdm->name);
275                 return;
276         }
277
278         /* Disable VP */
279         vpconfig = voltdm->read(vp->vpconfig);
280         vpconfig &= ~vp->common->vpconfig_vpenable;
281         voltdm->write(vpconfig, vp->vpconfig);
282
283         /*
284          * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
285          */
286         omap_test_timeout((voltdm->read(vp->vstatus)),
287                           VP_IDLE_TIMEOUT, timeout);
288
289         if (timeout >= VP_IDLE_TIMEOUT)
290                 pr_warning("%s: vdd_%s idle timedout\n",
291                         __func__, voltdm->name);
292
293         vp->enabled = false;
294
295         return;
296 }