blob: c708df502c776923690aa48a3bf776db1726cc29 [file] [log] [blame]
David Collins6f032ba2011-08-31 14:08:15 -07001/*
David Collins5779cea2012-01-05 15:09:21 -08002 * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
David Collins6f032ba2011-08-31 14:08:15 -070014#define pr_fmt(fmt) "%s: " fmt, __func__
15
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070016#include <linux/module.h>
17#include <linux/err.h>
18#include <linux/kernel.h>
19#include <linux/init.h>
David Collins6f032ba2011-08-31 14:08:15 -070020#include <linux/slab.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <linux/spinlock.h>
22#include <linux/platform_device.h>
23#include <linux/regulator/driver.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include <mach/rpm.h>
25#include <mach/rpm-regulator.h>
David Collins6f032ba2011-08-31 14:08:15 -070026#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
28#include "rpm_resources.h"
David Collins6f032ba2011-08-31 14:08:15 -070029#include "rpm-regulator-private.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030
31/* Debug Definitions */
32
33enum {
34 MSM_RPM_VREG_DEBUG_REQUEST = BIT(0),
35 MSM_RPM_VREG_DEBUG_VOTE = BIT(1),
36 MSM_RPM_VREG_DEBUG_DUPLICATE = BIT(2),
David Collins6f032ba2011-08-31 14:08:15 -070037 MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG = BIT(3),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038};
39
40static int msm_rpm_vreg_debug_mask;
41module_param_named(
42 debug_mask, msm_rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
43);
44
David Collins6f032ba2011-08-31 14:08:15 -070045struct vreg_config *(*get_config[])(void) = {
46 [RPM_VREG_VERSION_8660] = get_config_8660,
47 [RPM_VREG_VERSION_8960] = get_config_8960,
David Collins6ef12bf2011-08-31 14:08:15 -070048 [RPM_VREG_VERSION_9615] = get_config_9615,
David Collins5779cea2012-01-05 15:09:21 -080049 [RPM_VREG_VERSION_8930] = get_config_8930,
David Collins6f032ba2011-08-31 14:08:15 -070050};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051
David Collins6f032ba2011-08-31 14:08:15 -070052#define SET_PART(_vreg, _part, _val) \
53 _vreg->req[_vreg->part->_part.word].value \
54 = (_vreg->req[_vreg->part->_part.word].value \
David Collinsd8525e82011-11-21 14:54:25 -080055 & ~_vreg->part->_part.mask) \
56 | (((_val) << _vreg->part->_part.shift) \
57 & _vreg->part->_part.mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058
David Collins6f032ba2011-08-31 14:08:15 -070059#define GET_PART(_vreg, _part) \
David Collinsd8525e82011-11-21 14:54:25 -080060 ((_vreg->req[_vreg->part->_part.word].value & _vreg->part->_part.mask) \
61 >> _vreg->part->_part.shift)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062
David Collinsd8525e82011-11-21 14:54:25 -080063#define USES_PART(_vreg, _part) (_vreg->part->_part.mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
David Collins6f032ba2011-08-31 14:08:15 -070065#define vreg_err(vreg, fmt, ...) \
66 pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067
David Collins6f032ba2011-08-31 14:08:15 -070068#define RPM_VREG_PIN_CTRL_EN0 0x01
69#define RPM_VREG_PIN_CTRL_EN1 0x02
70#define RPM_VREG_PIN_CTRL_EN2 0x04
71#define RPM_VREG_PIN_CTRL_EN3 0x08
72#define RPM_VREG_PIN_CTRL_ALL 0x0F
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
David Collins6f032ba2011-08-31 14:08:15 -070074static const char *label_freq[] = {
75 [RPM_VREG_FREQ_NONE] = " N/A",
76 [RPM_VREG_FREQ_19p20] = "19.2",
77 [RPM_VREG_FREQ_9p60] = "9.60",
78 [RPM_VREG_FREQ_6p40] = "6.40",
79 [RPM_VREG_FREQ_4p80] = "4.80",
80 [RPM_VREG_FREQ_3p84] = "3.84",
81 [RPM_VREG_FREQ_3p20] = "3.20",
82 [RPM_VREG_FREQ_2p74] = "2.74",
83 [RPM_VREG_FREQ_2p40] = "2.40",
84 [RPM_VREG_FREQ_2p13] = "2.13",
85 [RPM_VREG_FREQ_1p92] = "1.92",
86 [RPM_VREG_FREQ_1p75] = "1.75",
87 [RPM_VREG_FREQ_1p60] = "1.60",
88 [RPM_VREG_FREQ_1p48] = "1.48",
89 [RPM_VREG_FREQ_1p37] = "1.37",
90 [RPM_VREG_FREQ_1p28] = "1.28",
91 [RPM_VREG_FREQ_1p20] = "1.20",
92};
David Collins0ac31fe2012-02-08 13:53:34 -080093
94static const char *label_corner[] = {
95 [RPM_VREG_CORNER_NONE] = "NONE",
96 [RPM_VREG_CORNER_LOW] = "LOW",
97 [RPM_VREG_CORNER_NOMINAL] = "NOM",
98 [RPM_VREG_CORNER_HIGH] = "HIGH",
99};
100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101/*
102 * This is used when voting for LPM or HPM by subtracting or adding to the
103 * hpm_min_load of a regulator. It has units of uA.
104 */
David Collins6f032ba2011-08-31 14:08:15 -0700105#define LOAD_THRESHOLD_STEP 1000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106
David Collins6f032ba2011-08-31 14:08:15 -0700107/* rpm_version keeps track of the version for the currently running driver. */
108enum rpm_vreg_version rpm_version = -1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109
David Collins6f032ba2011-08-31 14:08:15 -0700110/* config holds all configuration data of the currently running driver. */
111static struct vreg_config *config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
David Collins6f032ba2011-08-31 14:08:15 -0700113/* These regulator ID values are specified in the board file. */
114static int vreg_id_vdd_mem, vreg_id_vdd_dig;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115
David Collins6f032ba2011-08-31 14:08:15 -0700116static inline int vreg_id_is_vdd_mem_or_dig(int id)
117{
118 return id == vreg_id_vdd_mem || id == vreg_id_vdd_dig;
119}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120
David Collins6f032ba2011-08-31 14:08:15 -0700121#define DEBUG_PRINT_BUFFER_SIZE 512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122
David Collins6f032ba2011-08-31 14:08:15 -0700123static void rpm_regulator_req(struct vreg *vreg, int set)
124{
125 int uV, mV, fm, pm, pc, pf, pd, freq, state, i;
126 const char *pf_label = "", *fm_label = "", *pc_total = "";
127 const char *pc_en[4] = {"", "", "", ""};
David Collins0ac31fe2012-02-08 13:53:34 -0800128 const char *pm_label = "", *freq_label = "", *corner_label = "";
David Collins6f032ba2011-08-31 14:08:15 -0700129 char buf[DEBUG_PRINT_BUFFER_SIZE];
130 size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
131 int pos = 0;
132
133 /* Suppress VDD_MEM and VDD_DIG printing. */
134 if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
135 && vreg_id_is_vdd_mem_or_dig(vreg->id))
136 return;
137
138 uV = GET_PART(vreg, uV);
139 mV = GET_PART(vreg, mV);
140 if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
141 uV = -uV;
142 mV = -mV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 }
144
David Collins6f032ba2011-08-31 14:08:15 -0700145 fm = GET_PART(vreg, fm);
146 pm = GET_PART(vreg, pm);
147 pc = GET_PART(vreg, pc);
148 pf = GET_PART(vreg, pf);
149 pd = GET_PART(vreg, pd);
150 freq = GET_PART(vreg, freq);
151 state = GET_PART(vreg, enable_state);
152
153 if (pf >= 0 && pf < config->label_pin_func_len)
154 pf_label = config->label_pin_func[pf];
155
156 if (fm >= 0 && fm < config->label_force_mode_len)
157 fm_label = config->label_force_mode[fm];
158
159 if (pm >= 0 && pm < config->label_power_mode_len)
160 pm_label = config->label_power_mode[pm];
161
162 if (freq >= 0 && freq < ARRAY_SIZE(label_freq))
163 freq_label = label_freq[freq];
164
165 for (i = 0; i < config->label_pin_ctrl_len; i++)
166 if (pc & (1 << i))
167 pc_en[i] = config->label_pin_ctrl[i];
168
169 if (pc == RPM_VREG_PIN_CTRL_NONE)
170 pc_total = " none";
171
172 pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
173 KERN_INFO, __func__);
174
175 pos += scnprintf(buf + pos, buflen - pos, "%s %-9s: s=%c",
176 (set == MSM_RPM_CTX_SET_0 ? "sending " : "buffered"),
177 vreg->rdesc.name,
178 (set == MSM_RPM_CTX_SET_0 ? 'A' : 'S'));
179
David Collins0ac31fe2012-02-08 13:53:34 -0800180 if (USES_PART(vreg, uV) && vreg->type != RPM_REGULATOR_TYPE_CORNER)
David Collins6f032ba2011-08-31 14:08:15 -0700181 pos += scnprintf(buf + pos, buflen - pos, ", v=%7d uV", uV);
182 if (USES_PART(vreg, mV))
183 pos += scnprintf(buf + pos, buflen - pos, ", v=%4d mV", mV);
184 if (USES_PART(vreg, enable_state))
185 pos += scnprintf(buf + pos, buflen - pos, ", state=%s (%d)",
186 (state == 1 ? "on" : "off"), state);
187 if (USES_PART(vreg, ip))
188 pos += scnprintf(buf + pos, buflen - pos,
189 ", ip=%4d mA", GET_PART(vreg, ip));
190 if (USES_PART(vreg, fm))
191 pos += scnprintf(buf + pos, buflen - pos,
192 ", fm=%s (%d)", fm_label, fm);
193 if (USES_PART(vreg, pc))
194 pos += scnprintf(buf + pos, buflen - pos,
195 ", pc=%s%s%s%s%s (%X)", pc_en[0], pc_en[1],
196 pc_en[2], pc_en[3], pc_total, pc);
197 if (USES_PART(vreg, pf))
198 pos += scnprintf(buf + pos, buflen - pos,
199 ", pf=%s (%d)", pf_label, pf);
200 if (USES_PART(vreg, pd))
201 pos += scnprintf(buf + pos, buflen - pos,
202 ", pd=%s (%d)", (pd == 1 ? "Y" : "N"), pd);
203 if (USES_PART(vreg, ia))
204 pos += scnprintf(buf + pos, buflen - pos,
205 ", ia=%4d mA", GET_PART(vreg, ia));
206 if (USES_PART(vreg, freq)) {
207 if (vreg->type == RPM_REGULATOR_TYPE_NCP)
208 pos += scnprintf(buf + pos, buflen - pos,
209 ", freq=%2d", freq);
210 else
211 pos += scnprintf(buf + pos, buflen - pos,
212 ", freq=%s MHz (%2d)", freq_label, freq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 }
David Collins6f032ba2011-08-31 14:08:15 -0700214 if (USES_PART(vreg, pm))
215 pos += scnprintf(buf + pos, buflen - pos,
216 ", pm=%s (%d)", pm_label, pm);
217 if (USES_PART(vreg, freq_clk_src))
218 pos += scnprintf(buf + pos, buflen - pos,
219 ", clk_src=%d", GET_PART(vreg, freq_clk_src));
220 if (USES_PART(vreg, comp_mode))
221 pos += scnprintf(buf + pos, buflen - pos,
222 ", comp=%d", GET_PART(vreg, comp_mode));
223 if (USES_PART(vreg, hpm))
224 pos += scnprintf(buf + pos, buflen - pos,
225 ", hpm=%d", GET_PART(vreg, hpm));
David Collins0ac31fe2012-02-08 13:53:34 -0800226 if (USES_PART(vreg, uV) && vreg->type == RPM_REGULATOR_TYPE_CORNER) {
227 if (uV >= 0 && uV < (ARRAY_SIZE(label_corner) - 1))
228 corner_label = label_corner[uV+1];
229 pos += scnprintf(buf + pos, buflen - pos, ", corner=%s (%d)",
230 corner_label, uV);
231 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232
David Collins6f032ba2011-08-31 14:08:15 -0700233 pos += scnprintf(buf + pos, buflen - pos, "; req[0]={%d, 0x%08X}",
234 vreg->req[0].id, vreg->req[0].value);
235 if (vreg->part->request_len > 1)
236 pos += scnprintf(buf + pos, buflen - pos,
237 ", req[1]={%d, 0x%08X}", vreg->req[1].id,
238 vreg->req[1].value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239
David Collins6f032ba2011-08-31 14:08:15 -0700240 pos += scnprintf(buf + pos, buflen - pos, "\n");
241 printk(buf);
242}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243
David Collins6f032ba2011-08-31 14:08:15 -0700244static void rpm_regulator_vote(struct vreg *vreg, enum rpm_vreg_voter voter,
245 int set, int voter_uV, int aggregate_uV)
246{
247 /* Suppress VDD_MEM and VDD_DIG printing. */
248 if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
249 && vreg_id_is_vdd_mem_or_dig(vreg->id))
250 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251
David Collins6f032ba2011-08-31 14:08:15 -0700252 pr_info("vote received %-9s: voter=%d, set=%c, v_voter=%7d uV, "
253 "v_aggregate=%7d uV\n", vreg->rdesc.name, voter,
254 (set == 0 ? 'A' : 'S'), voter_uV, aggregate_uV);
255}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256
David Collins6f032ba2011-08-31 14:08:15 -0700257static void rpm_regulator_duplicate(struct vreg *vreg, int set, int cnt)
258{
259 /* Suppress VDD_MEM and VDD_DIG printing. */
260 if ((msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_IGNORE_VDD_MEM_DIG)
261 && vreg_id_is_vdd_mem_or_dig(vreg->id))
262 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263
David Collins6f032ba2011-08-31 14:08:15 -0700264 if (cnt == 2)
265 pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}, "
266 "req[1]={%d, 0x%08X}\n", vreg->rdesc.name,
267 (set == 0 ? 'A' : 'S'),
268 vreg->req[0].id, vreg->req[0].value,
269 vreg->req[1].id, vreg->req[1].value);
270 else if (cnt == 1)
271 pr_info("ignored request %-9s: set=%c; req[0]={%d, 0x%08X}\n",
272 vreg->rdesc.name, (set == 0 ? 'A' : 'S'),
273 vreg->req[0].id, vreg->req[0].value);
274}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
276/* Spin lock needed for sleep-selectable regulators. */
David Collins6f032ba2011-08-31 14:08:15 -0700277static DEFINE_SPINLOCK(rpm_noirq_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278
279static int voltage_from_req(struct vreg *vreg)
280{
David Collins6f032ba2011-08-31 14:08:15 -0700281 int uV = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282
David Collins6f032ba2011-08-31 14:08:15 -0700283 if (vreg->part->uV.mask)
284 uV = GET_PART(vreg, uV);
David Collins13397f22012-02-06 13:53:29 -0800285 else if (vreg->part->mV.mask)
David Collins6f032ba2011-08-31 14:08:15 -0700286 uV = MILLI_TO_MICRO(GET_PART(vreg, mV));
David Collins13397f22012-02-06 13:53:29 -0800287 else if (vreg->part->enable_state.mask)
288 uV = GET_PART(vreg, enable_state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289
David Collins6f032ba2011-08-31 14:08:15 -0700290 return uV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291}
292
David Collins6f032ba2011-08-31 14:08:15 -0700293static void voltage_to_req(int uV, struct vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294{
David Collins6f032ba2011-08-31 14:08:15 -0700295 if (vreg->part->uV.mask)
296 SET_PART(vreg, uV, uV);
David Collins13397f22012-02-06 13:53:29 -0800297 else if (vreg->part->mV.mask)
David Collins6f032ba2011-08-31 14:08:15 -0700298 SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
David Collins13397f22012-02-06 13:53:29 -0800299 else if (vreg->part->enable_state.mask)
300 SET_PART(vreg, enable_state, uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700301}
302
303static int vreg_send_request(struct vreg *vreg, enum rpm_vreg_voter voter,
304 int set, unsigned mask0, unsigned val0,
305 unsigned mask1, unsigned val1, unsigned cnt,
306 int update_voltage)
307{
308 struct msm_rpm_iv_pair *prev_req;
David Collins6f032ba2011-08-31 14:08:15 -0700309 int rc = 0, max_uV_vote = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310 unsigned prev0, prev1;
David Collins6f032ba2011-08-31 14:08:15 -0700311 int *min_uV_vote;
312 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313
314 if (set == MSM_RPM_CTX_SET_0) {
David Collins6f032ba2011-08-31 14:08:15 -0700315 min_uV_vote = vreg->active_min_uV_vote;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 prev_req = vreg->prev_active_req;
317 } else {
David Collins6f032ba2011-08-31 14:08:15 -0700318 min_uV_vote = vreg->sleep_min_uV_vote;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 prev_req = vreg->prev_sleep_req;
320 }
321
322 prev0 = vreg->req[0].value;
323 vreg->req[0].value &= ~mask0;
324 vreg->req[0].value |= val0 & mask0;
325
326 prev1 = vreg->req[1].value;
327 vreg->req[1].value &= ~mask1;
328 vreg->req[1].value |= val1 & mask1;
329
David Collinsd1b7aea2012-03-19 10:27:55 -0700330 /* Set the force mode field based on which set is being requested. */
331 if (set == MSM_RPM_CTX_SET_0)
332 SET_PART(vreg, fm, vreg->pdata.force_mode);
333 else
334 SET_PART(vreg, fm, vreg->pdata.sleep_set_force_mode);
335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336 if (update_voltage)
David Collins6f032ba2011-08-31 14:08:15 -0700337 min_uV_vote[voter] = voltage_from_req(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700338
339 /* Find the highest voltage voted for and use it. */
340 for (i = 0; i < RPM_VREG_VOTER_COUNT; i++)
David Collins6f032ba2011-08-31 14:08:15 -0700341 max_uV_vote = max(max_uV_vote, min_uV_vote[i]);
342 voltage_to_req(max_uV_vote, vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343
344 if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_VOTE)
David Collins6f032ba2011-08-31 14:08:15 -0700345 rpm_regulator_vote(vreg, voter, set, min_uV_vote[voter],
346 max_uV_vote);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347
348 /* Ignore duplicate requests */
349 if (vreg->req[0].value != prev_req[0].value ||
350 vreg->req[1].value != prev_req[1].value) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 rc = msm_rpmrs_set_noirq(set, vreg->req, cnt);
352 if (rc) {
353 vreg->req[0].value = prev0;
354 vreg->req[1].value = prev1;
355
David Collins6f032ba2011-08-31 14:08:15 -0700356 vreg_err(vreg, "msm_rpmrs_set_noirq failed - "
357 "set=%s, id=%d, rc=%d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 (set == MSM_RPM_CTX_SET_0 ? "active" : "sleep"),
359 vreg->req[0].id, rc);
360 } else {
361 /* Only save if nonzero and active set. */
David Collins6f032ba2011-08-31 14:08:15 -0700362 if (max_uV_vote && (set == MSM_RPM_CTX_SET_0))
363 vreg->save_uV = max_uV_vote;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 if (msm_rpm_vreg_debug_mask
365 & MSM_RPM_VREG_DEBUG_REQUEST)
David Collins6f032ba2011-08-31 14:08:15 -0700366 rpm_regulator_req(vreg, set);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 prev_req[0].value = vreg->req[0].value;
368 prev_req[1].value = vreg->req[1].value;
369 }
370 } else if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE) {
David Collins6f032ba2011-08-31 14:08:15 -0700371 rpm_regulator_duplicate(vreg, set, cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372 }
373
374 return rc;
375}
376
377static int vreg_set_noirq(struct vreg *vreg, enum rpm_vreg_voter voter,
378 int sleep, unsigned mask0, unsigned val0,
379 unsigned mask1, unsigned val1, unsigned cnt,
380 int update_voltage)
381{
David Collins6f032ba2011-08-31 14:08:15 -0700382 unsigned int s_mask[2] = {mask0, mask1}, s_val[2] = {val0, val1};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 unsigned long flags;
384 int rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
386 if (voter < 0 || voter >= RPM_VREG_VOTER_COUNT)
387 return -EINVAL;
388
David Collins6f032ba2011-08-31 14:08:15 -0700389 spin_lock_irqsave(&rpm_noirq_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390
391 /*
392 * Send sleep set request first so that subsequent set_mode, etc calls
393 * use the voltage from the active set.
394 */
395 if (sleep)
396 rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
397 mask0, val0, mask1, val1, cnt, update_voltage);
398 else {
399 /*
400 * Vote for 0 V in the sleep set when active set-only is
401 * specified. This ensures that a disable vote will be issued
402 * at some point for the sleep set of the regulator.
403 */
David Collins6f032ba2011-08-31 14:08:15 -0700404 if (vreg->part->uV.mask) {
405 s_val[vreg->part->uV.word] = 0 << vreg->part->uV.shift;
406 s_mask[vreg->part->uV.word] = vreg->part->uV.mask;
David Collins13397f22012-02-06 13:53:29 -0800407 } else if (vreg->part->mV.mask) {
David Collins6f032ba2011-08-31 14:08:15 -0700408 s_val[vreg->part->mV.word] = 0 << vreg->part->mV.shift;
409 s_mask[vreg->part->mV.word] = vreg->part->mV.mask;
David Collins13397f22012-02-06 13:53:29 -0800410 } else if (vreg->part->enable_state.mask) {
411 s_val[vreg->part->enable_state.word]
412 = 0 << vreg->part->enable_state.shift;
413 s_mask[vreg->part->enable_state.word]
414 = vreg->part->enable_state.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 }
416
417 rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_SLEEP,
David Collins6f032ba2011-08-31 14:08:15 -0700418 s_mask[0], s_val[0], s_mask[1], s_val[1],
419 cnt, update_voltage);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 }
421
422 rc = vreg_send_request(vreg, voter, MSM_RPM_CTX_SET_0, mask0, val0,
423 mask1, val1, cnt, update_voltage);
424
David Collins6f032ba2011-08-31 14:08:15 -0700425 spin_unlock_irqrestore(&rpm_noirq_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
427 return rc;
428}
429
430/**
431 * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
432 * @vreg: ID for regulator
433 * @voter: ID for the voter
434 * @min_uV: minimum acceptable voltage (in uV) that is voted for
435 * @max_uV: maximum acceptable voltage (in uV) that is voted for
436 * @sleep_also: 0 for active set only, non-0 for active set and sleep set
437 *
438 * Returns 0 on success or errno.
439 *
440 * This function is used to vote for the voltage of a regulator without
441 * using the regulator framework. It is needed by consumers which hold spin
442 * locks or have interrupts disabled because the regulator framework can sleep.
443 * It is also needed by consumers which wish to only vote for active set
444 * regulator voltage.
445 *
446 * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
447 *
448 * This function may only be called for regulators which have the sleep flag
449 * specified in their private data.
David Collins7462b9d2011-10-11 16:02:17 -0700450 *
451 * Consumers can vote to disable a regulator with this function by passing
452 * min_uV = 0 and max_uV = 0.
David Collins13397f22012-02-06 13:53:29 -0800453 *
454 * Voltage switch type regulators may be controlled via rpm_vreg_set_voltage
455 * as well. For this type of regulator, max_uV > 0 is treated as an enable
456 * request and max_uV == 0 is treated as a disable request.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 */
David Collins6f032ba2011-08-31 14:08:15 -0700458int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
459 int max_uV, int sleep_also)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460{
David Collins6f032ba2011-08-31 14:08:15 -0700461 unsigned int mask[2] = {0}, val[2] = {0};
462 struct vreg_range *range;
463 struct vreg *vreg;
464 int uV = min_uV;
465 int lim_min_uV, lim_max_uV, i, rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466
David Collins6f032ba2011-08-31 14:08:15 -0700467 if (!config) {
468 pr_err("rpm-regulator driver has not probed yet.\n");
469 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 }
471
David Collins6f032ba2011-08-31 14:08:15 -0700472 if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
473 pr_err("invalid regulator id=%d\n", vreg_id);
474 return -EINVAL;
475 }
476
477 vreg = &config->vregs[vreg_id];
David Collins6f032ba2011-08-31 14:08:15 -0700478
479 if (!vreg->pdata.sleep_selectable) {
480 vreg_err(vreg, "regulator is not marked sleep selectable\n");
481 return -EINVAL;
482 }
483
David Collins7462b9d2011-10-11 16:02:17 -0700484 /* Allow min_uV == max_uV == 0 to represent a disable request. */
David Collins13397f22012-02-06 13:53:29 -0800485 if ((min_uV != 0 || max_uV != 0)
486 && (vreg->part->uV.mask || vreg->part->mV.mask)) {
David Collins7462b9d2011-10-11 16:02:17 -0700487 /*
488 * Check if request voltage is outside of allowed range. The
489 * regulator core has already checked that constraint range
490 * is inside of the physically allowed range.
491 */
492 lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
493 lim_max_uV = vreg->pdata.init_data.constraints.max_uV;
David Collins6f032ba2011-08-31 14:08:15 -0700494
David Collins7462b9d2011-10-11 16:02:17 -0700495 if (uV < lim_min_uV && max_uV >= lim_min_uV)
496 uV = lim_min_uV;
David Collins6f032ba2011-08-31 14:08:15 -0700497
David Collins7462b9d2011-10-11 16:02:17 -0700498 if (uV < lim_min_uV || uV > lim_max_uV) {
499 vreg_err(vreg, "request v=[%d, %d] is outside allowed "
500 "v=[%d, %d]\n", min_uV, max_uV, lim_min_uV,
501 lim_max_uV);
502 return -EINVAL;
David Collins6f032ba2011-08-31 14:08:15 -0700503 }
David Collins6f032ba2011-08-31 14:08:15 -0700504
David Collins13397f22012-02-06 13:53:29 -0800505 range = &vreg->set_points->range[0];
David Collins7462b9d2011-10-11 16:02:17 -0700506 /* Find the range which uV is inside of. */
507 for (i = vreg->set_points->count - 1; i > 0; i--) {
508 if (uV > vreg->set_points->range[i - 1].max_uV) {
509 range = &vreg->set_points->range[i];
510 break;
511 }
512 }
513
514 /*
515 * Force uV to be an allowed set point and apply a ceiling
516 * function to non-set point values.
517 */
518 uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
519 uV = uV * range->step_uV + range->min_uV;
David Collins3974b612011-11-21 15:07:36 -0800520
521 if (uV > max_uV) {
522 vreg_err(vreg,
523 "request v=[%d, %d] cannot be met by any set point; "
524 "next set point: %d\n",
525 min_uV, max_uV, uV);
526 return -EINVAL;
527 }
David Collins7462b9d2011-10-11 16:02:17 -0700528 }
David Collins6f032ba2011-08-31 14:08:15 -0700529
David Collins0ac31fe2012-02-08 13:53:34 -0800530 if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
531 /*
532 * Translate from enum values which work as inputs in the
533 * rpm_vreg_set_voltage function to the actual corner values
534 * sent to the RPM.
535 */
536 if (uV > 0)
537 uV -= RPM_VREG_CORNER_NONE;
538 }
539
David Collins6f032ba2011-08-31 14:08:15 -0700540 if (vreg->part->uV.mask) {
541 val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
542 mask[vreg->part->uV.word] = vreg->part->uV.mask;
David Collins13397f22012-02-06 13:53:29 -0800543 } else if (vreg->part->mV.mask) {
David Collins6f032ba2011-08-31 14:08:15 -0700544 val[vreg->part->mV.word]
545 = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
546 mask[vreg->part->mV.word] = vreg->part->mV.mask;
David Collins13397f22012-02-06 13:53:29 -0800547 } else if (vreg->part->enable_state.mask) {
548 /*
549 * Translate max_uV > 0 into an enable request for regulator
550 * types which to not support voltage setting, e.g. voltage
551 * switches.
552 */
553 val[vreg->part->enable_state.word]
554 = (max_uV > 0 ? 1 : 0) << vreg->part->enable_state.shift;
555 mask[vreg->part->enable_state.word]
556 = vreg->part->enable_state.mask;
David Collins6f032ba2011-08-31 14:08:15 -0700557 }
558
559 rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
560 val[1], vreg->part->request_len, 1);
561 if (rc)
562 vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563
564 return rc;
565}
566EXPORT_SYMBOL_GPL(rpm_vreg_set_voltage);
567
568/**
569 * rpm_vreg_set_frequency - sets the frequency of a switching regulator
570 * @vreg: ID for regulator
David Collins6f032ba2011-08-31 14:08:15 -0700571 * @freq: enum corresponding to desired frequency
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 *
573 * Returns 0 on success or errno.
574 */
David Collins6f032ba2011-08-31 14:08:15 -0700575int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576{
David Collins6f032ba2011-08-31 14:08:15 -0700577 unsigned int mask[2] = {0}, val[2] = {0};
578 struct vreg *vreg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579 int rc;
580
David Collins6f032ba2011-08-31 14:08:15 -0700581 if (!config) {
582 pr_err("rpm-regulator driver has not probed yet.\n");
583 return -ENODEV;
584 }
585
586 if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
587 pr_err("invalid regulator id=%d\n", vreg_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 return -EINVAL;
589 }
590
David Collins6f032ba2011-08-31 14:08:15 -0700591 vreg = &config->vregs[vreg_id];
592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 if (freq < 0 || freq > RPM_VREG_FREQ_1p20) {
David Collins6f032ba2011-08-31 14:08:15 -0700594 vreg_err(vreg, "invalid frequency=%d\n", freq);
595 return -EINVAL;
596 }
597 if (!vreg->pdata.sleep_selectable) {
598 vreg_err(vreg, "regulator is not marked sleep selectable\n");
599 return -EINVAL;
600 }
601 if (!vreg->part->freq.mask) {
602 vreg_err(vreg, "frequency not supported\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 return -EINVAL;
604 }
605
David Collins6f032ba2011-08-31 14:08:15 -0700606 val[vreg->part->freq.word] = freq << vreg->part->freq.shift;
607 mask[vreg->part->freq.word] = vreg->part->freq.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608
David Collins6f032ba2011-08-31 14:08:15 -0700609 rc = vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1, mask[0],
610 val[0], mask[1], val[1], vreg->part->request_len, 0);
611 if (rc)
612 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613
614 return rc;
615}
616EXPORT_SYMBOL_GPL(rpm_vreg_set_frequency);
617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618static inline int vreg_hpm_min_uA(struct vreg *vreg)
619{
620 return vreg->hpm_min_load;
621}
622
623static inline int vreg_lpm_max_uA(struct vreg *vreg)
624{
625 return vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
626}
627
David Collins6f032ba2011-08-31 14:08:15 -0700628static inline unsigned saturate_peak_load(struct vreg *vreg, unsigned load_uA)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629{
David Collins6f032ba2011-08-31 14:08:15 -0700630 unsigned load_max
631 = MILLI_TO_MICRO(vreg->part->ip.mask >> vreg->part->ip.shift);
632
633 return (load_uA > load_max ? load_max : load_uA);
634}
635
636static inline unsigned saturate_avg_load(struct vreg *vreg, unsigned load_uA)
637{
638 unsigned load_max
639 = MILLI_TO_MICRO(vreg->part->ia.mask >> vreg->part->ia.shift);
640 return (load_uA > load_max ? load_max : load_uA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641}
642
643/* Change vreg->req, but do not send it to the RPM. */
644static int vreg_store(struct vreg *vreg, unsigned mask0, unsigned val0,
645 unsigned mask1, unsigned val1)
646{
647 unsigned long flags = 0;
648
David Collins6f032ba2011-08-31 14:08:15 -0700649 if (vreg->pdata.sleep_selectable)
650 spin_lock_irqsave(&rpm_noirq_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651
652 vreg->req[0].value &= ~mask0;
653 vreg->req[0].value |= val0 & mask0;
654
655 vreg->req[1].value &= ~mask1;
656 vreg->req[1].value |= val1 & mask1;
657
David Collins6f032ba2011-08-31 14:08:15 -0700658 if (vreg->pdata.sleep_selectable)
659 spin_unlock_irqrestore(&rpm_noirq_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660
661 return 0;
662}
663
664static int vreg_set(struct vreg *vreg, unsigned mask0, unsigned val0,
665 unsigned mask1, unsigned val1, unsigned cnt)
666{
667 unsigned prev0 = 0, prev1 = 0;
668 int rc;
669
670 /*
671 * Bypass the normal route for regulators that can be called to change
672 * just the active set values.
673 */
David Collins6f032ba2011-08-31 14:08:15 -0700674 if (vreg->pdata.sleep_selectable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 return vreg_set_noirq(vreg, RPM_VREG_VOTER_REG_FRAMEWORK, 1,
676 mask0, val0, mask1, val1, cnt, 1);
677
678 prev0 = vreg->req[0].value;
679 vreg->req[0].value &= ~mask0;
680 vreg->req[0].value |= val0 & mask0;
681
682 prev1 = vreg->req[1].value;
683 vreg->req[1].value &= ~mask1;
684 vreg->req[1].value |= val1 & mask1;
685
686 /* Ignore duplicate requests */
687 if (vreg->req[0].value == vreg->prev_active_req[0].value &&
688 vreg->req[1].value == vreg->prev_active_req[1].value) {
689 if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_DUPLICATE)
David Collins6f032ba2011-08-31 14:08:15 -0700690 rpm_regulator_duplicate(vreg, MSM_RPM_CTX_SET_0, cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 return 0;
692 }
693
694 rc = msm_rpm_set(MSM_RPM_CTX_SET_0, vreg->req, cnt);
695 if (rc) {
696 vreg->req[0].value = prev0;
697 vreg->req[1].value = prev1;
698
David Collins6f032ba2011-08-31 14:08:15 -0700699 vreg_err(vreg, "msm_rpm_set failed, set=active, id=%d, rc=%d\n",
700 vreg->req[0].id, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701 } else {
702 if (msm_rpm_vreg_debug_mask & MSM_RPM_VREG_DEBUG_REQUEST)
David Collins6f032ba2011-08-31 14:08:15 -0700703 rpm_regulator_req(vreg, MSM_RPM_CTX_SET_0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 vreg->prev_active_req[0].value = vreg->req[0].value;
705 vreg->prev_active_req[1].value = vreg->req[1].value;
706 }
707
708 return rc;
709}
710
David Collins6f032ba2011-08-31 14:08:15 -0700711static int vreg_is_enabled(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700712{
David Collins6f032ba2011-08-31 14:08:15 -0700713 struct vreg *vreg = rdev_get_drvdata(rdev);
714 int enabled;
715
716 mutex_lock(&vreg->pc_lock);
717 enabled = vreg->is_enabled;
718 mutex_unlock(&vreg->pc_lock);
719
720 return enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721}
722
David Collins6f032ba2011-08-31 14:08:15 -0700723static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724{
David Collins6f032ba2011-08-31 14:08:15 -0700725 switch (vreg->type) {
726 case RPM_REGULATOR_TYPE_LDO:
727 case RPM_REGULATOR_TYPE_SMPS:
David Collins0ac31fe2012-02-08 13:53:34 -0800728 case RPM_REGULATOR_TYPE_CORNER:
David Collins6f032ba2011-08-31 14:08:15 -0700729 /* Enable by setting a voltage. */
730 if (vreg->part->uV.mask) {
731 val[vreg->part->uV.word]
732 |= vreg->save_uV << vreg->part->uV.shift;
733 mask[vreg->part->uV.word] |= vreg->part->uV.mask;
734 } else {
735 val[vreg->part->mV.word]
736 |= MICRO_TO_MILLI(vreg->save_uV)
737 << vreg->part->mV.shift;
738 mask[vreg->part->mV.word] |= vreg->part->mV.mask;
739 }
740 break;
741 case RPM_REGULATOR_TYPE_VS:
742 case RPM_REGULATOR_TYPE_NCP:
743 /* Enable by setting enable_state. */
744 val[vreg->part->enable_state.word]
745 |= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
746 mask[vreg->part->enable_state.word]
747 |= vreg->part->enable_state.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749}
750
David Collins0ac31fe2012-02-08 13:53:34 -0800751static int rpm_vreg_enable(struct regulator_dev *rdev)
David Collins6f032ba2011-08-31 14:08:15 -0700752{
753 struct vreg *vreg = rdev_get_drvdata(rdev);
754 unsigned int mask[2] = {0}, val[2] = {0};
755 int rc = 0;
756
757 set_enable(vreg, mask, val);
758
759 mutex_lock(&vreg->pc_lock);
760
761 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
762 vreg->part->request_len);
763 if (!rc)
764 vreg->is_enabled = true;
765
766 mutex_unlock(&vreg->pc_lock);
767
768 if (rc)
769 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
770
771 return rc;
772}
773
774static void set_disable(struct vreg *vreg, unsigned int *mask,
775 unsigned int *val)
776{
777 switch (vreg->type) {
778 case RPM_REGULATOR_TYPE_LDO:
779 case RPM_REGULATOR_TYPE_SMPS:
David Collins0ac31fe2012-02-08 13:53:34 -0800780 case RPM_REGULATOR_TYPE_CORNER:
David Collins6f032ba2011-08-31 14:08:15 -0700781 /* Disable by setting a voltage of 0 uV. */
782 if (vreg->part->uV.mask) {
783 val[vreg->part->uV.word] |= 0 << vreg->part->uV.shift;
784 mask[vreg->part->uV.word] |= vreg->part->uV.mask;
785 } else {
786 val[vreg->part->mV.word] |= 0 << vreg->part->mV.shift;
787 mask[vreg->part->mV.word] |= vreg->part->mV.mask;
788 }
789 break;
790 case RPM_REGULATOR_TYPE_VS:
791 case RPM_REGULATOR_TYPE_NCP:
792 /* Disable by setting enable_state. */
793 val[vreg->part->enable_state.word]
794 |= RPM_VREG_STATE_OFF << vreg->part->enable_state.shift;
795 mask[vreg->part->enable_state.word]
796 |= vreg->part->enable_state.mask;
797 }
798}
799
David Collins0ac31fe2012-02-08 13:53:34 -0800800static int rpm_vreg_disable(struct regulator_dev *rdev)
David Collins6f032ba2011-08-31 14:08:15 -0700801{
802 struct vreg *vreg = rdev_get_drvdata(rdev);
803 unsigned int mask[2] = {0}, val[2] = {0};
804 int rc = 0;
805
806 set_disable(vreg, mask, val);
807
808 mutex_lock(&vreg->pc_lock);
809
810 /* Only disable if pin control is not in use. */
811 if (!vreg->is_enabled_pc)
812 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
813 vreg->part->request_len);
814
815 if (!rc)
816 vreg->is_enabled = false;
817
818 mutex_unlock(&vreg->pc_lock);
819
820 if (rc)
821 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
822
823 return rc;
824}
825
826static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 unsigned *selector)
828{
David Collins6f032ba2011-08-31 14:08:15 -0700829 struct vreg *vreg = rdev_get_drvdata(rdev);
830 struct vreg_range *range = &vreg->set_points->range[0];
831 unsigned int mask[2] = {0}, val[2] = {0};
832 int rc = 0, uV = min_uV;
833 int lim_min_uV, lim_max_uV, i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834
David Collins6f032ba2011-08-31 14:08:15 -0700835 /* Check if request voltage is outside of physically settable range. */
836 lim_min_uV = vreg->set_points->range[0].min_uV;
837 lim_max_uV =
838 vreg->set_points->range[vreg->set_points->count - 1].max_uV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839
David Collins6f032ba2011-08-31 14:08:15 -0700840 if (uV < lim_min_uV && max_uV >= lim_min_uV)
841 uV = lim_min_uV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842
David Collins6f032ba2011-08-31 14:08:15 -0700843 if (uV < lim_min_uV || uV > lim_max_uV) {
844 vreg_err(vreg,
845 "request v=[%d, %d] is outside possible v=[%d, %d]\n",
846 min_uV, max_uV, lim_min_uV, lim_max_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 return -EINVAL;
848 }
849
David Collins6f032ba2011-08-31 14:08:15 -0700850 /* Find the range which uV is inside of. */
851 for (i = vreg->set_points->count - 1; i > 0; i--) {
852 if (uV > vreg->set_points->range[i - 1].max_uV) {
853 range = &vreg->set_points->range[i];
854 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 }
856 }
857
David Collins6f032ba2011-08-31 14:08:15 -0700858 /*
859 * Force uV to be an allowed set point and apply a ceiling function
860 * to non-set point values.
861 */
862 uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
863 uV = uV * range->step_uV + range->min_uV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864
David Collins3974b612011-11-21 15:07:36 -0800865 if (uV > max_uV) {
866 vreg_err(vreg,
867 "request v=[%d, %d] cannot be met by any set point; "
868 "next set point: %d\n",
869 min_uV, max_uV, uV);
870 return -EINVAL;
871 }
872
David Collins0ac31fe2012-02-08 13:53:34 -0800873 if (vreg->type == RPM_REGULATOR_TYPE_CORNER) {
874 /*
875 * Translate from enum values which work as inputs in the
876 * regulator_set_voltage function to the actual corner values
877 * sent to the RPM.
878 */
879 uV -= RPM_VREG_CORNER_NONE;
880 }
881
David Collins6f032ba2011-08-31 14:08:15 -0700882 if (vreg->part->uV.mask) {
883 val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
884 mask[vreg->part->uV.word] = vreg->part->uV.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 } else {
David Collins6f032ba2011-08-31 14:08:15 -0700886 val[vreg->part->mV.word]
887 = MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
888 mask[vreg->part->mV.word] = vreg->part->mV.mask;
889 }
890
891 mutex_lock(&vreg->pc_lock);
892
893 /*
894 * Only send a request for a new voltage if the regulator is currently
895 * enabled. This will ensure that LDO and SMPS regulators are not
896 * inadvertently turned on because voltage > 0 is equivalent to
897 * enabling. For NCP, this just removes unnecessary RPM requests.
898 */
899 if (vreg->is_enabled) {
900 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
901 vreg->part->request_len);
902 if (rc)
903 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
904 } else if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 /* Regulator is disabled; store but don't send new request. */
David Collins6f032ba2011-08-31 14:08:15 -0700906 rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 }
908
David Collins6f032ba2011-08-31 14:08:15 -0700909 if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
910 vreg->save_uV = uV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
David Collins6f032ba2011-08-31 14:08:15 -0700912 mutex_unlock(&vreg->pc_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913
914 return rc;
915}
916
David Collins6f032ba2011-08-31 14:08:15 -0700917static int vreg_get_voltage(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918{
David Collins6f032ba2011-08-31 14:08:15 -0700919 struct vreg *vreg = rdev_get_drvdata(rdev);
920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 return vreg->save_uV;
922}
923
David Collins6f032ba2011-08-31 14:08:15 -0700924static int vreg_list_voltage(struct regulator_dev *rdev, unsigned selector)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925{
David Collins6f032ba2011-08-31 14:08:15 -0700926 struct vreg *vreg = rdev_get_drvdata(rdev);
927 int uV = 0;
928 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929
David Collins6f032ba2011-08-31 14:08:15 -0700930 if (!vreg->set_points) {
931 vreg_err(vreg, "no voltages available\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 return -EINVAL;
933 }
934
David Collins6f032ba2011-08-31 14:08:15 -0700935 if (selector >= vreg->set_points->n_voltages)
936 return 0;
937
938 for (i = 0; i < vreg->set_points->count; i++) {
939 if (selector < vreg->set_points->range[i].n_voltages) {
940 uV = selector * vreg->set_points->range[i].step_uV
941 + vreg->set_points->range[i].min_uV;
942 break;
943 } else {
944 selector -= vreg->set_points->range[i].n_voltages;
945 }
946 }
947
948 return uV;
949}
950
951static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
952{
953 struct vreg *vreg = rdev_get_drvdata(rdev);
954 unsigned int mask[2] = {0}, val[2] = {0};
955 int rc = 0;
956 int peak_uA;
957
958 mutex_lock(&vreg->pc_lock);
959
960 peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
961 & vreg->part->ip.mask) >> vreg->part->ip.shift);
962
963 if (mode == config->mode_hpm) {
964 /* Make sure that request currents are in HPM range. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 if (peak_uA < vreg_hpm_min_uA(vreg)) {
David Collins6f032ba2011-08-31 14:08:15 -0700966 val[vreg->part->ip.word]
967 = MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
968 << vreg->part->ip.shift;
969 mask[vreg->part->ip.word] = vreg->part->ip.mask;
970
971 if (config->ia_follows_ip) {
972 val[vreg->part->ia.word]
973 |= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
974 << vreg->part->ia.shift;
975 mask[vreg->part->ia.word]
976 |= vreg->part->ia.mask;
977 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 }
David Collins6f032ba2011-08-31 14:08:15 -0700979 } else if (mode == config->mode_lpm) {
980 /* Make sure that request currents are in LPM range. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981 if (peak_uA > vreg_lpm_max_uA(vreg)) {
David Collins6f032ba2011-08-31 14:08:15 -0700982 val[vreg->part->ip.word]
983 = MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
984 << vreg->part->ip.shift;
985 mask[vreg->part->ip.word] = vreg->part->ip.mask;
986
987 if (config->ia_follows_ip) {
988 val[vreg->part->ia.word]
989 |= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
990 << vreg->part->ia.shift;
991 mask[vreg->part->ia.word]
992 |= vreg->part->ia.mask;
993 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 }
David Collins6f032ba2011-08-31 14:08:15 -0700995 } else {
996 vreg_err(vreg, "invalid mode: %u\n", mode);
997 mutex_unlock(&vreg->pc_lock);
998 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 }
1000
David Collins6f032ba2011-08-31 14:08:15 -07001001 if (vreg->is_enabled) {
1002 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
1003 vreg->part->request_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004 } else {
1005 /* Regulator is disabled; store but don't send new request. */
David Collins6f032ba2011-08-31 14:08:15 -07001006 rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 }
David Collins6f032ba2011-08-31 14:08:15 -07001008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 if (rc)
David Collins6f032ba2011-08-31 14:08:15 -07001010 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
1011 else
1012 vreg->mode = mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013
David Collins6f032ba2011-08-31 14:08:15 -07001014 mutex_unlock(&vreg->pc_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015
David Collins6f032ba2011-08-31 14:08:15 -07001016 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017}
1018
David Collins6f032ba2011-08-31 14:08:15 -07001019static unsigned int vreg_get_mode(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020{
David Collins6f032ba2011-08-31 14:08:15 -07001021 struct vreg *vreg = rdev_get_drvdata(rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022
David Collins6f032ba2011-08-31 14:08:15 -07001023 return vreg->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024}
1025
David Collins6f032ba2011-08-31 14:08:15 -07001026static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
1027 int input_uV, int output_uV, int load_uA)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028{
David Collins6f032ba2011-08-31 14:08:15 -07001029 struct vreg *vreg = rdev_get_drvdata(rdev);
1030 unsigned int mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031
David Collins6f032ba2011-08-31 14:08:15 -07001032 load_uA += vreg->pdata.system_uA;
1033
1034 mutex_lock(&vreg->pc_lock);
1035 SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
1036 if (config->ia_follows_ip)
1037 SET_PART(vreg, ia,
1038 MICRO_TO_MILLI(saturate_avg_load(vreg, load_uA)));
1039 mutex_unlock(&vreg->pc_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040
1041 if (load_uA >= vreg->hpm_min_load)
David Collins6f032ba2011-08-31 14:08:15 -07001042 mode = config->mode_hpm;
1043 else
1044 mode = config->mode_lpm;
1045
1046 return mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047}
1048
David Collins6f032ba2011-08-31 14:08:15 -07001049static unsigned int vreg_legacy_get_optimum_mode(struct regulator_dev *rdev,
1050 int input_uV, int output_uV, int load_uA)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051{
David Collins6f032ba2011-08-31 14:08:15 -07001052 struct vreg *vreg = rdev_get_drvdata(rdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053
David Collins6f032ba2011-08-31 14:08:15 -07001054 if (MICRO_TO_MILLI(load_uA) <= 0) {
1055 /*
1056 * vreg_legacy_get_optimum_mode is being called before consumers
1057 * have specified their load currents via
1058 * regulator_set_optimum_mode. Return whatever the existing mode
1059 * is.
1060 */
1061 return vreg->mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062 }
1063
David Collins6f032ba2011-08-31 14:08:15 -07001064 return vreg_get_optimum_mode(rdev, input_uV, output_uV, load_uA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065}
1066
1067/*
David Collins6f032ba2011-08-31 14:08:15 -07001068 * Returns the logical pin control enable state because the pin control options
1069 * present in the hardware out of restart could be different from those desired
1070 * by the consumer.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071 */
David Collins6f032ba2011-08-31 14:08:15 -07001072static int vreg_pin_control_is_enabled(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073{
David Collins6f032ba2011-08-31 14:08:15 -07001074 struct vreg *vreg = rdev_get_drvdata(rdev);
1075
1076 return vreg->is_enabled_pc;
1077}
1078
1079static int vreg_pin_control_enable(struct regulator_dev *rdev)
1080{
1081 struct vreg *vreg = rdev_get_drvdata(rdev);
1082 unsigned int mask[2] = {0}, val[2] = {0};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 int rc;
1084
David Collins6f032ba2011-08-31 14:08:15 -07001085 mutex_lock(&vreg->pc_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086
David Collins6f032ba2011-08-31 14:08:15 -07001087 val[vreg->part->pc.word]
1088 |= vreg->pdata.pin_ctrl << vreg->part->pc.shift;
1089 mask[vreg->part->pc.word] |= vreg->part->pc.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090
David Collins6f032ba2011-08-31 14:08:15 -07001091 val[vreg->part->pf.word] |= vreg->pdata.pin_fn << vreg->part->pf.shift;
1092 mask[vreg->part->pf.word] |= vreg->part->pf.mask;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093
David Collins6f032ba2011-08-31 14:08:15 -07001094 if (!vreg->is_enabled)
1095 set_enable(vreg, mask, val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096
David Collins6f032ba2011-08-31 14:08:15 -07001097 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
1098 vreg->part->request_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099
David Collins6f032ba2011-08-31 14:08:15 -07001100 if (!rc)
1101 vreg->is_enabled_pc = true;
1102
1103 mutex_unlock(&vreg->pc_lock);
1104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 if (rc)
David Collins6f032ba2011-08-31 14:08:15 -07001106 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107
David Collins6f032ba2011-08-31 14:08:15 -07001108 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109}
1110
David Collins6f032ba2011-08-31 14:08:15 -07001111static int vreg_pin_control_disable(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112{
David Collins6f032ba2011-08-31 14:08:15 -07001113 struct vreg *vreg = rdev_get_drvdata(rdev);
1114 unsigned int mask[2] = {0}, val[2] = {0};
1115 int pin_fn, rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116
David Collins6f032ba2011-08-31 14:08:15 -07001117 mutex_lock(&vreg->pc_lock);
1118
1119 val[vreg->part->pc.word]
1120 |= RPM_VREG_PIN_CTRL_NONE << vreg->part->pc.shift;
1121 mask[vreg->part->pc.word] |= vreg->part->pc.mask;
1122
1123 pin_fn = config->pin_func_none;
1124 if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
1125 pin_fn = config->pin_func_sleep_b;
1126 val[vreg->part->pf.word] |= pin_fn << vreg->part->pf.shift;
1127 mask[vreg->part->pf.word] |= vreg->part->pf.mask;
1128
1129 if (!vreg->is_enabled)
1130 set_disable(vreg, mask, val);
1131
1132 rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
1133 vreg->part->request_len);
1134
1135 if (!rc)
1136 vreg->is_enabled_pc = false;
1137
1138 mutex_unlock(&vreg->pc_lock);
1139
1140 if (rc)
1141 vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
1142
1143 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144}
1145
David Collins6f032ba2011-08-31 14:08:15 -07001146static int vreg_enable_time(struct regulator_dev *rdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147{
David Collins6f032ba2011-08-31 14:08:15 -07001148 struct vreg *vreg = rdev_get_drvdata(rdev);
1149
1150 return vreg->pdata.enable_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151}
1152
David Collins6f032ba2011-08-31 14:08:15 -07001153/* Real regulator operations. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154static struct regulator_ops ldo_ops = {
David Collins0ac31fe2012-02-08 13:53:34 -08001155 .enable = rpm_vreg_enable,
1156 .disable = rpm_vreg_disable,
David Collins6f032ba2011-08-31 14:08:15 -07001157 .is_enabled = vreg_is_enabled,
1158 .set_voltage = vreg_set_voltage,
1159 .get_voltage = vreg_get_voltage,
1160 .list_voltage = vreg_list_voltage,
1161 .set_mode = vreg_set_mode,
1162 .get_mode = vreg_get_mode,
1163 .get_optimum_mode = vreg_get_optimum_mode,
1164 .enable_time = vreg_enable_time,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165};
1166
1167static struct regulator_ops smps_ops = {
David Collins0ac31fe2012-02-08 13:53:34 -08001168 .enable = rpm_vreg_enable,
1169 .disable = rpm_vreg_disable,
David Collins6f032ba2011-08-31 14:08:15 -07001170 .is_enabled = vreg_is_enabled,
1171 .set_voltage = vreg_set_voltage,
1172 .get_voltage = vreg_get_voltage,
1173 .list_voltage = vreg_list_voltage,
1174 .set_mode = vreg_set_mode,
1175 .get_mode = vreg_get_mode,
1176 .get_optimum_mode = vreg_get_optimum_mode,
1177 .enable_time = vreg_enable_time,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178};
1179
1180static struct regulator_ops switch_ops = {
David Collins0ac31fe2012-02-08 13:53:34 -08001181 .enable = rpm_vreg_enable,
1182 .disable = rpm_vreg_disable,
David Collins6f032ba2011-08-31 14:08:15 -07001183 .is_enabled = vreg_is_enabled,
1184 .enable_time = vreg_enable_time,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185};
1186
1187static struct regulator_ops ncp_ops = {
David Collins0ac31fe2012-02-08 13:53:34 -08001188 .enable = rpm_vreg_enable,
1189 .disable = rpm_vreg_disable,
1190 .is_enabled = vreg_is_enabled,
1191 .set_voltage = vreg_set_voltage,
1192 .get_voltage = vreg_get_voltage,
1193 .list_voltage = vreg_list_voltage,
1194 .enable_time = vreg_enable_time,
1195};
1196
1197static struct regulator_ops corner_ops = {
1198 .enable = rpm_vreg_enable,
1199 .disable = rpm_vreg_disable,
David Collins6f032ba2011-08-31 14:08:15 -07001200 .is_enabled = vreg_is_enabled,
1201 .set_voltage = vreg_set_voltage,
1202 .get_voltage = vreg_get_voltage,
1203 .list_voltage = vreg_list_voltage,
1204 .enable_time = vreg_enable_time,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205};
1206
David Collins6f032ba2011-08-31 14:08:15 -07001207/* Pin control regulator operations. */
1208static struct regulator_ops pin_control_ops = {
1209 .enable = vreg_pin_control_enable,
1210 .disable = vreg_pin_control_disable,
1211 .is_enabled = vreg_pin_control_is_enabled,
1212};
1213
1214struct regulator_ops *vreg_ops[] = {
1215 [RPM_REGULATOR_TYPE_LDO] = &ldo_ops,
1216 [RPM_REGULATOR_TYPE_SMPS] = &smps_ops,
1217 [RPM_REGULATOR_TYPE_VS] = &switch_ops,
1218 [RPM_REGULATOR_TYPE_NCP] = &ncp_ops,
David Collins0ac31fe2012-02-08 13:53:34 -08001219 [RPM_REGULATOR_TYPE_CORNER] = &corner_ops,
David Collins6f032ba2011-08-31 14:08:15 -07001220};
1221
1222static int __devinit
1223rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
1224 struct device *dev)
1225{
1226 struct regulator_desc *rdesc = NULL;
1227 struct regulator_dev *rdev;
1228 struct vreg *vreg;
1229 unsigned pin_ctrl;
1230 int id, pin_fn;
1231 int rc = 0;
1232
1233 if (!pdata) {
1234 pr_err("platform data missing\n");
1235 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 }
1237
David Collins6f032ba2011-08-31 14:08:15 -07001238 id = pdata->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239
David Collins6f032ba2011-08-31 14:08:15 -07001240 if (id < config->vreg_id_min || id > config->vreg_id_max) {
1241 pr_err("invalid regulator id: %d\n", id);
1242 return -ENODEV;
1243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244
David Collins6f032ba2011-08-31 14:08:15 -07001245 if (!config->is_real_id(pdata->id))
1246 id = config->pc_id_to_real_id(pdata->id);
1247 vreg = &config->vregs[id];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248
David Collins6f032ba2011-08-31 14:08:15 -07001249 if (config->is_real_id(pdata->id))
1250 rdesc = &vreg->rdesc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 else
David Collins6f032ba2011-08-31 14:08:15 -07001252 rdesc = &vreg->rdesc_pc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253
David Collins6f032ba2011-08-31 14:08:15 -07001254 if (vreg->type < 0 || vreg->type > RPM_REGULATOR_TYPE_MAX) {
1255 pr_err("%s: invalid regulator type: %d\n",
1256 vreg->rdesc.name, vreg->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 return -EINVAL;
David Collins6f032ba2011-08-31 14:08:15 -07001258 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259
David Collins6f032ba2011-08-31 14:08:15 -07001260 mutex_lock(&vreg->pc_lock);
1261
1262 if (vreg->set_points)
1263 rdesc->n_voltages = vreg->set_points->n_voltages;
1264 else
1265 rdesc->n_voltages = 0;
1266
1267 rdesc->id = pdata->id;
1268 rdesc->owner = THIS_MODULE;
1269 rdesc->type = REGULATOR_VOLTAGE;
1270
1271 if (config->is_real_id(pdata->id)) {
1272 /*
1273 * Real regulator; do not modify pin control and pin function
1274 * values.
1275 */
1276 rdesc->ops = vreg_ops[vreg->type];
1277 pin_ctrl = vreg->pdata.pin_ctrl;
1278 pin_fn = vreg->pdata.pin_fn;
1279 memcpy(&(vreg->pdata), pdata,
1280 sizeof(struct rpm_regulator_init_data));
1281 vreg->pdata.pin_ctrl = pin_ctrl;
1282 vreg->pdata.pin_fn = pin_fn;
1283
1284 vreg->save_uV = vreg->pdata.default_uV;
1285 if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
1286 vreg->mode = config->mode_hpm;
1287 else
1288 vreg->mode = config->mode_lpm;
1289
1290 /* Initialize the RPM request. */
1291 SET_PART(vreg, ip,
1292 MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
1293 SET_PART(vreg, fm, vreg->pdata.force_mode);
1294 SET_PART(vreg, pm, vreg->pdata.power_mode);
1295 SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
1296 SET_PART(vreg, ia,
1297 MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
1298 SET_PART(vreg, freq, vreg->pdata.freq);
1299 SET_PART(vreg, freq_clk_src, 0);
1300 SET_PART(vreg, comp_mode, 0);
1301 SET_PART(vreg, hpm, 0);
1302 if (!vreg->is_enabled_pc) {
1303 SET_PART(vreg, pf, config->pin_func_none);
1304 SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
1305 }
1306 } else {
1307 if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
1308 == RPM_VREG_PIN_CTRL_NONE
1309 && pdata->pin_fn != config->pin_func_sleep_b) {
1310 pr_err("%s: no pin control input specified\n",
1311 vreg->rdesc.name);
1312 mutex_unlock(&vreg->pc_lock);
1313 return -EINVAL;
1314 }
1315 rdesc->ops = &pin_control_ops;
1316 vreg->pdata.pin_ctrl = pdata->pin_ctrl;
1317 vreg->pdata.pin_fn = pdata->pin_fn;
1318
1319 /* Initialize the RPM request. */
1320 pin_fn = config->pin_func_none;
1321 /* Allow pf=sleep_b to be specified by platform data. */
1322 if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
1323 pin_fn = config->pin_func_sleep_b;
1324 SET_PART(vreg, pf, pin_fn);
1325 SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
1326 }
1327
1328 mutex_unlock(&vreg->pc_lock);
1329
1330 if (rc)
1331 goto bail;
1332
Rajendra Nayak11eafc62011-11-18 16:47:19 +05301333 rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg, NULL);
David Collins6f032ba2011-08-31 14:08:15 -07001334 if (IS_ERR(rdev)) {
1335 rc = PTR_ERR(rdev);
1336 pr_err("regulator_register failed: %s, rc=%d\n",
1337 vreg->rdesc.name, rc);
1338 return rc;
1339 } else {
1340 if (config->is_real_id(pdata->id))
1341 vreg->rdev = rdev;
1342 else
1343 vreg->rdev_pc = rdev;
1344 }
1345
1346bail:
1347 if (rc)
1348 pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
1349
1350 return rc;
1351}
1352
1353static void rpm_vreg_set_point_init(void)
1354{
1355 struct vreg_set_points **set_points;
1356 int i, j, temp;
1357
1358 set_points = config->set_points;
1359
1360 /* Calculate the number of set points available for each regulator. */
1361 for (i = 0; i < config->set_points_len; i++) {
1362 temp = 0;
1363 for (j = 0; j < set_points[i]->count; j++) {
1364 set_points[i]->range[j].n_voltages
1365 = (set_points[i]->range[j].max_uV
1366 - set_points[i]->range[j].min_uV)
1367 / set_points[i]->range[j].step_uV + 1;
1368 temp += set_points[i]->range[j].n_voltages;
1369 }
1370 set_points[i]->n_voltages = temp;
1371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372}
1373
1374static int __devinit rpm_vreg_probe(struct platform_device *pdev)
1375{
David Collins6f032ba2011-08-31 14:08:15 -07001376 struct rpm_regulator_platform_data *platform_data;
1377 int rc = 0;
1378 int i, id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379
David Collins6f032ba2011-08-31 14:08:15 -07001380 platform_data = pdev->dev.platform_data;
1381 if (!platform_data) {
1382 pr_err("rpm-regulator requires platform data\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001383 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 }
1385
David Collins6f032ba2011-08-31 14:08:15 -07001386 if (rpm_version >= 0 && rpm_version <= RPM_VREG_VERSION_MAX
1387 && platform_data->version != rpm_version) {
1388 pr_err("rpm version %d does not match previous version %d\n",
1389 platform_data->version, rpm_version);
1390 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001391 }
1392
David Collins6f032ba2011-08-31 14:08:15 -07001393 if (platform_data->version < 0
1394 || platform_data->version > RPM_VREG_VERSION_MAX) {
1395 pr_err("rpm version %d is invalid\n", platform_data->version);
1396 return -EINVAL;
1397 }
1398
1399 if (rpm_version < 0 || rpm_version > RPM_VREG_VERSION_MAX) {
1400 rpm_version = platform_data->version;
1401 config = get_config[platform_data->version]();
1402 vreg_id_vdd_mem = platform_data->vreg_id_vdd_mem;
1403 vreg_id_vdd_dig = platform_data->vreg_id_vdd_dig;
1404 if (!config) {
1405 pr_err("rpm version %d is not available\n",
1406 platform_data->version);
1407 return -ENODEV;
1408 }
1409 if (config->use_legacy_optimum_mode)
1410 for (i = 0; i < ARRAY_SIZE(vreg_ops); i++)
1411 vreg_ops[i]->get_optimum_mode
1412 = vreg_legacy_get_optimum_mode;
1413 rpm_vreg_set_point_init();
1414 /* First time probed; initialize pin control mutexes. */
1415 for (i = 0; i < config->vregs_len; i++)
1416 mutex_init(&config->vregs[i].pc_lock);
1417 }
1418
1419 /* Initialize all of the regulators listed in the platform data. */
1420 for (i = 0; i < platform_data->num_regulators; i++) {
1421 rc = rpm_vreg_init_regulator(&platform_data->init_data[i],
1422 &pdev->dev);
1423 if (rc) {
1424 pr_err("rpm_vreg_init_regulator failed, rc=%d\n", rc);
1425 goto remove_regulators;
1426 }
1427 }
1428
1429 platform_set_drvdata(pdev, platform_data);
1430
1431 return rc;
1432
1433remove_regulators:
1434 /* Unregister all regulators added before the erroring one. */
1435 for (; i >= 0; i--) {
1436 id = platform_data->init_data[i].id;
1437 if (config->is_real_id(id)) {
1438 regulator_unregister(config->vregs[id].rdev);
1439 config->vregs[id].rdev = NULL;
1440 } else {
1441 regulator_unregister(config->vregs[
1442 config->pc_id_to_real_id(id)].rdev_pc);
1443 config->vregs[id].rdev_pc = NULL;
1444 }
1445 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446
1447 return rc;
1448}
1449
1450static int __devexit rpm_vreg_remove(struct platform_device *pdev)
1451{
David Collins6f032ba2011-08-31 14:08:15 -07001452 struct rpm_regulator_platform_data *platform_data;
1453 int i, id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454
David Collins6f032ba2011-08-31 14:08:15 -07001455 platform_data = platform_get_drvdata(pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 platform_set_drvdata(pdev, NULL);
David Collins6f032ba2011-08-31 14:08:15 -07001457
1458 if (platform_data) {
1459 for (i = 0; i < platform_data->num_regulators; i++) {
1460 id = platform_data->init_data[i].id;
1461 if (config->is_real_id(id)) {
1462 regulator_unregister(config->vregs[id].rdev);
1463 config->vregs[id].rdev = NULL;
1464 } else {
1465 regulator_unregister(config->vregs[
1466 config->pc_id_to_real_id(id)].rdev_pc);
1467 config->vregs[id].rdev_pc = NULL;
1468 }
1469 }
1470 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471
1472 return 0;
1473}
1474
1475static struct platform_driver rpm_vreg_driver = {
1476 .probe = rpm_vreg_probe,
1477 .remove = __devexit_p(rpm_vreg_remove),
1478 .driver = {
David Collins6f032ba2011-08-31 14:08:15 -07001479 .name = RPM_REGULATOR_DEV_NAME,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 .owner = THIS_MODULE,
1481 },
1482};
1483
1484static int __init rpm_vreg_init(void)
1485{
1486 return platform_driver_register(&rpm_vreg_driver);
1487}
1488
1489static void __exit rpm_vreg_exit(void)
1490{
David Collins6f032ba2011-08-31 14:08:15 -07001491 int i;
1492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 platform_driver_unregister(&rpm_vreg_driver);
David Collins6f032ba2011-08-31 14:08:15 -07001494
1495 for (i = 0; i < config->vregs_len; i++)
1496 mutex_destroy(&config->vregs[i].pc_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497}
1498
1499postcore_initcall(rpm_vreg_init);
1500module_exit(rpm_vreg_exit);
1501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502MODULE_LICENSE("GPL v2");
David Collins6f032ba2011-08-31 14:08:15 -07001503MODULE_DESCRIPTION("MSM RPM regulator driver");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504MODULE_VERSION("1.0");
David Collins6f032ba2011-08-31 14:08:15 -07001505MODULE_ALIAS("platform:" RPM_REGULATOR_DEV_NAME);