blob: e137b0ff3f92686f5b24f5014189f12d8eaa93bd [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/err.h>
14#include <linux/string.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/bitops.h>
18#include <linux/mfd/pmic8058.h>
19#include <linux/regulator/driver.h>
20#include <linux/regulator/machine.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053021#include <linux/mfd/pm8xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/regulator/pmic8058-regulator.h>
23
24/* Regulator types */
25#define REGULATOR_TYPE_LDO 0
26#define REGULATOR_TYPE_SMPS 1
27#define REGULATOR_TYPE_LVS 2
28#define REGULATOR_TYPE_NCP 3
29
30/* Common masks */
31#define REGULATOR_EN_MASK 0x80
32
33#define REGULATOR_BANK_MASK 0xF0
34#define REGULATOR_BANK_SEL(n) ((n) << 4)
35#define REGULATOR_BANK_WRITE 0x80
36
37#define LDO_TEST_BANKS 7
38#define SMPS_TEST_BANKS 8
39#define REGULATOR_TEST_BANKS_MAX SMPS_TEST_BANKS
40
41/* LDO programming */
42
43/* CTRL register */
44#define LDO_ENABLE_MASK 0x80
45#define LDO_ENABLE 0x80
46#define LDO_PULL_DOWN_ENABLE_MASK 0x40
47#define LDO_PULL_DOWN_ENABLE 0x40
48
49#define LDO_CTRL_PM_MASK 0x20
50#define LDO_CTRL_PM_HPM 0x00
51#define LDO_CTRL_PM_LPM 0x20
52
53#define LDO_CTRL_VPROG_MASK 0x1F
54
55/* TEST register bank 0 */
56#define LDO_TEST_LPM_MASK 0x40
57#define LDO_TEST_LPM_SEL_CTRL 0x00
58#define LDO_TEST_LPM_SEL_TCXO 0x40
59
60/* TEST register bank 2 */
61#define LDO_TEST_VPROG_UPDATE_MASK 0x08
62#define LDO_TEST_RANGE_SEL_MASK 0x04
63#define LDO_TEST_FINE_STEP_MASK 0x02
64#define LDO_TEST_FINE_STEP_SHIFT 1
65
66/* TEST register bank 4 */
67#define LDO_TEST_RANGE_EXT_MASK 0x01
68
69/* TEST register bank 5 */
70#define LDO_TEST_PIN_CTRL_MASK 0x0F
71#define LDO_TEST_PIN_CTRL_EN3 0x08
72#define LDO_TEST_PIN_CTRL_EN2 0x04
73#define LDO_TEST_PIN_CTRL_EN1 0x02
74#define LDO_TEST_PIN_CTRL_EN0 0x01
75
76/* TEST register bank 6 */
77#define LDO_TEST_PIN_CTRL_LPM_MASK 0x0F
78
79/* Allowable voltage ranges */
80#define PLDO_LOW_UV_MIN 750000
81#define PLDO_LOW_UV_MAX 1537500
82#define PLDO_LOW_FINE_STEP_UV 12500
83
84#define PLDO_NORM_UV_MIN 1500000
85#define PLDO_NORM_UV_MAX 3075000
86#define PLDO_NORM_FINE_STEP_UV 25000
87
88#define PLDO_HIGH_UV_MIN 1750000
89#define PLDO_HIGH_UV_MAX 4900000
90#define PLDO_HIGH_FINE_STEP_UV 50000
91
92#define NLDO_UV_MIN 750000
93#define NLDO_UV_MAX 1537500
94#define NLDO_FINE_STEP_UV 12500
95
96/* SMPS masks and values */
97
98/* CTRL register */
99
100/* Legacy mode */
101#define SMPS_LEGACY_ENABLE 0x80
102#define SMPS_LEGACY_PULL_DOWN_ENABLE 0x40
103#define SMPS_LEGACY_VREF_SEL_MASK 0x20
104#define SMPS_LEGACY_VPROG_MASK 0x1F
105
106/* Advanced mode */
107#define SMPS_ADVANCED_BAND_MASK 0xC0
108#define SMPS_ADVANCED_BAND_OFF 0x00
109#define SMPS_ADVANCED_BAND_1 0x40
110#define SMPS_ADVANCED_BAND_2 0x80
111#define SMPS_ADVANCED_BAND_3 0xC0
112#define SMPS_ADVANCED_VPROG_MASK 0x3F
113
114/* Legacy mode voltage ranges */
115#define SMPS_MODE1_UV_MIN 1500000
116#define SMPS_MODE1_UV_MAX 3050000
117#define SMPS_MODE1_UV_STEP 50000
118
119#define SMPS_MODE2_UV_MIN 750000
120#define SMPS_MODE2_UV_MAX 1525000
121#define SMPS_MODE2_UV_STEP 25000
122
123#define SMPS_MODE3_UV_MIN 375000
124#define SMPS_MODE3_UV_MAX 1150000
125#define SMPS_MODE3_UV_STEP 25000
126
127/* Advanced mode voltage ranges */
128#define SMPS_BAND3_UV_MIN 1500000
129#define SMPS_BAND3_UV_MAX 3075000
130#define SMPS_BAND3_UV_STEP 25000
131
132#define SMPS_BAND2_UV_MIN 750000
133#define SMPS_BAND2_UV_MAX 1537500
134#define SMPS_BAND2_UV_STEP 12500
135
136#define SMPS_BAND1_UV_MIN 375000
137#define SMPS_BAND1_UV_MAX 1162500
138#define SMPS_BAND1_UV_STEP 12500
139
140#define SMPS_UV_MIN SMPS_MODE3_UV_MIN
141#define SMPS_UV_MAX SMPS_MODE1_UV_MAX
142
143/* Test2 register bank 1 */
144#define SMPS_LEGACY_VLOW_SEL_MASK 0x01
145
146/* Test2 register bank 6 */
147#define SMPS_ADVANCED_PULL_DOWN_ENABLE 0x08
148
149/* Test2 register bank 7 */
150#define SMPS_ADVANCED_MODE_MASK 0x02
151#define SMPS_ADVANCED_MODE 0x02
152#define SMPS_LEGACY_MODE 0x00
153
154#define SMPS_IN_ADVANCED_MODE(vreg) \
155 ((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
156
157/* BUCK_SLEEP_CNTRL register */
158#define SMPS_PIN_CTRL_MASK 0xF0
159#define SMPS_PIN_CTRL_A1 0x80
160#define SMPS_PIN_CTRL_A0 0x40
161#define SMPS_PIN_CTRL_D1 0x20
162#define SMPS_PIN_CTRL_D0 0x10
163
164#define SMPS_PIN_CTRL_LPM_MASK 0x0F
165#define SMPS_PIN_CTRL_LPM_A1 0x08
166#define SMPS_PIN_CTRL_LPM_A0 0x04
167#define SMPS_PIN_CTRL_LPM_D1 0x02
168#define SMPS_PIN_CTRL_LPM_D0 0x01
169
170/* BUCK_CLOCK_CNTRL register */
171#define SMPS_CLK_DIVIDE2 0x40
172
173#define SMPS_CLK_CTRL_MASK 0x30
174#define SMPS_CLK_CTRL_FOLLOW_TCXO 0x00
175#define SMPS_CLK_CTRL_PWM 0x10
176#define SMPS_CLK_CTRL_PFM 0x20
177
178/* LVS masks and values */
179
180/* CTRL register */
181#define LVS_ENABLE_MASK 0x80
182#define LVS_ENABLE 0x80
183#define LVS_PULL_DOWN_ENABLE_MASK 0x40
184#define LVS_PULL_DOWN_ENABLE 0x00
185#define LVS_PULL_DOWN_DISABLE 0x40
186
187#define LVS_PIN_CTRL_MASK 0x0F
188#define LVS_PIN_CTRL_EN0 0x08
189#define LVS_PIN_CTRL_EN1 0x04
190#define LVS_PIN_CTRL_EN2 0x02
191#define LVS_PIN_CTRL_EN3 0x01
192
193/* NCP masks and values */
194
195/* CTRL register */
196#define NCP_VPROG_MASK 0x1F
197
198#define NCP_UV_MIN 1500000
199#define NCP_UV_MAX 3050000
200#define NCP_UV_STEP 50000
201
202#define GLOBAL_ENABLE_MAX (2)
203struct pm8058_enable {
204 u16 addr;
205 u8 reg;
206};
207
208struct pm8058_vreg {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530209 struct device *dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210 struct pm8058_vreg_pdata *pdata;
211 struct regulator_dev *rdev;
212 struct pm8058_enable *global_enable[GLOBAL_ENABLE_MAX];
213 int hpm_min_load;
214 int save_uV;
215 unsigned pc_vote;
216 unsigned optimum;
217 unsigned mode_initialized;
218 u16 ctrl_addr;
219 u16 test_addr;
220 u16 clk_ctrl_addr;
221 u16 sleep_ctrl_addr;
222 u8 type;
223 u8 ctrl_reg;
224 u8 test_reg[REGULATOR_TEST_BANKS_MAX];
225 u8 clk_ctrl_reg;
226 u8 sleep_ctrl_reg;
227 u8 is_nmos;
228 u8 global_enable_mask[GLOBAL_ENABLE_MAX];
229};
230
231#define LDO_M2(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
232 _en0, _en0_mask, _en1, _en1_mask) \
233 [PM8058_VREG_ID_##_id] = { \
234 .ctrl_addr = _ctrl_addr, \
235 .test_addr = _test_addr, \
236 .type = REGULATOR_TYPE_LDO, \
237 .hpm_min_load = PM8058_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
238 .is_nmos = _is_nmos, \
239 .global_enable = { \
240 [0] = _en0, \
241 [1] = _en1, \
242 }, \
243 .global_enable_mask = { \
244 [0] = _en0_mask, \
245 [1] = _en1_mask, \
246 }, \
247 }
248
249#define LDO(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
250 _en0, _en0_mask) \
251 LDO_M2(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
252 _en0, _en0_mask, NULL, 0)
253
254#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
255 _hpm_min_load, _en0, _en0_mask) \
256 [PM8058_VREG_ID_##_id] = { \
257 .ctrl_addr = _ctrl_addr, \
258 .test_addr = _test_addr, \
259 .clk_ctrl_addr = _clk_ctrl_addr, \
260 .sleep_ctrl_addr = _sleep_ctrl_addr, \
261 .type = REGULATOR_TYPE_SMPS, \
262 .hpm_min_load = PM8058_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
263 .global_enable = { \
264 [0] = _en0, \
265 [1] = NULL, \
266 }, \
267 .global_enable_mask = { \
268 [0] = _en0_mask, \
269 [1] = 0, \
270 }, \
271 }
272
273#define LVS(_id, _ctrl_addr, _en0, _en0_mask) \
274 [PM8058_VREG_ID_##_id] = { \
275 .ctrl_addr = _ctrl_addr, \
276 .type = REGULATOR_TYPE_LVS, \
277 .global_enable = { \
278 [0] = _en0, \
279 [1] = NULL, \
280 }, \
281 .global_enable_mask = { \
282 [0] = _en0_mask, \
283 [1] = 0, \
284 }, \
285 }
286
287#define NCP(_id, _ctrl_addr, _test1) \
288 [PM8058_VREG_ID_##_id] = { \
289 .ctrl_addr = _ctrl_addr, \
290 .type = REGULATOR_TYPE_NCP, \
291 .test_addr = _test1, \
292 .global_enable = { \
293 [0] = NULL, \
294 [1] = NULL, \
295 }, \
296 .global_enable_mask = { \
297 [0] = 0, \
298 [1] = 0, \
299 }, \
300 }
301
302#define MASTER_ENABLE_COUNT 6
303
304#define EN_MSM 0
305#define EN_PH 1
306#define EN_RF 2
307#define EN_GRP_5_4 3
308#define EN_GRP_3_2 4
309#define EN_GRP_1_0 5
310
311/* Master regulator control registers */
312static struct pm8058_enable m_en[MASTER_ENABLE_COUNT] = {
313 [EN_MSM] = {
314 .addr = 0x018, /* VREG_EN_MSM */
315 },
316 [EN_PH] = {
317 .addr = 0x019, /* VREG_EN_PH */
318 },
319 [EN_RF] = {
320 .addr = 0x01A, /* VREG_EN_RF */
321 },
322 [EN_GRP_5_4] = {
323 .addr = 0x1C8, /* VREG_EN_MSM_GRP_5-4 */
324 },
325 [EN_GRP_3_2] = {
326 .addr = 0x1C9, /* VREG_EN_MSM_GRP_3-2 */
327 },
328 [EN_GRP_1_0] = {
329 .addr = 0x1CA, /* VREG_EN_MSM_GRP_1-0 */
330 },
331};
332
333
334static struct pm8058_vreg pm8058_vreg[] = {
335 /* id ctrl test n/p hpm_min m_en m_en_mask */
336 LDO(L0, 0x009, 0x065, 1, LDO_150, &m_en[EN_GRP_5_4], BIT(3)),
337 LDO(L1, 0x00A, 0x066, 1, LDO_300, &m_en[EN_GRP_5_4], BIT(6) | BIT(2)),
338 LDO(L2, 0x00B, 0x067, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(2)),
339 LDO(L3, 0x00C, 0x068, 0, LDO_150, &m_en[EN_GRP_1_0], BIT(1)),
340 LDO(L4, 0x00D, 0x069, 0, LDO_50, &m_en[EN_MSM], 0),
341 LDO(L5, 0x00E, 0x06A, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(7)),
342 LDO(L6, 0x00F, 0x06B, 0, LDO_50, &m_en[EN_GRP_1_0], BIT(2)),
343 LDO(L7, 0x010, 0x06C, 0, LDO_50, &m_en[EN_GRP_3_2], BIT(3)),
344 LDO(L8, 0x011, 0x06D, 0, LDO_300, &m_en[EN_PH], BIT(7)),
345 LDO(L9, 0x012, 0x06E, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(3)),
346 LDO(L10, 0x013, 0x06F, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(4)),
347 LDO(L11, 0x014, 0x070, 0, LDO_150, &m_en[EN_PH], BIT(4)),
348 LDO(L12, 0x015, 0x071, 0, LDO_150, &m_en[EN_PH], BIT(3)),
349 LDO(L13, 0x016, 0x072, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(1)),
350 LDO(L14, 0x017, 0x073, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(5)),
351 LDO(L15, 0x089, 0x0E5, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(4)),
352 LDO(L16, 0x08A, 0x0E6, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(0)),
353 LDO(L17, 0x08B, 0x0E7, 0, LDO_150, &m_en[EN_RF], BIT(7)),
354 LDO(L18, 0x11D, 0x125, 0, LDO_150, &m_en[EN_RF], BIT(6)),
355 LDO(L19, 0x11E, 0x126, 0, LDO_150, &m_en[EN_RF], BIT(5)),
356 LDO(L20, 0x11F, 0x127, 0, LDO_150, &m_en[EN_RF], BIT(4)),
357 LDO_M2(L21, 0x120, 0x128, 1, LDO_150, &m_en[EN_GRP_5_4], BIT(1),
358 &m_en[EN_GRP_1_0], BIT(6)),
359 LDO(L22, 0x121, 0x129, 1, LDO_300, &m_en[EN_GRP_3_2], BIT(7)),
360 LDO(L23, 0x122, 0x12A, 1, LDO_300, &m_en[EN_GRP_5_4], BIT(0)),
361 LDO(L24, 0x123, 0x12B, 1, LDO_150, &m_en[EN_RF], BIT(3)),
362 LDO(L25, 0x124, 0x12C, 1, LDO_150, &m_en[EN_RF], BIT(2)),
363
364 /* id ctrl test2 clk sleep hpm_min m_en m_en_mask */
365 SMPS(S0, 0x004, 0x084, 0x1D1, 0x1D8, SMPS, &m_en[EN_MSM], BIT(7)),
366 SMPS(S1, 0x005, 0x085, 0x1D2, 0x1DB, SMPS, &m_en[EN_MSM], BIT(6)),
367 SMPS(S2, 0x110, 0x119, 0x1D3, 0x1DE, SMPS, &m_en[EN_GRP_5_4], BIT(5)),
368 SMPS(S3, 0x111, 0x11A, 0x1D4, 0x1E1, SMPS, &m_en[EN_GRP_5_4],
369 BIT(7) | BIT(4)),
370 SMPS(S4, 0x112, 0x11B, 0x1D5, 0x1E4, SMPS, &m_en[EN_GRP_3_2], BIT(5)),
371
372 /* id ctrl m_en m_en_mask */
373 LVS(LVS0, 0x12D, &m_en[EN_RF], BIT(1)),
374 LVS(LVS1, 0x12F, &m_en[EN_GRP_1_0], BIT(0)),
375
376 /* id ctrl test1 */
377 NCP(NCP, 0x090, 0x0EC),
378};
379
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530380static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg, int uV,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 int force_on);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530382static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383static int _pm8058_vreg_is_enabled(struct pm8058_vreg *vreg);
384
385static unsigned int pm8058_vreg_get_mode(struct regulator_dev *dev);
386
387static void print_write_error(struct pm8058_vreg *vreg, int rc,
388 const char *func);
389
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530390static int pm8058_vreg_write(struct pm8058_vreg *vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 u16 addr, u8 val, u8 mask, u8 *reg_save)
392{
393 int rc = 0;
394 u8 reg;
395
396 reg = (*reg_save & ~mask) | (val & mask);
397 if (reg != *reg_save)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530398 rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530400 pr_err("%s: pm8xxx_write failed, rc=%d\n", __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 else
402 *reg_save = reg;
403 return rc;
404}
405
406static int pm8058_vreg_is_global_enabled(struct pm8058_vreg *vreg)
407{
408 int ret = 0, i;
409
410 for (i = 0;
411 (i < GLOBAL_ENABLE_MAX) && !ret && vreg->global_enable[i]; i++)
412 ret = vreg->global_enable[i]->reg &
413 vreg->global_enable_mask[i];
414
415 return ret;
416}
417
418
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530419static int pm8058_vreg_set_global_enable(struct pm8058_vreg *vreg, int on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420{
421 int rc = 0, i;
422
423 for (i = 0;
424 (i < GLOBAL_ENABLE_MAX) && !rc && vreg->global_enable[i]; i++)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530425 rc = pm8058_vreg_write(vreg, vreg->global_enable[i]->addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 (on ? vreg->global_enable_mask[i] : 0),
427 vreg->global_enable_mask[i],
428 &vreg->global_enable[i]->reg);
429
430 return rc;
431}
432
433static int pm8058_vreg_using_pin_ctrl(struct pm8058_vreg *vreg)
434{
435 int ret = 0;
436
437 switch (vreg->type) {
438 case REGULATOR_TYPE_LDO:
439 ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
440 | (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
441 break;
442 case REGULATOR_TYPE_SMPS:
443 ret = vreg->sleep_ctrl_reg
444 & (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
445 break;
446 case REGULATOR_TYPE_LVS:
447 ret = vreg->ctrl_reg & LVS_PIN_CTRL_MASK;
448 break;
449 }
450
451 return ret;
452}
453
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530454static int pm8058_vreg_set_pin_ctrl(struct pm8058_vreg *vreg, int on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455{
456 int rc = 0, bank;
457 u8 val = 0, mask;
458 unsigned pc = vreg->pdata->pin_ctrl;
459 unsigned pf = vreg->pdata->pin_fn;
460
461 switch (vreg->type) {
462 case REGULATOR_TYPE_LDO:
463 if (on) {
464 if (pc & PM8058_VREG_PIN_CTRL_D0)
465 val |= LDO_TEST_PIN_CTRL_EN0;
466 if (pc & PM8058_VREG_PIN_CTRL_D1)
467 val |= LDO_TEST_PIN_CTRL_EN1;
468 if (pc & PM8058_VREG_PIN_CTRL_A0)
469 val |= LDO_TEST_PIN_CTRL_EN2;
470 if (pc & PM8058_VREG_PIN_CTRL_A1)
471 val |= LDO_TEST_PIN_CTRL_EN3;
472
473 bank = (pf == PM8058_VREG_PIN_FN_ENABLE ? 5 : 6);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530474 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475 val | REGULATOR_BANK_SEL(bank)
476 | REGULATOR_BANK_WRITE,
477 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
478 &vreg->test_reg[bank]);
479 if (rc)
480 goto bail;
481
482 val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
483 | REGULATOR_BANK_SEL(0);
484 mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530485 rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 &vreg->test_reg[0]);
487 if (rc)
488 goto bail;
489
490 if (pf == PM8058_VREG_PIN_FN_ENABLE) {
491 /* Pin control ON/OFF */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530492 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493 LDO_CTRL_PM_HPM,
494 LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
495 &vreg->ctrl_reg);
496 if (rc)
497 goto bail;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530498 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 if (rc)
500 goto bail;
501 } else {
502 /* Pin control LPM/HPM */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530503 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 LDO_ENABLE | LDO_CTRL_PM_LPM,
505 LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
506 &vreg->ctrl_reg);
507 if (rc)
508 goto bail;
509 }
510 } else {
511 /* Pin control off */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530512 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
514 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
515 &vreg->test_reg[5]);
516 if (rc)
517 goto bail;
518
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530519 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520 REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
521 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
522 &vreg->test_reg[6]);
523 if (rc)
524 goto bail;
525 }
526 break;
527
528 case REGULATOR_TYPE_SMPS:
529 if (on) {
530 if (pf == PM8058_VREG_PIN_FN_ENABLE) {
531 /* Pin control ON/OFF */
532 if (pc & PM8058_VREG_PIN_CTRL_D0)
533 val |= SMPS_PIN_CTRL_D0;
534 if (pc & PM8058_VREG_PIN_CTRL_D1)
535 val |= SMPS_PIN_CTRL_D1;
536 if (pc & PM8058_VREG_PIN_CTRL_A0)
537 val |= SMPS_PIN_CTRL_A0;
538 if (pc & PM8058_VREG_PIN_CTRL_A1)
539 val |= SMPS_PIN_CTRL_A1;
540 } else {
541 /* Pin control LPM/HPM */
542 if (pc & PM8058_VREG_PIN_CTRL_D0)
543 val |= SMPS_PIN_CTRL_LPM_D0;
544 if (pc & PM8058_VREG_PIN_CTRL_D1)
545 val |= SMPS_PIN_CTRL_LPM_D1;
546 if (pc & PM8058_VREG_PIN_CTRL_A0)
547 val |= SMPS_PIN_CTRL_LPM_A0;
548 if (pc & PM8058_VREG_PIN_CTRL_A1)
549 val |= SMPS_PIN_CTRL_LPM_A1;
550 }
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530551 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552 if (rc)
553 goto bail;
554
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530555 rc = pm8058_smps_set_voltage_legacy(vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556 vreg->save_uV);
557 if (rc)
558 goto bail;
559
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530560 rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
562 &vreg->sleep_ctrl_reg);
563 if (rc)
564 goto bail;
565
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530566 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567 (pf == PM8058_VREG_PIN_FN_ENABLE
568 ? 0 : SMPS_LEGACY_ENABLE),
569 SMPS_LEGACY_ENABLE, &vreg->ctrl_reg);
570 if (rc)
571 goto bail;
572
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530573 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 (pf == PM8058_VREG_PIN_FN_ENABLE
575 ? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
576 SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
577 if (rc)
578 goto bail;
579 } else {
580 /* Pin control off */
581 if (!SMPS_IN_ADVANCED_MODE(vreg)) {
582 if (_pm8058_vreg_is_enabled(vreg))
583 val = SMPS_LEGACY_ENABLE;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530584 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 val, SMPS_LEGACY_ENABLE,
586 &vreg->ctrl_reg);
587 if (rc)
588 goto bail;
589 }
590
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530591 rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
593 &vreg->sleep_ctrl_reg);
594 if (rc)
595 goto bail;
596
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530597 rc = pm8058_smps_set_voltage_advanced(vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 vreg->save_uV, 0);
599 if (rc)
600 goto bail;
601 }
602 break;
603
604 case REGULATOR_TYPE_LVS:
605 if (on) {
606 if (pc & PM8058_VREG_PIN_CTRL_D0)
607 val |= LVS_PIN_CTRL_EN0;
608 if (pc & PM8058_VREG_PIN_CTRL_D1)
609 val |= LVS_PIN_CTRL_EN1;
610 if (pc & PM8058_VREG_PIN_CTRL_A0)
611 val |= LVS_PIN_CTRL_EN2;
612 if (pc & PM8058_VREG_PIN_CTRL_A1)
613 val |= LVS_PIN_CTRL_EN3;
614
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530615 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 LVS_PIN_CTRL_MASK | LVS_ENABLE_MASK,
617 &vreg->ctrl_reg);
618 if (rc)
619 goto bail;
620
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530621 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 if (rc)
623 goto bail;
624 } else {
625 /* Pin control off */
626 if (_pm8058_vreg_is_enabled(vreg))
627 val = LVS_ENABLE;
628
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530629 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 LVS_ENABLE_MASK | LVS_PIN_CTRL_MASK,
631 &vreg->ctrl_reg);
632 if (rc)
633 goto bail;
634
635 }
636 break;
637 }
638
639bail:
640 if (rc)
641 print_write_error(vreg, rc, __func__);
642
643 return rc;
644}
645
646static int pm8058_vreg_enable(struct regulator_dev *dev)
647{
648 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 int mode;
650 int rc = 0;
651
652 mode = pm8058_vreg_get_mode(dev);
653
654 if (mode == REGULATOR_MODE_IDLE) {
655 /* Turn on pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530656 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 if (rc)
658 goto bail;
659 return rc;
660 }
661 if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530662 rc = pm8058_smps_set_voltage_advanced(vreg, vreg->save_uV, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530664 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, REGULATOR_EN_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 REGULATOR_EN_MASK, &vreg->ctrl_reg);
666bail:
667 if (rc)
668 print_write_error(vreg, rc, __func__);
669
670 return rc;
671}
672
673static int _pm8058_vreg_is_enabled(struct pm8058_vreg *vreg)
674{
675 /*
676 * All regulator types except advanced mode SMPS have enable bit in
677 * bit 7 of the control register. Global enable and pin control also
678 * do not work for advanced mode SMPS.
679 */
680 if (!(vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
681 && ((vreg->ctrl_reg & REGULATOR_EN_MASK)
682 || pm8058_vreg_is_global_enabled(vreg)
683 || pm8058_vreg_using_pin_ctrl(vreg)))
684 return 1;
685 else if (vreg->type == REGULATOR_TYPE_SMPS
686 && SMPS_IN_ADVANCED_MODE(vreg)
687 && ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
688 != SMPS_ADVANCED_BAND_OFF))
689 return 1;
690
691 return 0;
692}
693
694static int pm8058_vreg_is_enabled(struct regulator_dev *dev)
695{
696 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
697
698 return _pm8058_vreg_is_enabled(vreg);
699}
700
701static int pm8058_vreg_disable(struct regulator_dev *dev)
702{
703 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 int rc = 0;
705
706 /* Disable in global control register. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530707 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 if (rc)
709 goto bail;
710
711 /* Turn off pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530712 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 if (rc)
714 goto bail;
715
716 /* Disable in local control register. */
717 if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530718 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 SMPS_ADVANCED_BAND_OFF, SMPS_ADVANCED_BAND_MASK,
720 &vreg->ctrl_reg);
721 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530722 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 REGULATOR_EN_MASK, &vreg->ctrl_reg);
724
725bail:
726 if (rc)
727 print_write_error(vreg, rc, __func__);
728
729 return rc;
730}
731
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530732static int pm8058_pldo_set_voltage(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733{
734 int vmin, rc = 0;
735 unsigned vprog, fine_step;
736 u8 range_ext, range_sel, fine_step_reg;
737
738 if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX)
739 return -EINVAL;
740
741 if (uV < PLDO_LOW_UV_MAX + PLDO_LOW_FINE_STEP_UV) {
742 vmin = PLDO_LOW_UV_MIN;
743 fine_step = PLDO_LOW_FINE_STEP_UV;
744 range_ext = 0;
745 range_sel = LDO_TEST_RANGE_SEL_MASK;
746 } else if (uV < PLDO_NORM_UV_MAX + PLDO_NORM_FINE_STEP_UV) {
747 vmin = PLDO_NORM_UV_MIN;
748 fine_step = PLDO_NORM_FINE_STEP_UV;
749 range_ext = 0;
750 range_sel = 0;
751 } else {
752 vmin = PLDO_HIGH_UV_MIN;
753 fine_step = PLDO_HIGH_FINE_STEP_UV;
754 range_ext = LDO_TEST_RANGE_EXT_MASK;
755 range_sel = 0;
756 }
757
758 vprog = (uV - vmin) / fine_step;
759 fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
760 vprog >>= 1;
761
762 /*
763 * Disable program voltage update if range extension, range select,
764 * or fine step have changed and the regulator is enabled.
765 */
766 if (_pm8058_vreg_is_enabled(vreg) &&
767 (((range_ext ^ vreg->test_reg[4]) & LDO_TEST_RANGE_EXT_MASK)
768 || ((range_sel ^ vreg->test_reg[2]) & LDO_TEST_RANGE_SEL_MASK)
769 || ((fine_step_reg ^ vreg->test_reg[2])
770 & LDO_TEST_FINE_STEP_MASK))) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530771 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 REGULATOR_BANK_SEL(2) | REGULATOR_BANK_WRITE,
773 REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
774 &vreg->test_reg[2]);
775 if (rc)
776 goto bail;
777 }
778
779 /* Write new voltage. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530780 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
782 if (rc)
783 goto bail;
784
785 /* Write range extension. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530786 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 range_ext | REGULATOR_BANK_SEL(4)
788 | REGULATOR_BANK_WRITE,
789 LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
790 &vreg->test_reg[4]);
791 if (rc)
792 goto bail;
793
794 /* Write fine step, range select and program voltage update. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530795 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
797 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
798 LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
799 | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
800 &vreg->test_reg[2]);
801bail:
802 if (rc)
803 print_write_error(vreg, rc, __func__);
804
805 return rc;
806}
807
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530808static int pm8058_nldo_set_voltage(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809{
810 unsigned vprog, fine_step_reg;
811 int rc;
812
813 if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX)
814 return -EINVAL;
815
816 vprog = (uV - NLDO_UV_MIN) / NLDO_FINE_STEP_UV;
817 fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
818 vprog >>= 1;
819
820 /* Write new voltage. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530821 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
823 if (rc)
824 goto bail;
825
826 /* Write fine step. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530827 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 fine_step_reg | REGULATOR_BANK_SEL(2)
829 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
830 LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
831 | LDO_TEST_VPROG_UPDATE_MASK,
832 &vreg->test_reg[2]);
833bail:
834 if (rc)
835 print_write_error(vreg, rc, __func__);
836
837 return rc;
838}
839
840static int pm8058_ldo_set_voltage(struct regulator_dev *dev,
841 int min_uV, int max_uV, unsigned *selector)
842{
843 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844
845 if (vreg->is_nmos)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530846 return pm8058_nldo_set_voltage(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530848 return pm8058_pldo_set_voltage(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849}
850
851static int pm8058_pldo_get_voltage(struct pm8058_vreg *vreg)
852{
853 int vmin, fine_step;
854 u8 range_ext, range_sel, vprog, fine_step_reg;
855
856 fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
857 range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
858 range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
859 vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
860
861 vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
862
863 if (range_sel) {
864 /* low range mode */
865 fine_step = PLDO_LOW_FINE_STEP_UV;
866 vmin = PLDO_LOW_UV_MIN;
867 } else if (!range_ext) {
868 /* normal mode */
869 fine_step = PLDO_NORM_FINE_STEP_UV;
870 vmin = PLDO_NORM_UV_MIN;
871 } else {
872 /* high range mode */
873 fine_step = PLDO_HIGH_FINE_STEP_UV;
874 vmin = PLDO_HIGH_UV_MIN;
875 }
876
877 return fine_step * vprog + vmin;
878}
879
880static int pm8058_nldo_get_voltage(struct pm8058_vreg *vreg)
881{
882 u8 vprog, fine_step_reg;
883
884 fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
885 vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
886
887 vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
888
889 return NLDO_FINE_STEP_UV * vprog + NLDO_UV_MIN;
890}
891
892static int pm8058_ldo_get_voltage(struct regulator_dev *dev)
893{
894 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
895
896 if (vreg->is_nmos)
897 return pm8058_nldo_get_voltage(vreg);
898 else
899 return pm8058_pldo_get_voltage(vreg);
900}
901
902static int pm8058_smps_get_voltage_advanced(struct pm8058_vreg *vreg)
903{
904 u8 vprog, band;
905 int uV = 0;
906
907 vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
908 band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
909
910 if (band == SMPS_ADVANCED_BAND_1)
911 uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
912 else if (band == SMPS_ADVANCED_BAND_2)
913 uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
914 else if (band == SMPS_ADVANCED_BAND_3)
915 uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
916 else
917 uV = vreg->save_uV;
918
919 return uV;
920}
921
922static int pm8058_smps_get_voltage_legacy(struct pm8058_vreg *vreg)
923{
924 u8 vlow, vref, vprog;
925 int uV;
926
927 vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
928 vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
929 vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
930
931 if (vlow && vref) {
932 /* mode 3 */
933 uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
934 } else if (vref) {
935 /* mode 2 */
936 uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
937 } else {
938 /* mode 1 */
939 uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
940 }
941
942 return uV;
943}
944
945static int _pm8058_smps_get_voltage(struct pm8058_vreg *vreg)
946{
947 if (SMPS_IN_ADVANCED_MODE(vreg))
948 return pm8058_smps_get_voltage_advanced(vreg);
949
950 return pm8058_smps_get_voltage_legacy(vreg);
951}
952
953static int pm8058_smps_get_voltage(struct regulator_dev *dev)
954{
955 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
956
957 return _pm8058_smps_get_voltage(vreg);
958}
959
960static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg,
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530961 int uV, int force_on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962{
963 u8 vprog, band;
964 int rc, new_uV;
965
966 if (uV < SMPS_BAND1_UV_MAX + SMPS_BAND1_UV_STEP) {
967 vprog = ((uV - SMPS_BAND1_UV_MIN) / SMPS_BAND1_UV_STEP);
968 band = SMPS_ADVANCED_BAND_1;
969 new_uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
970 } else if (uV < SMPS_BAND2_UV_MAX + SMPS_BAND2_UV_STEP) {
971 vprog = ((uV - SMPS_BAND2_UV_MIN) / SMPS_BAND2_UV_STEP);
972 band = SMPS_ADVANCED_BAND_2;
973 new_uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
974 } else {
975 vprog = ((uV - SMPS_BAND3_UV_MIN) / SMPS_BAND3_UV_STEP);
976 band = SMPS_ADVANCED_BAND_3;
977 new_uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
978 }
979
980 /* Do not set band if regulator currently disabled. */
981 if (!_pm8058_vreg_is_enabled(vreg) && !force_on)
982 band = SMPS_ADVANCED_BAND_OFF;
983
984 /* Set advanced mode bit to 1. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530985 rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
987 SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
988 &vreg->test_reg[7]);
989 if (rc)
990 goto bail;
991
992 /* Set voltage and voltage band. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530993 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, band | vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
995 &vreg->ctrl_reg);
996 if (rc)
997 goto bail;
998
999 vreg->save_uV = new_uV;
1000
1001bail:
1002 return rc;
1003}
1004
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301005static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006{
1007 u8 vlow, vref, vprog, pd, en;
1008 int rc;
1009
1010 if (uV < SMPS_MODE3_UV_MAX + SMPS_MODE3_UV_STEP) {
1011 vprog = ((uV - SMPS_MODE3_UV_MIN) / SMPS_MODE3_UV_STEP);
1012 vref = SMPS_LEGACY_VREF_SEL_MASK;
1013 vlow = SMPS_LEGACY_VLOW_SEL_MASK;
1014 } else if (uV < SMPS_MODE2_UV_MAX + SMPS_MODE2_UV_STEP) {
1015 vprog = ((uV - SMPS_MODE2_UV_MIN) / SMPS_MODE2_UV_STEP);
1016 vref = SMPS_LEGACY_VREF_SEL_MASK;
1017 vlow = 0;
1018 } else {
1019 vprog = ((uV - SMPS_MODE1_UV_MIN) / SMPS_MODE1_UV_STEP);
1020 vref = 0;
1021 vlow = 0;
1022 }
1023
1024 /* set vlow bit for ultra low voltage mode */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301025 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
1027 REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
1028 &vreg->test_reg[1]);
1029 if (rc)
1030 goto bail;
1031
1032 /* Set advanced mode bit to 0. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301033 rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
1035 SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
1036 &vreg->test_reg[7]);
1037 if (rc)
1038 goto bail;
1039
1040 en = (_pm8058_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
1041 pd = (vreg->pdata->pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
1042
1043 /* Set voltage (and the rest of the control register). */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301044 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, en | pd | vref | vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 SMPS_LEGACY_ENABLE | SMPS_LEGACY_PULL_DOWN_ENABLE
1046 | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
1047 &vreg->ctrl_reg);
1048
1049 vreg->save_uV = pm8058_smps_get_voltage_legacy(vreg);
1050
1051bail:
1052 return rc;
1053}
1054
1055static int pm8058_smps_set_voltage(struct regulator_dev *dev,
1056 int min_uV, int max_uV, unsigned *selector)
1057{
1058 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 int rc = 0;
1060
1061 if (min_uV < SMPS_UV_MIN || min_uV > SMPS_UV_MAX)
1062 return -EINVAL;
1063
1064 if (SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301065 rc = pm8058_smps_set_voltage_advanced(vreg, min_uV, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301067 rc = pm8058_smps_set_voltage_legacy(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068
1069 if (rc)
1070 print_write_error(vreg, rc, __func__);
1071
1072 return rc;
1073}
1074
1075static int pm8058_ncp_set_voltage(struct regulator_dev *dev,
1076 int min_uV, int max_uV, unsigned *selector)
1077{
1078 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 int rc;
1080 u8 val;
1081
1082 if (min_uV < NCP_UV_MIN || min_uV > NCP_UV_MAX)
1083 return -EINVAL;
1084
1085 val = (min_uV - NCP_UV_MIN) / NCP_UV_STEP;
1086
1087 /* voltage setting */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301088 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, NCP_VPROG_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 &vreg->ctrl_reg);
1090 if (rc)
1091 print_write_error(vreg, rc, __func__);
1092
1093 return rc;
1094}
1095
1096static int pm8058_ncp_get_voltage(struct regulator_dev *dev)
1097{
1098 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1099 u8 vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
1100 return NCP_UV_MIN + vprog * NCP_UV_STEP;
1101}
1102
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301103static int pm8058_ldo_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104{
1105 int rc = 0;
1106 u8 mask, val;
1107
1108 switch (mode) {
1109 case REGULATOR_MODE_FAST:
1110 /* HPM */
1111 val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
1112 | LDO_CTRL_PM_HPM;
1113 mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301114 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 &vreg->ctrl_reg);
1116 if (rc)
1117 goto bail;
1118
1119 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301120 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 if (rc)
1122 goto bail;
1123 break;
1124
1125 case REGULATOR_MODE_STANDBY:
1126 /* LPM */
1127 val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
1128 | LDO_CTRL_PM_LPM;
1129 mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301130 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131 &vreg->ctrl_reg);
1132 if (rc)
1133 goto bail;
1134
1135 val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
1136 | REGULATOR_BANK_SEL(0);
1137 mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301138 rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 &vreg->test_reg[0]);
1140 if (rc)
1141 goto bail;
1142
1143 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301144 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 if (rc)
1146 goto bail;
1147 break;
1148
1149 case REGULATOR_MODE_IDLE:
1150 /* Pin Control */
1151 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301152 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 if (rc)
1154 goto bail;
1155 break;
1156
1157 default:
1158 pr_err("%s: invalid mode: %u\n", __func__, mode);
1159 return -EINVAL;
1160 }
1161
1162bail:
1163 if (rc)
1164 print_write_error(vreg, rc, __func__);
1165
1166 return rc;
1167}
1168
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301169static int pm8058_smps_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170{
1171 int rc = 0;
1172 u8 mask, val;
1173
1174 switch (mode) {
1175 case REGULATOR_MODE_FAST:
1176 /* HPM */
1177 val = SMPS_CLK_CTRL_PWM;
1178 mask = SMPS_CLK_CTRL_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301179 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 &vreg->clk_ctrl_reg);
1181 if (rc)
1182 goto bail;
1183
1184 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301185 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 if (rc)
1187 goto bail;
1188 break;
1189
1190 case REGULATOR_MODE_STANDBY:
1191 /* LPM */
1192 val = SMPS_CLK_CTRL_PFM;
1193 mask = SMPS_CLK_CTRL_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301194 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 &vreg->clk_ctrl_reg);
1196 if (rc)
1197 goto bail;
1198
1199 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301200 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 if (rc)
1202 goto bail;
1203 break;
1204
1205 case REGULATOR_MODE_IDLE:
1206 /* Pin Control */
1207 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301208 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 if (rc)
1210 goto bail;
1211 break;
1212
1213 default:
1214 pr_err("%s: invalid mode: %u\n", __func__, mode);
1215 return -EINVAL;
1216 }
1217
1218bail:
1219 if (rc)
1220 print_write_error(vreg, rc, __func__);
1221
1222 return rc;
1223}
1224
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301225static int pm8058_lvs_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226{
1227 int rc = 0;
1228
1229 if (mode == REGULATOR_MODE_IDLE) {
1230 /* Use pin control. */
1231 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301232 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 } else {
1234 /* Turn off pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301235 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 }
1237
1238 return rc;
1239}
1240
1241/*
1242 * Optimum mode programming:
1243 * REGULATOR_MODE_FAST: Go to HPM (highest priority)
1244 * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
1245 * votes, else go to LPM
1246 *
1247 * Pin ctrl mode voting via regulator set_mode:
1248 * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
1249 * go to HPM
1250 * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
1251 */
1252static int pm8058_vreg_set_mode(struct regulator_dev *dev, unsigned int mode)
1253{
1254 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 unsigned prev_optimum = vreg->optimum;
1256 unsigned prev_pc_vote = vreg->pc_vote;
1257 unsigned prev_mode_initialized = vreg->mode_initialized;
1258 int new_mode = REGULATOR_MODE_FAST;
1259 int rc = 0;
1260
1261 /* Determine new mode to go into. */
1262 switch (mode) {
1263 case REGULATOR_MODE_FAST:
1264 new_mode = REGULATOR_MODE_FAST;
1265 vreg->optimum = mode;
1266 vreg->mode_initialized = 1;
1267 break;
1268
1269 case REGULATOR_MODE_STANDBY:
1270 if (vreg->pc_vote)
1271 new_mode = REGULATOR_MODE_IDLE;
1272 else
1273 new_mode = REGULATOR_MODE_STANDBY;
1274 vreg->optimum = mode;
1275 vreg->mode_initialized = 1;
1276 break;
1277
1278 case REGULATOR_MODE_IDLE:
1279 if (vreg->pc_vote++)
1280 goto done; /* already taken care of */
1281
1282 if (vreg->mode_initialized
1283 && vreg->optimum == REGULATOR_MODE_FAST)
1284 new_mode = REGULATOR_MODE_FAST;
1285 else
1286 new_mode = REGULATOR_MODE_IDLE;
1287 break;
1288
1289 case REGULATOR_MODE_NORMAL:
1290 if (vreg->pc_vote && --(vreg->pc_vote))
1291 goto done; /* already taken care of */
1292
1293 if (vreg->optimum == REGULATOR_MODE_STANDBY)
1294 new_mode = REGULATOR_MODE_STANDBY;
1295 else
1296 new_mode = REGULATOR_MODE_FAST;
1297 break;
1298
1299 default:
1300 pr_err("%s: unknown mode, mode=%u\n", __func__, mode);
1301 return -EINVAL;
1302 }
1303
1304 switch (vreg->type) {
1305 case REGULATOR_TYPE_LDO:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301306 rc = pm8058_ldo_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 break;
1308 case REGULATOR_TYPE_SMPS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301309 rc = pm8058_smps_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 break;
1311 case REGULATOR_TYPE_LVS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301312 rc = pm8058_lvs_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 break;
1314 }
1315
1316 if (rc) {
1317 print_write_error(vreg, rc, __func__);
1318 vreg->mode_initialized = prev_mode_initialized;
1319 vreg->optimum = prev_optimum;
1320 vreg->pc_vote = prev_pc_vote;
1321 return rc;
1322 }
1323
1324done:
1325 return 0;
1326}
1327
1328static unsigned int pm8058_vreg_get_mode(struct regulator_dev *dev)
1329{
1330 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1331
1332 if (!vreg->mode_initialized && vreg->pc_vote)
1333 return REGULATOR_MODE_IDLE;
1334
1335 /* Check physical pin control state. */
1336 switch (vreg->type) {
1337 case REGULATOR_TYPE_LDO:
1338 if (!(vreg->ctrl_reg & LDO_ENABLE_MASK)
1339 && !pm8058_vreg_is_global_enabled(vreg)
1340 && (vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK))
1341 return REGULATOR_MODE_IDLE;
1342 else if (((vreg->ctrl_reg & LDO_ENABLE_MASK)
1343 || pm8058_vreg_is_global_enabled(vreg))
1344 && (vreg->ctrl_reg & LDO_CTRL_PM_MASK)
1345 && (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK))
1346 return REGULATOR_MODE_IDLE;
1347 break;
1348 case REGULATOR_TYPE_SMPS:
1349 if (!SMPS_IN_ADVANCED_MODE(vreg)
1350 && !(vreg->ctrl_reg & REGULATOR_EN_MASK)
1351 && !pm8058_vreg_is_global_enabled(vreg)
1352 && (vreg->sleep_ctrl_reg & SMPS_PIN_CTRL_MASK))
1353 return REGULATOR_MODE_IDLE;
1354 else if (!SMPS_IN_ADVANCED_MODE(vreg)
1355 && ((vreg->ctrl_reg & REGULATOR_EN_MASK)
1356 || pm8058_vreg_is_global_enabled(vreg))
1357 && ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
1358 == SMPS_CLK_CTRL_PFM)
1359 && (vreg->sleep_ctrl_reg & SMPS_PIN_CTRL_LPM_MASK))
1360 return REGULATOR_MODE_IDLE;
1361 break;
1362 case REGULATOR_TYPE_LVS:
1363 if (!(vreg->ctrl_reg & LVS_ENABLE_MASK)
1364 && !pm8058_vreg_is_global_enabled(vreg)
1365 && (vreg->ctrl_reg & LVS_PIN_CTRL_MASK))
1366 return REGULATOR_MODE_IDLE;
1367 }
1368
1369 if (vreg->optimum == REGULATOR_MODE_FAST)
1370 return REGULATOR_MODE_FAST;
1371 else if (vreg->pc_vote)
1372 return REGULATOR_MODE_IDLE;
1373 else if (vreg->optimum == REGULATOR_MODE_STANDBY)
1374 return REGULATOR_MODE_STANDBY;
1375 return REGULATOR_MODE_FAST;
1376}
1377
1378unsigned int pm8058_vreg_get_optimum_mode(struct regulator_dev *dev,
1379 int input_uV, int output_uV, int load_uA)
1380{
1381 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1382
1383 if (load_uA <= 0) {
1384 /*
1385 * pm8058_vreg_get_optimum_mode is being called before consumers
1386 * have specified their load currents via
1387 * regulator_set_optimum_mode. Return whatever the existing mode
1388 * is.
1389 */
1390 return pm8058_vreg_get_mode(dev);
1391 }
1392
1393 if (load_uA >= vreg->hpm_min_load)
1394 return REGULATOR_MODE_FAST;
1395 return REGULATOR_MODE_STANDBY;
1396}
1397
1398static struct regulator_ops pm8058_ldo_ops = {
1399 .enable = pm8058_vreg_enable,
1400 .disable = pm8058_vreg_disable,
1401 .is_enabled = pm8058_vreg_is_enabled,
1402 .set_voltage = pm8058_ldo_set_voltage,
1403 .get_voltage = pm8058_ldo_get_voltage,
1404 .set_mode = pm8058_vreg_set_mode,
1405 .get_mode = pm8058_vreg_get_mode,
1406 .get_optimum_mode = pm8058_vreg_get_optimum_mode,
1407};
1408
1409static struct regulator_ops pm8058_smps_ops = {
1410 .enable = pm8058_vreg_enable,
1411 .disable = pm8058_vreg_disable,
1412 .is_enabled = pm8058_vreg_is_enabled,
1413 .set_voltage = pm8058_smps_set_voltage,
1414 .get_voltage = pm8058_smps_get_voltage,
1415 .set_mode = pm8058_vreg_set_mode,
1416 .get_mode = pm8058_vreg_get_mode,
1417 .get_optimum_mode = pm8058_vreg_get_optimum_mode,
1418};
1419
1420static struct regulator_ops pm8058_lvs_ops = {
1421 .enable = pm8058_vreg_enable,
1422 .disable = pm8058_vreg_disable,
1423 .is_enabled = pm8058_vreg_is_enabled,
1424 .set_mode = pm8058_vreg_set_mode,
1425 .get_mode = pm8058_vreg_get_mode,
1426};
1427
1428static struct regulator_ops pm8058_ncp_ops = {
1429 .enable = pm8058_vreg_enable,
1430 .disable = pm8058_vreg_disable,
1431 .is_enabled = pm8058_vreg_is_enabled,
1432 .set_voltage = pm8058_ncp_set_voltage,
1433 .get_voltage = pm8058_ncp_get_voltage,
1434};
1435
1436#define VREG_DESCRIP(_id, _name, _ops) \
1437 [_id] = { \
1438 .id = _id, \
1439 .name = _name, \
1440 .ops = _ops, \
1441 .type = REGULATOR_VOLTAGE, \
1442 .owner = THIS_MODULE, \
1443 }
1444
1445static struct regulator_desc pm8058_vreg_descrip[] = {
1446 VREG_DESCRIP(PM8058_VREG_ID_L0, "8058_l0", &pm8058_ldo_ops),
1447 VREG_DESCRIP(PM8058_VREG_ID_L1, "8058_l1", &pm8058_ldo_ops),
1448 VREG_DESCRIP(PM8058_VREG_ID_L2, "8058_l2", &pm8058_ldo_ops),
1449 VREG_DESCRIP(PM8058_VREG_ID_L3, "8058_l3", &pm8058_ldo_ops),
1450 VREG_DESCRIP(PM8058_VREG_ID_L4, "8058_l4", &pm8058_ldo_ops),
1451 VREG_DESCRIP(PM8058_VREG_ID_L5, "8058_l5", &pm8058_ldo_ops),
1452 VREG_DESCRIP(PM8058_VREG_ID_L6, "8058_l6", &pm8058_ldo_ops),
1453 VREG_DESCRIP(PM8058_VREG_ID_L7, "8058_l7", &pm8058_ldo_ops),
1454 VREG_DESCRIP(PM8058_VREG_ID_L8, "8058_l8", &pm8058_ldo_ops),
1455 VREG_DESCRIP(PM8058_VREG_ID_L9, "8058_l9", &pm8058_ldo_ops),
1456 VREG_DESCRIP(PM8058_VREG_ID_L10, "8058_l10", &pm8058_ldo_ops),
1457 VREG_DESCRIP(PM8058_VREG_ID_L11, "8058_l11", &pm8058_ldo_ops),
1458 VREG_DESCRIP(PM8058_VREG_ID_L12, "8058_l12", &pm8058_ldo_ops),
1459 VREG_DESCRIP(PM8058_VREG_ID_L13, "8058_l13", &pm8058_ldo_ops),
1460 VREG_DESCRIP(PM8058_VREG_ID_L14, "8058_l14", &pm8058_ldo_ops),
1461 VREG_DESCRIP(PM8058_VREG_ID_L15, "8058_l15", &pm8058_ldo_ops),
1462 VREG_DESCRIP(PM8058_VREG_ID_L16, "8058_l16", &pm8058_ldo_ops),
1463 VREG_DESCRIP(PM8058_VREG_ID_L17, "8058_l17", &pm8058_ldo_ops),
1464 VREG_DESCRIP(PM8058_VREG_ID_L18, "8058_l18", &pm8058_ldo_ops),
1465 VREG_DESCRIP(PM8058_VREG_ID_L19, "8058_l19", &pm8058_ldo_ops),
1466 VREG_DESCRIP(PM8058_VREG_ID_L20, "8058_l20", &pm8058_ldo_ops),
1467 VREG_DESCRIP(PM8058_VREG_ID_L21, "8058_l21", &pm8058_ldo_ops),
1468 VREG_DESCRIP(PM8058_VREG_ID_L22, "8058_l22", &pm8058_ldo_ops),
1469 VREG_DESCRIP(PM8058_VREG_ID_L23, "8058_l23", &pm8058_ldo_ops),
1470 VREG_DESCRIP(PM8058_VREG_ID_L24, "8058_l24", &pm8058_ldo_ops),
1471 VREG_DESCRIP(PM8058_VREG_ID_L25, "8058_l25", &pm8058_ldo_ops),
1472
1473 VREG_DESCRIP(PM8058_VREG_ID_S0, "8058_s0", &pm8058_smps_ops),
1474 VREG_DESCRIP(PM8058_VREG_ID_S1, "8058_s1", &pm8058_smps_ops),
1475 VREG_DESCRIP(PM8058_VREG_ID_S2, "8058_s2", &pm8058_smps_ops),
1476 VREG_DESCRIP(PM8058_VREG_ID_S3, "8058_s3", &pm8058_smps_ops),
1477 VREG_DESCRIP(PM8058_VREG_ID_S4, "8058_s4", &pm8058_smps_ops),
1478
1479 VREG_DESCRIP(PM8058_VREG_ID_LVS0, "8058_lvs0", &pm8058_lvs_ops),
1480 VREG_DESCRIP(PM8058_VREG_ID_LVS1, "8058_lvs1", &pm8058_lvs_ops),
1481
1482 VREG_DESCRIP(PM8058_VREG_ID_NCP, "8058_ncp", &pm8058_ncp_ops),
1483};
1484
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301485static int pm8058_master_enable_init(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486{
1487 int rc = 0, i;
1488
1489 for (i = 0; i < MASTER_ENABLE_COUNT; i++) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301490 rc = pm8xxx_readb(vreg->dev->parent, m_en[i].addr,
1491 &(m_en[i].reg));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 if (rc)
1493 goto bail;
1494 }
1495
1496bail:
1497 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301498 pr_err("%s: pm8xxx_read failed, rc=%d\n", __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499
1500 return rc;
1501}
1502
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301503static int pm8058_init_ldo(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504{
1505 int rc = 0, i;
1506 u8 bank;
1507
1508 /* Save the current test register state. */
1509 for (i = 0; i < LDO_TEST_BANKS; i++) {
1510 bank = REGULATOR_BANK_SEL(i);
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301511 rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 if (rc)
1513 goto bail;
1514
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301515 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1516 &vreg->test_reg[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 if (rc)
1518 goto bail;
1519 vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
1520 }
1521
1522 if ((vreg->ctrl_reg & LDO_CTRL_PM_MASK) == LDO_CTRL_PM_LPM)
1523 vreg->optimum = REGULATOR_MODE_STANDBY;
1524 else
1525 vreg->optimum = REGULATOR_MODE_FAST;
1526
1527 /* Set pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301528 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 (vreg->pdata->pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
1530 LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
1531bail:
1532 return rc;
1533}
1534
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301535static int pm8058_init_smps(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536{
1537 int rc = 0, i;
1538 u8 bank;
1539
1540 /* Save the current test2 register state. */
1541 for (i = 0; i < SMPS_TEST_BANKS; i++) {
1542 bank = REGULATOR_BANK_SEL(i);
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301543 rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 if (rc)
1545 goto bail;
1546
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301547 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1548 &vreg->test_reg[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549 if (rc)
1550 goto bail;
1551 vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
1552 }
1553
1554 /* Save the current clock control register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301555 rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
1556 &vreg->clk_ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 if (rc)
1558 goto bail;
1559
1560 /* Save the current sleep control register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301561 rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
1562 &vreg->sleep_ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 if (rc)
1564 goto bail;
1565
1566 vreg->save_uV = 1; /* This is not a no-op. */
1567 vreg->save_uV = _pm8058_smps_get_voltage(vreg);
1568
1569 if ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK) == SMPS_CLK_CTRL_PFM)
1570 vreg->optimum = REGULATOR_MODE_STANDBY;
1571 else
1572 vreg->optimum = REGULATOR_MODE_FAST;
1573
1574 /* Set advanced mode pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301575 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 (vreg->pdata->pull_down_enable
1577 ? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
1578 | REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
1579 REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
1580 &vreg->test_reg[6]);
1581 if (rc)
1582 goto bail;
1583
1584 if (!SMPS_IN_ADVANCED_MODE(vreg)) {
1585 /* Set legacy mode pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301586 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587 (vreg->pdata->pull_down_enable
1588 ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
1589 SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
1590 if (rc)
1591 goto bail;
1592 }
1593
1594bail:
1595 return rc;
1596}
1597
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301598static int pm8058_init_lvs(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599{
1600 int rc = 0;
1601
1602 vreg->optimum = REGULATOR_MODE_FAST;
1603
1604 /* Set pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301605 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 (vreg->pdata->pull_down_enable
1607 ? LVS_PULL_DOWN_ENABLE : LVS_PULL_DOWN_DISABLE),
1608 LVS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
1609 return rc;
1610}
1611
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301612static int pm8058_init_ncp(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613{
1614 int rc = 0;
1615
1616 /* Save the current test1 register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301617 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1618 &vreg->test_reg[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 if (rc)
1620 goto bail;
1621
1622 vreg->optimum = REGULATOR_MODE_FAST;
1623
1624bail:
1625 return rc;
1626}
1627
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301628static int pm8058_init_regulator(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001629{
1630 static int master_enable_inited;
1631 int rc = 0;
1632
1633 vreg->mode_initialized = 0;
1634
1635 if (!master_enable_inited) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301636 rc = pm8058_master_enable_init(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (!rc)
1638 master_enable_inited = 1;
1639 }
1640
1641 /* save the current control register state */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301642 rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 if (rc)
1644 goto bail;
1645
1646 switch (vreg->type) {
1647 case REGULATOR_TYPE_LDO:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301648 rc = pm8058_init_ldo(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 break;
1650 case REGULATOR_TYPE_SMPS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301651 rc = pm8058_init_smps(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652 break;
1653 case REGULATOR_TYPE_LVS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301654 rc = pm8058_init_lvs(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 break;
1656 case REGULATOR_TYPE_NCP:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301657 rc = pm8058_init_ncp(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001658 break;
1659 }
1660
1661bail:
1662 if (rc)
1663 pr_err("%s: pm8058_read/write failed; initial register states "
1664 "unknown, rc=%d\n", __func__, rc);
1665 return rc;
1666}
1667
1668static int __devinit pm8058_vreg_probe(struct platform_device *pdev)
1669{
1670 struct regulator_desc *rdesc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671 struct pm8058_vreg *vreg;
1672 const char *reg_name = NULL;
1673 int rc = 0;
1674
1675 if (pdev == NULL)
1676 return -EINVAL;
1677
1678 if (pdev->id >= 0 && pdev->id < PM8058_VREG_MAX) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 rdesc = &pm8058_vreg_descrip[pdev->id];
1680 vreg = &pm8058_vreg[pdev->id];
1681 vreg->pdata = pdev->dev.platform_data;
1682 reg_name = pm8058_vreg_descrip[pdev->id].name;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301683 vreg->dev = &pdev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301685 rc = pm8058_init_regulator(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 if (rc)
1687 goto bail;
1688
1689 /* Disallow idle and normal modes if pin control isn't set. */
1690 if (vreg->pdata->pin_ctrl == 0)
1691 vreg->pdata->init_data.constraints.valid_modes_mask
1692 &= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
1693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 vreg->rdev = regulator_register(rdesc, &pdev->dev,
1695 &vreg->pdata->init_data, vreg);
1696 if (IS_ERR(vreg->rdev)) {
1697 rc = PTR_ERR(vreg->rdev);
1698 pr_err("%s: regulator_register failed for %s, rc=%d\n",
1699 __func__, reg_name, rc);
1700 }
1701 } else {
1702 rc = -ENODEV;
1703 }
1704
1705bail:
1706 if (rc)
1707 pr_err("%s: error for %s, rc=%d\n", __func__, reg_name, rc);
1708
1709 return rc;
1710}
1711
1712static int __devexit pm8058_vreg_remove(struct platform_device *pdev)
1713{
1714 regulator_unregister(pm8058_vreg[pdev->id].rdev);
1715 return 0;
1716}
1717
1718static struct platform_driver pm8058_vreg_driver = {
1719 .probe = pm8058_vreg_probe,
1720 .remove = __devexit_p(pm8058_vreg_remove),
1721 .driver = {
1722 .name = "pm8058-regulator",
1723 .owner = THIS_MODULE,
1724 },
1725};
1726
1727static int __init pm8058_vreg_init(void)
1728{
1729 return platform_driver_register(&pm8058_vreg_driver);
1730}
1731
1732static void __exit pm8058_vreg_exit(void)
1733{
1734 platform_driver_unregister(&pm8058_vreg_driver);
1735}
1736
1737static void print_write_error(struct pm8058_vreg *vreg, int rc,
1738 const char *func)
1739{
1740 const char *reg_name = NULL;
1741 ptrdiff_t id = vreg - pm8058_vreg;
1742
1743 if (id >= 0 && id < PM8058_VREG_MAX)
1744 reg_name = pm8058_vreg_descrip[id].name;
1745 pr_err("%s: pm8058_vreg_write failed for %s, rc=%d\n",
1746 func, reg_name, rc);
1747}
1748
1749subsys_initcall(pm8058_vreg_init);
1750module_exit(pm8058_vreg_exit);
1751
1752MODULE_LICENSE("GPL v2");
1753MODULE_DESCRIPTION("PMIC8058 regulator driver");
1754MODULE_VERSION("1.0");
1755MODULE_ALIAS("platform:pm8058-regulator");