OMAP2+: voltage: move VC into struct voltagedomain, misc. renames
[linux-block.git] / arch / arm / mach-omap2 / vc.c
1 /*
2  * OMAP Voltage Controller (VC) interface
3  *
4  * Copyright (C) 2011 Texas Instruments, Inc.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2. This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10 #include <linux/kernel.h>
11 #include <linux/delay.h>
12 #include <linux/init.h>
13
14 #include <plat/cpu.h>
15
16 #include "voltage.h"
17 #include "vc.h"
18 #include "prm-regbits-34xx.h"
19 #include "prm-regbits-44xx.h"
20 #include "prm44xx.h"
21
22 /* Voltage scale and accessory APIs */
23 int omap_vc_pre_scale(struct voltagedomain *voltdm,
24                       unsigned long target_volt,
25                       u8 *target_vsel, u8 *current_vsel)
26 {
27         struct omap_vc_channel *vc = voltdm->vc;
28         struct omap_vdd_info *vdd = voltdm->vdd;
29         struct omap_volt_data *volt_data;
30         const struct omap_vp_common_data *vp_common;
31         u32 vc_cmdval, vp_errgain_val;
32
33         vp_common = vdd->vp_data->vp_common;
34
35         /* Check if sufficient pmic info is available for this vdd */
36         if (!vdd->pmic_info) {
37                 pr_err("%s: Insufficient pmic info to scale the vdd_%s\n",
38                         __func__, voltdm->name);
39                 return -EINVAL;
40         }
41
42         if (!vdd->pmic_info->uv_to_vsel) {
43                 pr_err("%s: PMIC function to convert voltage in uV to"
44                         "vsel not registered. Hence unable to scale voltage"
45                         "for vdd_%s\n", __func__, voltdm->name);
46                 return -ENODATA;
47         }
48
49         if (!vdd->read_reg || !vdd->write_reg) {
50                 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
51                         __func__, voltdm->name);
52                 return -EINVAL;
53         }
54
55         /* Get volt_data corresponding to target_volt */
56         volt_data = omap_voltage_get_voltdata(voltdm, target_volt);
57         if (IS_ERR(volt_data))
58                 volt_data = NULL;
59
60         *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
61         *current_vsel = vdd->read_reg(vdd->vp_data->vp_common->prm_mod, vdd->vp_data->voltage);
62
63         /* Setting the ON voltage to the new target voltage */
64         vc_cmdval = vdd->read_reg(vc->common->prm_mod, vc->cmdval_reg);
65         vc_cmdval &= ~vc->common->cmd_on_mask;
66         vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift);
67         vdd->write_reg(vc_cmdval, vc->common->prm_mod, vc->cmdval_reg);
68
69         /* Setting vp errorgain based on the voltage */
70         if (volt_data) {
71                 vp_errgain_val = vdd->read_reg(vdd->vp_data->vp_common->prm_mod,
72                                                vdd->vp_data->vpconfig);
73                 vdd->vp_rt_data.vpconfig_errorgain = volt_data->vp_errgain;
74                 vp_errgain_val &= ~vp_common->vpconfig_errorgain_mask;
75                 vp_errgain_val |= vdd->vp_rt_data.vpconfig_errorgain <<
76                         vp_common->vpconfig_errorgain_shift;
77                 vdd->write_reg(vp_errgain_val, vdd->vp_data->vp_common->prm_mod,
78                                vdd->vp_data->vpconfig);
79         }
80
81         return 0;
82 }
83
84 void omap_vc_post_scale(struct voltagedomain *voltdm,
85                         unsigned long target_volt,
86                         u8 target_vsel, u8 current_vsel)
87 {
88         struct omap_vdd_info *vdd = voltdm->vdd;
89         u32 smps_steps = 0, smps_delay = 0;
90
91         smps_steps = abs(target_vsel - current_vsel);
92         /* SMPS slew rate / step size. 2us added as buffer. */
93         smps_delay = ((smps_steps * vdd->pmic_info->step_size) /
94                         vdd->pmic_info->slew_rate) + 2;
95         udelay(smps_delay);
96
97         vdd->curr_volt = target_volt;
98 }
99
100 /* vc_bypass_scale - VC bypass method of voltage scaling */
101 int omap_vc_bypass_scale(struct voltagedomain *voltdm,
102                          unsigned long target_volt)
103 {
104         struct omap_vc_channel *vc = voltdm->vc;
105         struct omap_vdd_info *vdd = voltdm->vdd;
106         u32 loop_cnt = 0, retries_cnt = 0;
107         u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
108         u8 target_vsel, current_vsel;
109         int ret;
110
111         ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, &current_vsel);
112         if (ret)
113                 return ret;
114
115         vc_valid = vc->common->valid;
116         vc_bypass_val_reg = vc->common->bypass_val_reg;
117         vc_bypass_value = (target_vsel << vc->common->data_shift) |
118                         (vdd->pmic_info->pmic_reg <<
119                         vc->common->regaddr_shift) |
120                         (vdd->pmic_info->i2c_slave_addr <<
121                         vc->common->slaveaddr_shift);
122
123         vdd->write_reg(vc_bypass_value, vc->common->prm_mod, vc_bypass_val_reg);
124         vdd->write_reg(vc_bypass_value | vc_valid, vc->common->prm_mod,
125                        vc_bypass_val_reg);
126
127         vc_bypass_value = vdd->read_reg(vc->common->prm_mod, vc_bypass_val_reg);
128         /*
129          * Loop till the bypass command is acknowledged from the SMPS.
130          * NOTE: This is legacy code. The loop count and retry count needs
131          * to be revisited.
132          */
133         while (!(vc_bypass_value & vc_valid)) {
134                 loop_cnt++;
135
136                 if (retries_cnt > 10) {
137                         pr_warning("%s: Retry count exceeded\n", __func__);
138                         return -ETIMEDOUT;
139                 }
140
141                 if (loop_cnt > 50) {
142                         retries_cnt++;
143                         loop_cnt = 0;
144                         udelay(10);
145                 }
146                 vc_bypass_value = vdd->read_reg(vc->common->prm_mod,
147                                                 vc_bypass_val_reg);
148         }
149
150         omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);
151         return 0;
152 }
153
154 static void __init omap3_vfsm_init(struct voltagedomain *voltdm)
155 {
156         struct omap_vc_channel *vc = voltdm->vc;
157         struct omap_vdd_info *vdd = voltdm->vdd;
158
159         /*
160          * Voltage Manager FSM parameters init
161          * XXX This data should be passed in from the board file
162          */
163         vdd->write_reg(OMAP3_CLKSETUP, vc->common->prm_mod, OMAP3_PRM_CLKSETUP_OFFSET);
164         vdd->write_reg(OMAP3_VOLTOFFSET, vc->common->prm_mod,
165                        OMAP3_PRM_VOLTOFFSET_OFFSET);
166         vdd->write_reg(OMAP3_VOLTSETUP2, vc->common->prm_mod,
167                        OMAP3_PRM_VOLTSETUP2_OFFSET);
168 }
169
170 static void __init omap3_vc_init_channel(struct voltagedomain *voltdm)
171 {
172         struct omap_vc_channel *vc = voltdm->vc;
173         struct omap_vdd_info *vdd = voltdm->vdd;
174         static bool is_initialized;
175         u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
176         u32 vc_val;
177
178         if (is_initialized)
179                 return;
180
181         /* Set up the on, inactive, retention and off voltage */
182         on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt);
183         onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt);
184         ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt);
185         off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt);
186         vc_val  = ((on_vsel << vc->common->cmd_on_shift) |
187                 (onlp_vsel << vc->common->cmd_onlp_shift) |
188                 (ret_vsel << vc->common->cmd_ret_shift) |
189                 (off_vsel << vc->common->cmd_off_shift));
190         vdd->write_reg(vc_val, vc->common->prm_mod, vc->cmdval_reg);
191
192         /*
193          * Generic VC parameters init
194          * XXX This data should be abstracted out
195          */
196         vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, vc->common->prm_mod,
197                         OMAP3_PRM_VC_CH_CONF_OFFSET);
198         vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, vc->common->prm_mod,
199                         OMAP3_PRM_VC_I2C_CFG_OFFSET);
200
201         omap3_vfsm_init(voltdm);
202
203         is_initialized = true;
204 }
205
206
207 /* OMAP4 specific voltage init functions */
208 static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
209 {
210         struct omap_vc_channel *vc = voltdm->vc;
211         struct omap_vdd_info *vdd = voltdm->vdd;
212         static bool is_initialized;
213         u32 vc_val;
214
215         if (is_initialized)
216                 return;
217
218         /* TODO: Configure setup times and CMD_VAL values*/
219
220         /*
221          * Generic VC parameters init
222          * XXX This data should be abstracted out
223          */
224         vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK |
225                   OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK |
226                   OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK);
227         vdd->write_reg(vc_val, vc->common->prm_mod, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET);
228
229         /* XXX These are magic numbers and do not belong! */
230         vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT);
231         vdd->write_reg(vc_val, vc->common->prm_mod, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
232
233         is_initialized = true;
234 }
235
236 void __init omap_vc_init_channel(struct voltagedomain *voltdm)
237 {
238         struct omap_vc_channel *vc = voltdm->vc;
239         struct omap_vdd_info *vdd = voltdm->vdd;
240         u32 vc_val;
241
242         if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
243                 pr_err("%s: PMIC info requried to configure vc for"
244                         "vdd_%s not populated.Hence cannot initialize vc\n",
245                         __func__, voltdm->name);
246                 return;
247         }
248
249         if (!vdd->read_reg || !vdd->write_reg) {
250                 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
251                         __func__, voltdm->name);
252                 return;
253         }
254
255         /* Set up the SMPS_SA(i2c slave address in VC */
256         vc_val = vdd->read_reg(vc->common->prm_mod,
257                                vc->common->smps_sa_reg);
258         vc_val &= ~vc->smps_sa_mask;
259         vc_val |= vdd->pmic_info->i2c_slave_addr << vc->smps_sa_shift;
260         vdd->write_reg(vc_val, vc->common->prm_mod,
261                        vc->common->smps_sa_reg);
262
263         /* Setup the VOLRA(pmic reg addr) in VC */
264         vc_val = vdd->read_reg(vc->common->prm_mod,
265                                vc->common->smps_volra_reg);
266         vc_val &= ~vc->smps_volra_mask;
267         vc_val |= vdd->pmic_info->pmic_reg << vc->smps_volra_shift;
268         vdd->write_reg(vc_val, vc->common->prm_mod,
269                        vc->common->smps_volra_reg);
270
271         /* Configure the setup times */
272         vc_val = vdd->read_reg(vc->common->prm_mod, vdd->vfsm->voltsetup_reg);
273         vc_val &= ~vdd->vfsm->voltsetup_mask;
274         vc_val |= vdd->pmic_info->volt_setup_time <<
275                         vdd->vfsm->voltsetup_shift;
276         vdd->write_reg(vc_val, vc->common->prm_mod, vdd->vfsm->voltsetup_reg);
277
278         if (cpu_is_omap34xx())
279                 omap3_vc_init_channel(voltdm);
280         else if (cpu_is_omap44xx())
281                 omap4_vc_init_channel(voltdm);
282 }
283