blob: 24c79023deed2d45d764436ac72554c055050507 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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>
Steve Mucklef132c6c2012-06-06 18:30:57 -070016#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070017#include <linux/init.h>
18#include <linux/bitops.h>
19#include <linux/mfd/pmic8058.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/machine.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053022#include <linux/mfd/pm8xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/regulator/pmic8058-regulator.h>
24
25/* Regulator types */
26#define REGULATOR_TYPE_LDO 0
27#define REGULATOR_TYPE_SMPS 1
28#define REGULATOR_TYPE_LVS 2
29#define REGULATOR_TYPE_NCP 3
30
31/* Common masks */
32#define REGULATOR_EN_MASK 0x80
33
34#define REGULATOR_BANK_MASK 0xF0
35#define REGULATOR_BANK_SEL(n) ((n) << 4)
36#define REGULATOR_BANK_WRITE 0x80
37
38#define LDO_TEST_BANKS 7
39#define SMPS_TEST_BANKS 8
40#define REGULATOR_TEST_BANKS_MAX SMPS_TEST_BANKS
41
42/* LDO programming */
43
44/* CTRL register */
45#define LDO_ENABLE_MASK 0x80
46#define LDO_ENABLE 0x80
47#define LDO_PULL_DOWN_ENABLE_MASK 0x40
48#define LDO_PULL_DOWN_ENABLE 0x40
49
50#define LDO_CTRL_PM_MASK 0x20
51#define LDO_CTRL_PM_HPM 0x00
52#define LDO_CTRL_PM_LPM 0x20
53
54#define LDO_CTRL_VPROG_MASK 0x1F
55
56/* TEST register bank 0 */
57#define LDO_TEST_LPM_MASK 0x40
58#define LDO_TEST_LPM_SEL_CTRL 0x00
59#define LDO_TEST_LPM_SEL_TCXO 0x40
60
61/* TEST register bank 2 */
62#define LDO_TEST_VPROG_UPDATE_MASK 0x08
63#define LDO_TEST_RANGE_SEL_MASK 0x04
64#define LDO_TEST_FINE_STEP_MASK 0x02
65#define LDO_TEST_FINE_STEP_SHIFT 1
66
67/* TEST register bank 4 */
68#define LDO_TEST_RANGE_EXT_MASK 0x01
69
70/* TEST register bank 5 */
71#define LDO_TEST_PIN_CTRL_MASK 0x0F
72#define LDO_TEST_PIN_CTRL_EN3 0x08
73#define LDO_TEST_PIN_CTRL_EN2 0x04
74#define LDO_TEST_PIN_CTRL_EN1 0x02
75#define LDO_TEST_PIN_CTRL_EN0 0x01
76
77/* TEST register bank 6 */
78#define LDO_TEST_PIN_CTRL_LPM_MASK 0x0F
79
80/* Allowable voltage ranges */
81#define PLDO_LOW_UV_MIN 750000
82#define PLDO_LOW_UV_MAX 1537500
83#define PLDO_LOW_FINE_STEP_UV 12500
84
85#define PLDO_NORM_UV_MIN 1500000
86#define PLDO_NORM_UV_MAX 3075000
87#define PLDO_NORM_FINE_STEP_UV 25000
88
89#define PLDO_HIGH_UV_MIN 1750000
90#define PLDO_HIGH_UV_MAX 4900000
91#define PLDO_HIGH_FINE_STEP_UV 50000
92
93#define NLDO_UV_MIN 750000
94#define NLDO_UV_MAX 1537500
95#define NLDO_FINE_STEP_UV 12500
96
97/* SMPS masks and values */
98
99/* CTRL register */
100
101/* Legacy mode */
102#define SMPS_LEGACY_ENABLE 0x80
103#define SMPS_LEGACY_PULL_DOWN_ENABLE 0x40
104#define SMPS_LEGACY_VREF_SEL_MASK 0x20
105#define SMPS_LEGACY_VPROG_MASK 0x1F
106
107/* Advanced mode */
108#define SMPS_ADVANCED_BAND_MASK 0xC0
109#define SMPS_ADVANCED_BAND_OFF 0x00
110#define SMPS_ADVANCED_BAND_1 0x40
111#define SMPS_ADVANCED_BAND_2 0x80
112#define SMPS_ADVANCED_BAND_3 0xC0
113#define SMPS_ADVANCED_VPROG_MASK 0x3F
114
115/* Legacy mode voltage ranges */
116#define SMPS_MODE1_UV_MIN 1500000
117#define SMPS_MODE1_UV_MAX 3050000
118#define SMPS_MODE1_UV_STEP 50000
119
120#define SMPS_MODE2_UV_MIN 750000
121#define SMPS_MODE2_UV_MAX 1525000
122#define SMPS_MODE2_UV_STEP 25000
123
124#define SMPS_MODE3_UV_MIN 375000
125#define SMPS_MODE3_UV_MAX 1150000
126#define SMPS_MODE3_UV_STEP 25000
127
128/* Advanced mode voltage ranges */
129#define SMPS_BAND3_UV_MIN 1500000
130#define SMPS_BAND3_UV_MAX 3075000
131#define SMPS_BAND3_UV_STEP 25000
132
133#define SMPS_BAND2_UV_MIN 750000
134#define SMPS_BAND2_UV_MAX 1537500
135#define SMPS_BAND2_UV_STEP 12500
136
137#define SMPS_BAND1_UV_MIN 375000
138#define SMPS_BAND1_UV_MAX 1162500
139#define SMPS_BAND1_UV_STEP 12500
140
141#define SMPS_UV_MIN SMPS_MODE3_UV_MIN
142#define SMPS_UV_MAX SMPS_MODE1_UV_MAX
143
144/* Test2 register bank 1 */
145#define SMPS_LEGACY_VLOW_SEL_MASK 0x01
146
147/* Test2 register bank 6 */
148#define SMPS_ADVANCED_PULL_DOWN_ENABLE 0x08
149
150/* Test2 register bank 7 */
151#define SMPS_ADVANCED_MODE_MASK 0x02
152#define SMPS_ADVANCED_MODE 0x02
153#define SMPS_LEGACY_MODE 0x00
154
155#define SMPS_IN_ADVANCED_MODE(vreg) \
156 ((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
157
158/* BUCK_SLEEP_CNTRL register */
159#define SMPS_PIN_CTRL_MASK 0xF0
160#define SMPS_PIN_CTRL_A1 0x80
161#define SMPS_PIN_CTRL_A0 0x40
162#define SMPS_PIN_CTRL_D1 0x20
163#define SMPS_PIN_CTRL_D0 0x10
164
165#define SMPS_PIN_CTRL_LPM_MASK 0x0F
166#define SMPS_PIN_CTRL_LPM_A1 0x08
167#define SMPS_PIN_CTRL_LPM_A0 0x04
168#define SMPS_PIN_CTRL_LPM_D1 0x02
169#define SMPS_PIN_CTRL_LPM_D0 0x01
170
171/* BUCK_CLOCK_CNTRL register */
172#define SMPS_CLK_DIVIDE2 0x40
173
174#define SMPS_CLK_CTRL_MASK 0x30
175#define SMPS_CLK_CTRL_FOLLOW_TCXO 0x00
176#define SMPS_CLK_CTRL_PWM 0x10
177#define SMPS_CLK_CTRL_PFM 0x20
178
179/* LVS masks and values */
180
181/* CTRL register */
182#define LVS_ENABLE_MASK 0x80
183#define LVS_ENABLE 0x80
184#define LVS_PULL_DOWN_ENABLE_MASK 0x40
185#define LVS_PULL_DOWN_ENABLE 0x00
186#define LVS_PULL_DOWN_DISABLE 0x40
187
188#define LVS_PIN_CTRL_MASK 0x0F
189#define LVS_PIN_CTRL_EN0 0x08
190#define LVS_PIN_CTRL_EN1 0x04
191#define LVS_PIN_CTRL_EN2 0x02
192#define LVS_PIN_CTRL_EN3 0x01
193
194/* NCP masks and values */
195
196/* CTRL register */
197#define NCP_VPROG_MASK 0x1F
198
199#define NCP_UV_MIN 1500000
200#define NCP_UV_MAX 3050000
201#define NCP_UV_STEP 50000
202
203#define GLOBAL_ENABLE_MAX (2)
204struct pm8058_enable {
205 u16 addr;
206 u8 reg;
207};
208
209struct pm8058_vreg {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530210 struct device *dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 struct pm8058_vreg_pdata *pdata;
212 struct regulator_dev *rdev;
213 struct pm8058_enable *global_enable[GLOBAL_ENABLE_MAX];
214 int hpm_min_load;
215 int save_uV;
216 unsigned pc_vote;
217 unsigned optimum;
218 unsigned mode_initialized;
219 u16 ctrl_addr;
220 u16 test_addr;
221 u16 clk_ctrl_addr;
222 u16 sleep_ctrl_addr;
223 u8 type;
224 u8 ctrl_reg;
225 u8 test_reg[REGULATOR_TEST_BANKS_MAX];
226 u8 clk_ctrl_reg;
227 u8 sleep_ctrl_reg;
228 u8 is_nmos;
229 u8 global_enable_mask[GLOBAL_ENABLE_MAX];
230};
231
232#define LDO_M2(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
233 _en0, _en0_mask, _en1, _en1_mask) \
234 [PM8058_VREG_ID_##_id] = { \
235 .ctrl_addr = _ctrl_addr, \
236 .test_addr = _test_addr, \
237 .type = REGULATOR_TYPE_LDO, \
238 .hpm_min_load = PM8058_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
239 .is_nmos = _is_nmos, \
240 .global_enable = { \
241 [0] = _en0, \
242 [1] = _en1, \
243 }, \
244 .global_enable_mask = { \
245 [0] = _en0_mask, \
246 [1] = _en1_mask, \
247 }, \
248 }
249
250#define LDO(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
251 _en0, _en0_mask) \
252 LDO_M2(_id, _ctrl_addr, _test_addr, _is_nmos, _hpm_min_load, \
253 _en0, _en0_mask, NULL, 0)
254
255#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
256 _hpm_min_load, _en0, _en0_mask) \
257 [PM8058_VREG_ID_##_id] = { \
258 .ctrl_addr = _ctrl_addr, \
259 .test_addr = _test_addr, \
260 .clk_ctrl_addr = _clk_ctrl_addr, \
261 .sleep_ctrl_addr = _sleep_ctrl_addr, \
262 .type = REGULATOR_TYPE_SMPS, \
263 .hpm_min_load = PM8058_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
264 .global_enable = { \
265 [0] = _en0, \
266 [1] = NULL, \
267 }, \
268 .global_enable_mask = { \
269 [0] = _en0_mask, \
270 [1] = 0, \
271 }, \
272 }
273
274#define LVS(_id, _ctrl_addr, _en0, _en0_mask) \
275 [PM8058_VREG_ID_##_id] = { \
276 .ctrl_addr = _ctrl_addr, \
277 .type = REGULATOR_TYPE_LVS, \
278 .global_enable = { \
279 [0] = _en0, \
280 [1] = NULL, \
281 }, \
282 .global_enable_mask = { \
283 [0] = _en0_mask, \
284 [1] = 0, \
285 }, \
286 }
287
288#define NCP(_id, _ctrl_addr, _test1) \
289 [PM8058_VREG_ID_##_id] = { \
290 .ctrl_addr = _ctrl_addr, \
291 .type = REGULATOR_TYPE_NCP, \
292 .test_addr = _test1, \
293 .global_enable = { \
294 [0] = NULL, \
295 [1] = NULL, \
296 }, \
297 .global_enable_mask = { \
298 [0] = 0, \
299 [1] = 0, \
300 }, \
301 }
302
303#define MASTER_ENABLE_COUNT 6
304
305#define EN_MSM 0
306#define EN_PH 1
307#define EN_RF 2
308#define EN_GRP_5_4 3
309#define EN_GRP_3_2 4
310#define EN_GRP_1_0 5
311
312/* Master regulator control registers */
313static struct pm8058_enable m_en[MASTER_ENABLE_COUNT] = {
314 [EN_MSM] = {
315 .addr = 0x018, /* VREG_EN_MSM */
316 },
317 [EN_PH] = {
318 .addr = 0x019, /* VREG_EN_PH */
319 },
320 [EN_RF] = {
321 .addr = 0x01A, /* VREG_EN_RF */
322 },
323 [EN_GRP_5_4] = {
324 .addr = 0x1C8, /* VREG_EN_MSM_GRP_5-4 */
325 },
326 [EN_GRP_3_2] = {
327 .addr = 0x1C9, /* VREG_EN_MSM_GRP_3-2 */
328 },
329 [EN_GRP_1_0] = {
330 .addr = 0x1CA, /* VREG_EN_MSM_GRP_1-0 */
331 },
332};
333
334
335static struct pm8058_vreg pm8058_vreg[] = {
336 /* id ctrl test n/p hpm_min m_en m_en_mask */
337 LDO(L0, 0x009, 0x065, 1, LDO_150, &m_en[EN_GRP_5_4], BIT(3)),
338 LDO(L1, 0x00A, 0x066, 1, LDO_300, &m_en[EN_GRP_5_4], BIT(6) | BIT(2)),
339 LDO(L2, 0x00B, 0x067, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(2)),
340 LDO(L3, 0x00C, 0x068, 0, LDO_150, &m_en[EN_GRP_1_0], BIT(1)),
341 LDO(L4, 0x00D, 0x069, 0, LDO_50, &m_en[EN_MSM], 0),
342 LDO(L5, 0x00E, 0x06A, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(7)),
343 LDO(L6, 0x00F, 0x06B, 0, LDO_50, &m_en[EN_GRP_1_0], BIT(2)),
344 LDO(L7, 0x010, 0x06C, 0, LDO_50, &m_en[EN_GRP_3_2], BIT(3)),
345 LDO(L8, 0x011, 0x06D, 0, LDO_300, &m_en[EN_PH], BIT(7)),
346 LDO(L9, 0x012, 0x06E, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(3)),
347 LDO(L10, 0x013, 0x06F, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(4)),
348 LDO(L11, 0x014, 0x070, 0, LDO_150, &m_en[EN_PH], BIT(4)),
349 LDO(L12, 0x015, 0x071, 0, LDO_150, &m_en[EN_PH], BIT(3)),
350 LDO(L13, 0x016, 0x072, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(1)),
351 LDO(L14, 0x017, 0x073, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(5)),
352 LDO(L15, 0x089, 0x0E5, 0, LDO_300, &m_en[EN_GRP_1_0], BIT(4)),
353 LDO(L16, 0x08A, 0x0E6, 0, LDO_300, &m_en[EN_GRP_3_2], BIT(0)),
354 LDO(L17, 0x08B, 0x0E7, 0, LDO_150, &m_en[EN_RF], BIT(7)),
355 LDO(L18, 0x11D, 0x125, 0, LDO_150, &m_en[EN_RF], BIT(6)),
356 LDO(L19, 0x11E, 0x126, 0, LDO_150, &m_en[EN_RF], BIT(5)),
357 LDO(L20, 0x11F, 0x127, 0, LDO_150, &m_en[EN_RF], BIT(4)),
358 LDO_M2(L21, 0x120, 0x128, 1, LDO_150, &m_en[EN_GRP_5_4], BIT(1),
359 &m_en[EN_GRP_1_0], BIT(6)),
360 LDO(L22, 0x121, 0x129, 1, LDO_300, &m_en[EN_GRP_3_2], BIT(7)),
361 LDO(L23, 0x122, 0x12A, 1, LDO_300, &m_en[EN_GRP_5_4], BIT(0)),
362 LDO(L24, 0x123, 0x12B, 1, LDO_150, &m_en[EN_RF], BIT(3)),
363 LDO(L25, 0x124, 0x12C, 1, LDO_150, &m_en[EN_RF], BIT(2)),
364
365 /* id ctrl test2 clk sleep hpm_min m_en m_en_mask */
366 SMPS(S0, 0x004, 0x084, 0x1D1, 0x1D8, SMPS, &m_en[EN_MSM], BIT(7)),
367 SMPS(S1, 0x005, 0x085, 0x1D2, 0x1DB, SMPS, &m_en[EN_MSM], BIT(6)),
368 SMPS(S2, 0x110, 0x119, 0x1D3, 0x1DE, SMPS, &m_en[EN_GRP_5_4], BIT(5)),
369 SMPS(S3, 0x111, 0x11A, 0x1D4, 0x1E1, SMPS, &m_en[EN_GRP_5_4],
370 BIT(7) | BIT(4)),
371 SMPS(S4, 0x112, 0x11B, 0x1D5, 0x1E4, SMPS, &m_en[EN_GRP_3_2], BIT(5)),
372
373 /* id ctrl m_en m_en_mask */
374 LVS(LVS0, 0x12D, &m_en[EN_RF], BIT(1)),
375 LVS(LVS1, 0x12F, &m_en[EN_GRP_1_0], BIT(0)),
376
377 /* id ctrl test1 */
378 NCP(NCP, 0x090, 0x0EC),
379};
380
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530381static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg, int uV,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 int force_on);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530383static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384static int _pm8058_vreg_is_enabled(struct pm8058_vreg *vreg);
385
386static unsigned int pm8058_vreg_get_mode(struct regulator_dev *dev);
387
388static void print_write_error(struct pm8058_vreg *vreg, int rc,
389 const char *func);
390
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530391static int pm8058_vreg_write(struct pm8058_vreg *vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 u16 addr, u8 val, u8 mask, u8 *reg_save)
393{
394 int rc = 0;
395 u8 reg;
396
397 reg = (*reg_save & ~mask) | (val & mask);
398 if (reg != *reg_save)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530399 rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530401 pr_err("%s: pm8xxx_write failed, rc=%d\n", __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 else
403 *reg_save = reg;
404 return rc;
405}
406
407static int pm8058_vreg_is_global_enabled(struct pm8058_vreg *vreg)
408{
409 int ret = 0, i;
410
411 for (i = 0;
412 (i < GLOBAL_ENABLE_MAX) && !ret && vreg->global_enable[i]; i++)
413 ret = vreg->global_enable[i]->reg &
414 vreg->global_enable_mask[i];
415
416 return ret;
417}
418
419
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530420static int pm8058_vreg_set_global_enable(struct pm8058_vreg *vreg, int on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421{
422 int rc = 0, i;
423
424 for (i = 0;
425 (i < GLOBAL_ENABLE_MAX) && !rc && vreg->global_enable[i]; i++)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530426 rc = pm8058_vreg_write(vreg, vreg->global_enable[i]->addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 (on ? vreg->global_enable_mask[i] : 0),
428 vreg->global_enable_mask[i],
429 &vreg->global_enable[i]->reg);
430
431 return rc;
432}
433
434static int pm8058_vreg_using_pin_ctrl(struct pm8058_vreg *vreg)
435{
436 int ret = 0;
437
438 switch (vreg->type) {
439 case REGULATOR_TYPE_LDO:
440 ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
441 | (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
442 break;
443 case REGULATOR_TYPE_SMPS:
444 ret = vreg->sleep_ctrl_reg
445 & (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
446 break;
447 case REGULATOR_TYPE_LVS:
448 ret = vreg->ctrl_reg & LVS_PIN_CTRL_MASK;
449 break;
450 }
451
452 return ret;
453}
454
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530455static int pm8058_vreg_set_pin_ctrl(struct pm8058_vreg *vreg, int on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700456{
457 int rc = 0, bank;
458 u8 val = 0, mask;
459 unsigned pc = vreg->pdata->pin_ctrl;
460 unsigned pf = vreg->pdata->pin_fn;
461
462 switch (vreg->type) {
463 case REGULATOR_TYPE_LDO:
464 if (on) {
465 if (pc & PM8058_VREG_PIN_CTRL_D0)
466 val |= LDO_TEST_PIN_CTRL_EN0;
467 if (pc & PM8058_VREG_PIN_CTRL_D1)
468 val |= LDO_TEST_PIN_CTRL_EN1;
469 if (pc & PM8058_VREG_PIN_CTRL_A0)
470 val |= LDO_TEST_PIN_CTRL_EN2;
471 if (pc & PM8058_VREG_PIN_CTRL_A1)
472 val |= LDO_TEST_PIN_CTRL_EN3;
473
474 bank = (pf == PM8058_VREG_PIN_FN_ENABLE ? 5 : 6);
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530475 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 val | REGULATOR_BANK_SEL(bank)
477 | REGULATOR_BANK_WRITE,
478 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
479 &vreg->test_reg[bank]);
480 if (rc)
481 goto bail;
482
483 val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
484 | REGULATOR_BANK_SEL(0);
485 mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530486 rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 &vreg->test_reg[0]);
488 if (rc)
489 goto bail;
490
491 if (pf == PM8058_VREG_PIN_FN_ENABLE) {
492 /* Pin control ON/OFF */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530493 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 LDO_CTRL_PM_HPM,
495 LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
496 &vreg->ctrl_reg);
497 if (rc)
498 goto bail;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530499 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 if (rc)
501 goto bail;
502 } else {
503 /* Pin control LPM/HPM */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530504 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505 LDO_ENABLE | LDO_CTRL_PM_LPM,
506 LDO_ENABLE_MASK | LDO_CTRL_PM_MASK,
507 &vreg->ctrl_reg);
508 if (rc)
509 goto bail;
510 }
511 } else {
512 /* Pin control off */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530513 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514 REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
515 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
516 &vreg->test_reg[5]);
517 if (rc)
518 goto bail;
519
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530520 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
522 LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
523 &vreg->test_reg[6]);
524 if (rc)
525 goto bail;
526 }
527 break;
528
529 case REGULATOR_TYPE_SMPS:
530 if (on) {
531 if (pf == PM8058_VREG_PIN_FN_ENABLE) {
532 /* Pin control ON/OFF */
533 if (pc & PM8058_VREG_PIN_CTRL_D0)
534 val |= SMPS_PIN_CTRL_D0;
535 if (pc & PM8058_VREG_PIN_CTRL_D1)
536 val |= SMPS_PIN_CTRL_D1;
537 if (pc & PM8058_VREG_PIN_CTRL_A0)
538 val |= SMPS_PIN_CTRL_A0;
539 if (pc & PM8058_VREG_PIN_CTRL_A1)
540 val |= SMPS_PIN_CTRL_A1;
541 } else {
542 /* Pin control LPM/HPM */
543 if (pc & PM8058_VREG_PIN_CTRL_D0)
544 val |= SMPS_PIN_CTRL_LPM_D0;
545 if (pc & PM8058_VREG_PIN_CTRL_D1)
546 val |= SMPS_PIN_CTRL_LPM_D1;
547 if (pc & PM8058_VREG_PIN_CTRL_A0)
548 val |= SMPS_PIN_CTRL_LPM_A0;
549 if (pc & PM8058_VREG_PIN_CTRL_A1)
550 val |= SMPS_PIN_CTRL_LPM_A1;
551 }
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530552 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 if (rc)
554 goto bail;
555
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530556 rc = pm8058_smps_set_voltage_legacy(vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557 vreg->save_uV);
558 if (rc)
559 goto bail;
560
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530561 rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
563 &vreg->sleep_ctrl_reg);
564 if (rc)
565 goto bail;
566
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530567 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 (pf == PM8058_VREG_PIN_FN_ENABLE
569 ? 0 : SMPS_LEGACY_ENABLE),
570 SMPS_LEGACY_ENABLE, &vreg->ctrl_reg);
571 if (rc)
572 goto bail;
573
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530574 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 (pf == PM8058_VREG_PIN_FN_ENABLE
576 ? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
577 SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
578 if (rc)
579 goto bail;
580 } else {
581 /* Pin control off */
582 if (!SMPS_IN_ADVANCED_MODE(vreg)) {
583 if (_pm8058_vreg_is_enabled(vreg))
584 val = SMPS_LEGACY_ENABLE;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530585 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 val, SMPS_LEGACY_ENABLE,
587 &vreg->ctrl_reg);
588 if (rc)
589 goto bail;
590 }
591
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530592 rc = pm8058_vreg_write(vreg, vreg->sleep_ctrl_addr, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
594 &vreg->sleep_ctrl_reg);
595 if (rc)
596 goto bail;
597
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530598 rc = pm8058_smps_set_voltage_advanced(vreg,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 vreg->save_uV, 0);
600 if (rc)
601 goto bail;
602 }
603 break;
604
605 case REGULATOR_TYPE_LVS:
606 if (on) {
607 if (pc & PM8058_VREG_PIN_CTRL_D0)
608 val |= LVS_PIN_CTRL_EN0;
609 if (pc & PM8058_VREG_PIN_CTRL_D1)
610 val |= LVS_PIN_CTRL_EN1;
611 if (pc & PM8058_VREG_PIN_CTRL_A0)
612 val |= LVS_PIN_CTRL_EN2;
613 if (pc & PM8058_VREG_PIN_CTRL_A1)
614 val |= LVS_PIN_CTRL_EN3;
615
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530616 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 LVS_PIN_CTRL_MASK | LVS_ENABLE_MASK,
618 &vreg->ctrl_reg);
619 if (rc)
620 goto bail;
621
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530622 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 if (rc)
624 goto bail;
625 } else {
626 /* Pin control off */
627 if (_pm8058_vreg_is_enabled(vreg))
628 val = LVS_ENABLE;
629
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530630 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 LVS_ENABLE_MASK | LVS_PIN_CTRL_MASK,
632 &vreg->ctrl_reg);
633 if (rc)
634 goto bail;
635
636 }
637 break;
638 }
639
640bail:
641 if (rc)
642 print_write_error(vreg, rc, __func__);
643
644 return rc;
645}
646
647static int pm8058_vreg_enable(struct regulator_dev *dev)
648{
649 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650 int mode;
651 int rc = 0;
652
653 mode = pm8058_vreg_get_mode(dev);
654
655 if (mode == REGULATOR_MODE_IDLE) {
656 /* Turn on pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530657 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 if (rc)
659 goto bail;
660 return rc;
661 }
662 if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530663 rc = pm8058_smps_set_voltage_advanced(vreg, vreg->save_uV, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530665 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, REGULATOR_EN_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 REGULATOR_EN_MASK, &vreg->ctrl_reg);
667bail:
668 if (rc)
669 print_write_error(vreg, rc, __func__);
670
671 return rc;
672}
673
674static int _pm8058_vreg_is_enabled(struct pm8058_vreg *vreg)
675{
676 /*
677 * All regulator types except advanced mode SMPS have enable bit in
678 * bit 7 of the control register. Global enable and pin control also
679 * do not work for advanced mode SMPS.
680 */
681 if (!(vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
682 && ((vreg->ctrl_reg & REGULATOR_EN_MASK)
683 || pm8058_vreg_is_global_enabled(vreg)
684 || pm8058_vreg_using_pin_ctrl(vreg)))
685 return 1;
686 else if (vreg->type == REGULATOR_TYPE_SMPS
687 && SMPS_IN_ADVANCED_MODE(vreg)
688 && ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
689 != SMPS_ADVANCED_BAND_OFF))
690 return 1;
691
692 return 0;
693}
694
695static int pm8058_vreg_is_enabled(struct regulator_dev *dev)
696{
697 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
698
699 return _pm8058_vreg_is_enabled(vreg);
700}
701
702static int pm8058_vreg_disable(struct regulator_dev *dev)
703{
704 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705 int rc = 0;
706
707 /* Disable in global control register. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530708 rc = pm8058_vreg_set_global_enable(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 if (rc)
710 goto bail;
711
712 /* Turn off pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530713 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714 if (rc)
715 goto bail;
716
717 /* Disable in local control register. */
718 if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530719 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 SMPS_ADVANCED_BAND_OFF, SMPS_ADVANCED_BAND_MASK,
721 &vreg->ctrl_reg);
722 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530723 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 REGULATOR_EN_MASK, &vreg->ctrl_reg);
725
726bail:
727 if (rc)
728 print_write_error(vreg, rc, __func__);
729
730 return rc;
731}
732
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530733static int pm8058_pldo_set_voltage(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734{
735 int vmin, rc = 0;
736 unsigned vprog, fine_step;
737 u8 range_ext, range_sel, fine_step_reg;
738
739 if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX)
740 return -EINVAL;
741
742 if (uV < PLDO_LOW_UV_MAX + PLDO_LOW_FINE_STEP_UV) {
743 vmin = PLDO_LOW_UV_MIN;
744 fine_step = PLDO_LOW_FINE_STEP_UV;
745 range_ext = 0;
746 range_sel = LDO_TEST_RANGE_SEL_MASK;
747 } else if (uV < PLDO_NORM_UV_MAX + PLDO_NORM_FINE_STEP_UV) {
748 vmin = PLDO_NORM_UV_MIN;
749 fine_step = PLDO_NORM_FINE_STEP_UV;
750 range_ext = 0;
751 range_sel = 0;
752 } else {
753 vmin = PLDO_HIGH_UV_MIN;
754 fine_step = PLDO_HIGH_FINE_STEP_UV;
755 range_ext = LDO_TEST_RANGE_EXT_MASK;
756 range_sel = 0;
757 }
758
759 vprog = (uV - vmin) / fine_step;
760 fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
761 vprog >>= 1;
762
763 /*
764 * Disable program voltage update if range extension, range select,
765 * or fine step have changed and the regulator is enabled.
766 */
767 if (_pm8058_vreg_is_enabled(vreg) &&
768 (((range_ext ^ vreg->test_reg[4]) & LDO_TEST_RANGE_EXT_MASK)
769 || ((range_sel ^ vreg->test_reg[2]) & LDO_TEST_RANGE_SEL_MASK)
770 || ((fine_step_reg ^ vreg->test_reg[2])
771 & LDO_TEST_FINE_STEP_MASK))) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530772 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 REGULATOR_BANK_SEL(2) | REGULATOR_BANK_WRITE,
774 REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
775 &vreg->test_reg[2]);
776 if (rc)
777 goto bail;
778 }
779
780 /* Write new voltage. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530781 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
783 if (rc)
784 goto bail;
785
786 /* Write range extension. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530787 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 range_ext | REGULATOR_BANK_SEL(4)
789 | REGULATOR_BANK_WRITE,
790 LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
791 &vreg->test_reg[4]);
792 if (rc)
793 goto bail;
794
795 /* Write fine step, range select and program voltage update. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530796 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
798 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
799 LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
800 | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
801 &vreg->test_reg[2]);
802bail:
803 if (rc)
804 print_write_error(vreg, rc, __func__);
805
806 return rc;
807}
808
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530809static int pm8058_nldo_set_voltage(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810{
811 unsigned vprog, fine_step_reg;
812 int rc;
813
814 if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX)
815 return -EINVAL;
816
817 vprog = (uV - NLDO_UV_MIN) / NLDO_FINE_STEP_UV;
818 fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
819 vprog >>= 1;
820
821 /* Write new voltage. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530822 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
824 if (rc)
825 goto bail;
826
827 /* Write fine step. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530828 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 fine_step_reg | REGULATOR_BANK_SEL(2)
830 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
831 LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
832 | LDO_TEST_VPROG_UPDATE_MASK,
833 &vreg->test_reg[2]);
834bail:
835 if (rc)
836 print_write_error(vreg, rc, __func__);
837
838 return rc;
839}
840
841static int pm8058_ldo_set_voltage(struct regulator_dev *dev,
842 int min_uV, int max_uV, unsigned *selector)
843{
844 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700845
846 if (vreg->is_nmos)
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530847 return pm8058_nldo_set_voltage(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530849 return pm8058_pldo_set_voltage(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850}
851
852static int pm8058_pldo_get_voltage(struct pm8058_vreg *vreg)
853{
854 int vmin, fine_step;
855 u8 range_ext, range_sel, vprog, fine_step_reg;
856
857 fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
858 range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
859 range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
860 vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
861
862 vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
863
864 if (range_sel) {
865 /* low range mode */
866 fine_step = PLDO_LOW_FINE_STEP_UV;
867 vmin = PLDO_LOW_UV_MIN;
868 } else if (!range_ext) {
869 /* normal mode */
870 fine_step = PLDO_NORM_FINE_STEP_UV;
871 vmin = PLDO_NORM_UV_MIN;
872 } else {
873 /* high range mode */
874 fine_step = PLDO_HIGH_FINE_STEP_UV;
875 vmin = PLDO_HIGH_UV_MIN;
876 }
877
878 return fine_step * vprog + vmin;
879}
880
881static int pm8058_nldo_get_voltage(struct pm8058_vreg *vreg)
882{
883 u8 vprog, fine_step_reg;
884
885 fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
886 vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
887
888 vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
889
890 return NLDO_FINE_STEP_UV * vprog + NLDO_UV_MIN;
891}
892
893static int pm8058_ldo_get_voltage(struct regulator_dev *dev)
894{
895 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
896
897 if (vreg->is_nmos)
898 return pm8058_nldo_get_voltage(vreg);
899 else
900 return pm8058_pldo_get_voltage(vreg);
901}
902
903static int pm8058_smps_get_voltage_advanced(struct pm8058_vreg *vreg)
904{
905 u8 vprog, band;
906 int uV = 0;
907
908 vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
909 band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
910
911 if (band == SMPS_ADVANCED_BAND_1)
912 uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
913 else if (band == SMPS_ADVANCED_BAND_2)
914 uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
915 else if (band == SMPS_ADVANCED_BAND_3)
916 uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
917 else
918 uV = vreg->save_uV;
919
920 return uV;
921}
922
923static int pm8058_smps_get_voltage_legacy(struct pm8058_vreg *vreg)
924{
925 u8 vlow, vref, vprog;
926 int uV;
927
928 vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
929 vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
930 vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
931
932 if (vlow && vref) {
933 /* mode 3 */
934 uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
935 } else if (vref) {
936 /* mode 2 */
937 uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
938 } else {
939 /* mode 1 */
940 uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
941 }
942
943 return uV;
944}
945
946static int _pm8058_smps_get_voltage(struct pm8058_vreg *vreg)
947{
948 if (SMPS_IN_ADVANCED_MODE(vreg))
949 return pm8058_smps_get_voltage_advanced(vreg);
950
951 return pm8058_smps_get_voltage_legacy(vreg);
952}
953
954static int pm8058_smps_get_voltage(struct regulator_dev *dev)
955{
956 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
957
958 return _pm8058_smps_get_voltage(vreg);
959}
960
961static int pm8058_smps_set_voltage_advanced(struct pm8058_vreg *vreg,
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530962 int uV, int force_on)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963{
964 u8 vprog, band;
965 int rc, new_uV;
966
967 if (uV < SMPS_BAND1_UV_MAX + SMPS_BAND1_UV_STEP) {
968 vprog = ((uV - SMPS_BAND1_UV_MIN) / SMPS_BAND1_UV_STEP);
969 band = SMPS_ADVANCED_BAND_1;
970 new_uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
971 } else if (uV < SMPS_BAND2_UV_MAX + SMPS_BAND2_UV_STEP) {
972 vprog = ((uV - SMPS_BAND2_UV_MIN) / SMPS_BAND2_UV_STEP);
973 band = SMPS_ADVANCED_BAND_2;
974 new_uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
975 } else {
976 vprog = ((uV - SMPS_BAND3_UV_MIN) / SMPS_BAND3_UV_STEP);
977 band = SMPS_ADVANCED_BAND_3;
978 new_uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
979 }
980
981 /* Do not set band if regulator currently disabled. */
982 if (!_pm8058_vreg_is_enabled(vreg) && !force_on)
983 band = SMPS_ADVANCED_BAND_OFF;
984
985 /* Set advanced mode bit to 1. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530986 rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
988 SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
989 &vreg->test_reg[7]);
990 if (rc)
991 goto bail;
992
993 /* Set voltage and voltage band. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530994 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, band | vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
996 &vreg->ctrl_reg);
997 if (rc)
998 goto bail;
999
1000 vreg->save_uV = new_uV;
1001
1002bail:
1003 return rc;
1004}
1005
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301006static int pm8058_smps_set_voltage_legacy(struct pm8058_vreg *vreg, int uV)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007{
1008 u8 vlow, vref, vprog, pd, en;
1009 int rc;
1010
1011 if (uV < SMPS_MODE3_UV_MAX + SMPS_MODE3_UV_STEP) {
1012 vprog = ((uV - SMPS_MODE3_UV_MIN) / SMPS_MODE3_UV_STEP);
1013 vref = SMPS_LEGACY_VREF_SEL_MASK;
1014 vlow = SMPS_LEGACY_VLOW_SEL_MASK;
1015 } else if (uV < SMPS_MODE2_UV_MAX + SMPS_MODE2_UV_STEP) {
1016 vprog = ((uV - SMPS_MODE2_UV_MIN) / SMPS_MODE2_UV_STEP);
1017 vref = SMPS_LEGACY_VREF_SEL_MASK;
1018 vlow = 0;
1019 } else {
1020 vprog = ((uV - SMPS_MODE1_UV_MIN) / SMPS_MODE1_UV_STEP);
1021 vref = 0;
1022 vlow = 0;
1023 }
1024
1025 /* set vlow bit for ultra low voltage mode */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301026 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
1028 REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
1029 &vreg->test_reg[1]);
1030 if (rc)
1031 goto bail;
1032
1033 /* Set advanced mode bit to 0. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301034 rc = pm8058_vreg_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
1036 SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
1037 &vreg->test_reg[7]);
1038 if (rc)
1039 goto bail;
1040
1041 en = (_pm8058_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
1042 pd = (vreg->pdata->pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
1043
1044 /* Set voltage (and the rest of the control register). */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301045 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, en | pd | vref | vprog,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 SMPS_LEGACY_ENABLE | SMPS_LEGACY_PULL_DOWN_ENABLE
1047 | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
1048 &vreg->ctrl_reg);
1049
1050 vreg->save_uV = pm8058_smps_get_voltage_legacy(vreg);
1051
1052bail:
1053 return rc;
1054}
1055
1056static int pm8058_smps_set_voltage(struct regulator_dev *dev,
1057 int min_uV, int max_uV, unsigned *selector)
1058{
1059 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060 int rc = 0;
1061
1062 if (min_uV < SMPS_UV_MIN || min_uV > SMPS_UV_MAX)
1063 return -EINVAL;
1064
1065 if (SMPS_IN_ADVANCED_MODE(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301066 rc = pm8058_smps_set_voltage_advanced(vreg, min_uV, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 else
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301068 rc = pm8058_smps_set_voltage_legacy(vreg, min_uV);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069
1070 if (rc)
1071 print_write_error(vreg, rc, __func__);
1072
1073 return rc;
1074}
1075
1076static int pm8058_ncp_set_voltage(struct regulator_dev *dev,
1077 int min_uV, int max_uV, unsigned *selector)
1078{
1079 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 int rc;
1081 u8 val;
1082
1083 if (min_uV < NCP_UV_MIN || min_uV > NCP_UV_MAX)
1084 return -EINVAL;
1085
1086 val = (min_uV - NCP_UV_MIN) / NCP_UV_STEP;
1087
1088 /* voltage setting */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301089 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, NCP_VPROG_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 &vreg->ctrl_reg);
1091 if (rc)
1092 print_write_error(vreg, rc, __func__);
1093
1094 return rc;
1095}
1096
1097static int pm8058_ncp_get_voltage(struct regulator_dev *dev)
1098{
1099 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1100 u8 vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
1101 return NCP_UV_MIN + vprog * NCP_UV_STEP;
1102}
1103
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301104static int pm8058_ldo_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105{
1106 int rc = 0;
1107 u8 mask, val;
1108
1109 switch (mode) {
1110 case REGULATOR_MODE_FAST:
1111 /* HPM */
1112 val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
1113 | LDO_CTRL_PM_HPM;
1114 mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301115 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 &vreg->ctrl_reg);
1117 if (rc)
1118 goto bail;
1119
1120 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301121 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122 if (rc)
1123 goto bail;
1124 break;
1125
1126 case REGULATOR_MODE_STANDBY:
1127 /* LPM */
1128 val = (_pm8058_vreg_is_enabled(vreg) ? LDO_ENABLE : 0)
1129 | LDO_CTRL_PM_LPM;
1130 mask = LDO_ENABLE_MASK | LDO_CTRL_PM_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301131 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 &vreg->ctrl_reg);
1133 if (rc)
1134 goto bail;
1135
1136 val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
1137 | REGULATOR_BANK_SEL(0);
1138 mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301139 rc = pm8058_vreg_write(vreg, vreg->test_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 &vreg->test_reg[0]);
1141 if (rc)
1142 goto bail;
1143
1144 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301145 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 if (rc)
1147 goto bail;
1148 break;
1149
1150 case REGULATOR_MODE_IDLE:
1151 /* Pin Control */
1152 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301153 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 if (rc)
1155 goto bail;
1156 break;
1157
1158 default:
1159 pr_err("%s: invalid mode: %u\n", __func__, mode);
1160 return -EINVAL;
1161 }
1162
1163bail:
1164 if (rc)
1165 print_write_error(vreg, rc, __func__);
1166
1167 return rc;
1168}
1169
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301170static int pm8058_smps_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171{
1172 int rc = 0;
1173 u8 mask, val;
1174
1175 switch (mode) {
1176 case REGULATOR_MODE_FAST:
1177 /* HPM */
1178 val = SMPS_CLK_CTRL_PWM;
1179 mask = SMPS_CLK_CTRL_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301180 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 &vreg->clk_ctrl_reg);
1182 if (rc)
1183 goto bail;
1184
1185 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301186 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187 if (rc)
1188 goto bail;
1189 break;
1190
1191 case REGULATOR_MODE_STANDBY:
1192 /* LPM */
1193 val = SMPS_CLK_CTRL_PFM;
1194 mask = SMPS_CLK_CTRL_MASK;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301195 rc = pm8058_vreg_write(vreg, vreg->clk_ctrl_addr, val, mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 &vreg->clk_ctrl_reg);
1197 if (rc)
1198 goto bail;
1199
1200 if (pm8058_vreg_using_pin_ctrl(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301201 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 if (rc)
1203 goto bail;
1204 break;
1205
1206 case REGULATOR_MODE_IDLE:
1207 /* Pin Control */
1208 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301209 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 if (rc)
1211 goto bail;
1212 break;
1213
1214 default:
1215 pr_err("%s: invalid mode: %u\n", __func__, mode);
1216 return -EINVAL;
1217 }
1218
1219bail:
1220 if (rc)
1221 print_write_error(vreg, rc, __func__);
1222
1223 return rc;
1224}
1225
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301226static int pm8058_lvs_set_mode(struct pm8058_vreg *vreg, unsigned int mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227{
1228 int rc = 0;
1229
1230 if (mode == REGULATOR_MODE_IDLE) {
1231 /* Use pin control. */
1232 if (_pm8058_vreg_is_enabled(vreg))
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301233 rc = pm8058_vreg_set_pin_ctrl(vreg, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234 } else {
1235 /* Turn off pin control. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301236 rc = pm8058_vreg_set_pin_ctrl(vreg, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237 }
1238
1239 return rc;
1240}
1241
1242/*
1243 * Optimum mode programming:
1244 * REGULATOR_MODE_FAST: Go to HPM (highest priority)
1245 * REGULATOR_MODE_STANDBY: Go to pin ctrl mode if there are any pin ctrl
1246 * votes, else go to LPM
1247 *
1248 * Pin ctrl mode voting via regulator set_mode:
1249 * REGULATOR_MODE_IDLE: Go to pin ctrl mode if the optimum mode is LPM, else
1250 * go to HPM
1251 * REGULATOR_MODE_NORMAL: Go to LPM if it is the optimum mode, else go to HPM
1252 */
1253static int pm8058_vreg_set_mode(struct regulator_dev *dev, unsigned int mode)
1254{
1255 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 unsigned prev_optimum = vreg->optimum;
1257 unsigned prev_pc_vote = vreg->pc_vote;
1258 unsigned prev_mode_initialized = vreg->mode_initialized;
1259 int new_mode = REGULATOR_MODE_FAST;
1260 int rc = 0;
1261
1262 /* Determine new mode to go into. */
1263 switch (mode) {
1264 case REGULATOR_MODE_FAST:
1265 new_mode = REGULATOR_MODE_FAST;
1266 vreg->optimum = mode;
1267 vreg->mode_initialized = 1;
1268 break;
1269
1270 case REGULATOR_MODE_STANDBY:
1271 if (vreg->pc_vote)
1272 new_mode = REGULATOR_MODE_IDLE;
1273 else
1274 new_mode = REGULATOR_MODE_STANDBY;
1275 vreg->optimum = mode;
1276 vreg->mode_initialized = 1;
1277 break;
1278
1279 case REGULATOR_MODE_IDLE:
1280 if (vreg->pc_vote++)
1281 goto done; /* already taken care of */
1282
1283 if (vreg->mode_initialized
1284 && vreg->optimum == REGULATOR_MODE_FAST)
1285 new_mode = REGULATOR_MODE_FAST;
1286 else
1287 new_mode = REGULATOR_MODE_IDLE;
1288 break;
1289
1290 case REGULATOR_MODE_NORMAL:
1291 if (vreg->pc_vote && --(vreg->pc_vote))
1292 goto done; /* already taken care of */
1293
1294 if (vreg->optimum == REGULATOR_MODE_STANDBY)
1295 new_mode = REGULATOR_MODE_STANDBY;
1296 else
1297 new_mode = REGULATOR_MODE_FAST;
1298 break;
1299
1300 default:
1301 pr_err("%s: unknown mode, mode=%u\n", __func__, mode);
1302 return -EINVAL;
1303 }
1304
1305 switch (vreg->type) {
1306 case REGULATOR_TYPE_LDO:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301307 rc = pm8058_ldo_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 break;
1309 case REGULATOR_TYPE_SMPS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301310 rc = pm8058_smps_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 break;
1312 case REGULATOR_TYPE_LVS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301313 rc = pm8058_lvs_set_mode(vreg, new_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 break;
1315 }
1316
1317 if (rc) {
1318 print_write_error(vreg, rc, __func__);
1319 vreg->mode_initialized = prev_mode_initialized;
1320 vreg->optimum = prev_optimum;
1321 vreg->pc_vote = prev_pc_vote;
1322 return rc;
1323 }
1324
1325done:
1326 return 0;
1327}
1328
1329static unsigned int pm8058_vreg_get_mode(struct regulator_dev *dev)
1330{
1331 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1332
1333 if (!vreg->mode_initialized && vreg->pc_vote)
1334 return REGULATOR_MODE_IDLE;
1335
1336 /* Check physical pin control state. */
1337 switch (vreg->type) {
1338 case REGULATOR_TYPE_LDO:
1339 if (!(vreg->ctrl_reg & LDO_ENABLE_MASK)
1340 && !pm8058_vreg_is_global_enabled(vreg)
1341 && (vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK))
1342 return REGULATOR_MODE_IDLE;
1343 else if (((vreg->ctrl_reg & LDO_ENABLE_MASK)
1344 || pm8058_vreg_is_global_enabled(vreg))
1345 && (vreg->ctrl_reg & LDO_CTRL_PM_MASK)
1346 && (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK))
1347 return REGULATOR_MODE_IDLE;
1348 break;
1349 case REGULATOR_TYPE_SMPS:
1350 if (!SMPS_IN_ADVANCED_MODE(vreg)
1351 && !(vreg->ctrl_reg & REGULATOR_EN_MASK)
1352 && !pm8058_vreg_is_global_enabled(vreg)
1353 && (vreg->sleep_ctrl_reg & SMPS_PIN_CTRL_MASK))
1354 return REGULATOR_MODE_IDLE;
1355 else if (!SMPS_IN_ADVANCED_MODE(vreg)
1356 && ((vreg->ctrl_reg & REGULATOR_EN_MASK)
1357 || pm8058_vreg_is_global_enabled(vreg))
1358 && ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
1359 == SMPS_CLK_CTRL_PFM)
1360 && (vreg->sleep_ctrl_reg & SMPS_PIN_CTRL_LPM_MASK))
1361 return REGULATOR_MODE_IDLE;
1362 break;
1363 case REGULATOR_TYPE_LVS:
1364 if (!(vreg->ctrl_reg & LVS_ENABLE_MASK)
1365 && !pm8058_vreg_is_global_enabled(vreg)
1366 && (vreg->ctrl_reg & LVS_PIN_CTRL_MASK))
1367 return REGULATOR_MODE_IDLE;
1368 }
1369
1370 if (vreg->optimum == REGULATOR_MODE_FAST)
1371 return REGULATOR_MODE_FAST;
1372 else if (vreg->pc_vote)
1373 return REGULATOR_MODE_IDLE;
1374 else if (vreg->optimum == REGULATOR_MODE_STANDBY)
1375 return REGULATOR_MODE_STANDBY;
1376 return REGULATOR_MODE_FAST;
1377}
1378
1379unsigned int pm8058_vreg_get_optimum_mode(struct regulator_dev *dev,
1380 int input_uV, int output_uV, int load_uA)
1381{
1382 struct pm8058_vreg *vreg = rdev_get_drvdata(dev);
1383
1384 if (load_uA <= 0) {
1385 /*
1386 * pm8058_vreg_get_optimum_mode is being called before consumers
1387 * have specified their load currents via
1388 * regulator_set_optimum_mode. Return whatever the existing mode
1389 * is.
1390 */
1391 return pm8058_vreg_get_mode(dev);
1392 }
1393
1394 if (load_uA >= vreg->hpm_min_load)
1395 return REGULATOR_MODE_FAST;
1396 return REGULATOR_MODE_STANDBY;
1397}
1398
1399static struct regulator_ops pm8058_ldo_ops = {
1400 .enable = pm8058_vreg_enable,
1401 .disable = pm8058_vreg_disable,
1402 .is_enabled = pm8058_vreg_is_enabled,
1403 .set_voltage = pm8058_ldo_set_voltage,
1404 .get_voltage = pm8058_ldo_get_voltage,
1405 .set_mode = pm8058_vreg_set_mode,
1406 .get_mode = pm8058_vreg_get_mode,
1407 .get_optimum_mode = pm8058_vreg_get_optimum_mode,
1408};
1409
1410static struct regulator_ops pm8058_smps_ops = {
1411 .enable = pm8058_vreg_enable,
1412 .disable = pm8058_vreg_disable,
1413 .is_enabled = pm8058_vreg_is_enabled,
1414 .set_voltage = pm8058_smps_set_voltage,
1415 .get_voltage = pm8058_smps_get_voltage,
1416 .set_mode = pm8058_vreg_set_mode,
1417 .get_mode = pm8058_vreg_get_mode,
1418 .get_optimum_mode = pm8058_vreg_get_optimum_mode,
1419};
1420
1421static struct regulator_ops pm8058_lvs_ops = {
1422 .enable = pm8058_vreg_enable,
1423 .disable = pm8058_vreg_disable,
1424 .is_enabled = pm8058_vreg_is_enabled,
1425 .set_mode = pm8058_vreg_set_mode,
1426 .get_mode = pm8058_vreg_get_mode,
1427};
1428
1429static struct regulator_ops pm8058_ncp_ops = {
1430 .enable = pm8058_vreg_enable,
1431 .disable = pm8058_vreg_disable,
1432 .is_enabled = pm8058_vreg_is_enabled,
1433 .set_voltage = pm8058_ncp_set_voltage,
1434 .get_voltage = pm8058_ncp_get_voltage,
1435};
1436
1437#define VREG_DESCRIP(_id, _name, _ops) \
1438 [_id] = { \
1439 .id = _id, \
1440 .name = _name, \
1441 .ops = _ops, \
1442 .type = REGULATOR_VOLTAGE, \
1443 .owner = THIS_MODULE, \
1444 }
1445
1446static struct regulator_desc pm8058_vreg_descrip[] = {
1447 VREG_DESCRIP(PM8058_VREG_ID_L0, "8058_l0", &pm8058_ldo_ops),
1448 VREG_DESCRIP(PM8058_VREG_ID_L1, "8058_l1", &pm8058_ldo_ops),
1449 VREG_DESCRIP(PM8058_VREG_ID_L2, "8058_l2", &pm8058_ldo_ops),
1450 VREG_DESCRIP(PM8058_VREG_ID_L3, "8058_l3", &pm8058_ldo_ops),
1451 VREG_DESCRIP(PM8058_VREG_ID_L4, "8058_l4", &pm8058_ldo_ops),
1452 VREG_DESCRIP(PM8058_VREG_ID_L5, "8058_l5", &pm8058_ldo_ops),
1453 VREG_DESCRIP(PM8058_VREG_ID_L6, "8058_l6", &pm8058_ldo_ops),
1454 VREG_DESCRIP(PM8058_VREG_ID_L7, "8058_l7", &pm8058_ldo_ops),
1455 VREG_DESCRIP(PM8058_VREG_ID_L8, "8058_l8", &pm8058_ldo_ops),
1456 VREG_DESCRIP(PM8058_VREG_ID_L9, "8058_l9", &pm8058_ldo_ops),
1457 VREG_DESCRIP(PM8058_VREG_ID_L10, "8058_l10", &pm8058_ldo_ops),
1458 VREG_DESCRIP(PM8058_VREG_ID_L11, "8058_l11", &pm8058_ldo_ops),
1459 VREG_DESCRIP(PM8058_VREG_ID_L12, "8058_l12", &pm8058_ldo_ops),
1460 VREG_DESCRIP(PM8058_VREG_ID_L13, "8058_l13", &pm8058_ldo_ops),
1461 VREG_DESCRIP(PM8058_VREG_ID_L14, "8058_l14", &pm8058_ldo_ops),
1462 VREG_DESCRIP(PM8058_VREG_ID_L15, "8058_l15", &pm8058_ldo_ops),
1463 VREG_DESCRIP(PM8058_VREG_ID_L16, "8058_l16", &pm8058_ldo_ops),
1464 VREG_DESCRIP(PM8058_VREG_ID_L17, "8058_l17", &pm8058_ldo_ops),
1465 VREG_DESCRIP(PM8058_VREG_ID_L18, "8058_l18", &pm8058_ldo_ops),
1466 VREG_DESCRIP(PM8058_VREG_ID_L19, "8058_l19", &pm8058_ldo_ops),
1467 VREG_DESCRIP(PM8058_VREG_ID_L20, "8058_l20", &pm8058_ldo_ops),
1468 VREG_DESCRIP(PM8058_VREG_ID_L21, "8058_l21", &pm8058_ldo_ops),
1469 VREG_DESCRIP(PM8058_VREG_ID_L22, "8058_l22", &pm8058_ldo_ops),
1470 VREG_DESCRIP(PM8058_VREG_ID_L23, "8058_l23", &pm8058_ldo_ops),
1471 VREG_DESCRIP(PM8058_VREG_ID_L24, "8058_l24", &pm8058_ldo_ops),
1472 VREG_DESCRIP(PM8058_VREG_ID_L25, "8058_l25", &pm8058_ldo_ops),
1473
1474 VREG_DESCRIP(PM8058_VREG_ID_S0, "8058_s0", &pm8058_smps_ops),
1475 VREG_DESCRIP(PM8058_VREG_ID_S1, "8058_s1", &pm8058_smps_ops),
1476 VREG_DESCRIP(PM8058_VREG_ID_S2, "8058_s2", &pm8058_smps_ops),
1477 VREG_DESCRIP(PM8058_VREG_ID_S3, "8058_s3", &pm8058_smps_ops),
1478 VREG_DESCRIP(PM8058_VREG_ID_S4, "8058_s4", &pm8058_smps_ops),
1479
1480 VREG_DESCRIP(PM8058_VREG_ID_LVS0, "8058_lvs0", &pm8058_lvs_ops),
1481 VREG_DESCRIP(PM8058_VREG_ID_LVS1, "8058_lvs1", &pm8058_lvs_ops),
1482
1483 VREG_DESCRIP(PM8058_VREG_ID_NCP, "8058_ncp", &pm8058_ncp_ops),
1484};
1485
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301486static int pm8058_master_enable_init(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487{
1488 int rc = 0, i;
1489
1490 for (i = 0; i < MASTER_ENABLE_COUNT; i++) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301491 rc = pm8xxx_readb(vreg->dev->parent, m_en[i].addr,
1492 &(m_en[i].reg));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 if (rc)
1494 goto bail;
1495 }
1496
1497bail:
1498 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301499 pr_err("%s: pm8xxx_read failed, rc=%d\n", __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500
1501 return rc;
1502}
1503
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301504static int pm8058_init_ldo(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505{
1506 int rc = 0, i;
1507 u8 bank;
1508
1509 /* Save the current test register state. */
1510 for (i = 0; i < LDO_TEST_BANKS; i++) {
1511 bank = REGULATOR_BANK_SEL(i);
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301512 rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 if (rc)
1514 goto bail;
1515
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301516 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1517 &vreg->test_reg[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 if (rc)
1519 goto bail;
1520 vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
1521 }
1522
1523 if ((vreg->ctrl_reg & LDO_CTRL_PM_MASK) == LDO_CTRL_PM_LPM)
1524 vreg->optimum = REGULATOR_MODE_STANDBY;
1525 else
1526 vreg->optimum = REGULATOR_MODE_FAST;
1527
1528 /* Set pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301529 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 (vreg->pdata->pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
1531 LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
1532bail:
1533 return rc;
1534}
1535
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301536static int pm8058_init_smps(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537{
1538 int rc = 0, i;
1539 u8 bank;
1540
1541 /* Save the current test2 register state. */
1542 for (i = 0; i < SMPS_TEST_BANKS; i++) {
1543 bank = REGULATOR_BANK_SEL(i);
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301544 rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 if (rc)
1546 goto bail;
1547
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301548 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1549 &vreg->test_reg[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 if (rc)
1551 goto bail;
1552 vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
1553 }
1554
1555 /* Save the current clock control register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301556 rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
1557 &vreg->clk_ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 if (rc)
1559 goto bail;
1560
1561 /* Save the current sleep control register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301562 rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
1563 &vreg->sleep_ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 if (rc)
1565 goto bail;
1566
1567 vreg->save_uV = 1; /* This is not a no-op. */
1568 vreg->save_uV = _pm8058_smps_get_voltage(vreg);
1569
1570 if ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK) == SMPS_CLK_CTRL_PFM)
1571 vreg->optimum = REGULATOR_MODE_STANDBY;
1572 else
1573 vreg->optimum = REGULATOR_MODE_FAST;
1574
1575 /* Set advanced mode pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301576 rc = pm8058_vreg_write(vreg, vreg->test_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 (vreg->pdata->pull_down_enable
1578 ? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
1579 | REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
1580 REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
1581 &vreg->test_reg[6]);
1582 if (rc)
1583 goto bail;
1584
1585 if (!SMPS_IN_ADVANCED_MODE(vreg)) {
1586 /* Set legacy mode pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301587 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 (vreg->pdata->pull_down_enable
1589 ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
1590 SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
1591 if (rc)
1592 goto bail;
1593 }
1594
1595bail:
1596 return rc;
1597}
1598
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301599static int pm8058_init_lvs(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600{
1601 int rc = 0;
1602
1603 vreg->optimum = REGULATOR_MODE_FAST;
1604
1605 /* Set pull down enable based on platform data. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301606 rc = pm8058_vreg_write(vreg, vreg->ctrl_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 (vreg->pdata->pull_down_enable
1608 ? LVS_PULL_DOWN_ENABLE : LVS_PULL_DOWN_DISABLE),
1609 LVS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
1610 return rc;
1611}
1612
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301613static int pm8058_init_ncp(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614{
1615 int rc = 0;
1616
1617 /* Save the current test1 register state. */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301618 rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
1619 &vreg->test_reg[0]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 if (rc)
1621 goto bail;
1622
1623 vreg->optimum = REGULATOR_MODE_FAST;
1624
1625bail:
1626 return rc;
1627}
1628
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301629static int pm8058_init_regulator(struct pm8058_vreg *vreg)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630{
1631 static int master_enable_inited;
1632 int rc = 0;
1633
1634 vreg->mode_initialized = 0;
1635
1636 if (!master_enable_inited) {
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301637 rc = pm8058_master_enable_init(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 if (!rc)
1639 master_enable_inited = 1;
1640 }
1641
1642 /* save the current control register state */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301643 rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 if (rc)
1645 goto bail;
1646
1647 switch (vreg->type) {
1648 case REGULATOR_TYPE_LDO:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301649 rc = pm8058_init_ldo(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650 break;
1651 case REGULATOR_TYPE_SMPS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301652 rc = pm8058_init_smps(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 break;
1654 case REGULATOR_TYPE_LVS:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301655 rc = pm8058_init_lvs(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656 break;
1657 case REGULATOR_TYPE_NCP:
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301658 rc = pm8058_init_ncp(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 break;
1660 }
1661
1662bail:
1663 if (rc)
1664 pr_err("%s: pm8058_read/write failed; initial register states "
1665 "unknown, rc=%d\n", __func__, rc);
1666 return rc;
1667}
1668
1669static int __devinit pm8058_vreg_probe(struct platform_device *pdev)
1670{
1671 struct regulator_desc *rdesc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 struct pm8058_vreg *vreg;
1673 const char *reg_name = NULL;
1674 int rc = 0;
1675
1676 if (pdev == NULL)
1677 return -EINVAL;
1678
1679 if (pdev->id >= 0 && pdev->id < PM8058_VREG_MAX) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 rdesc = &pm8058_vreg_descrip[pdev->id];
1681 vreg = &pm8058_vreg[pdev->id];
1682 vreg->pdata = pdev->dev.platform_data;
1683 reg_name = pm8058_vreg_descrip[pdev->id].name;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301684 vreg->dev = &pdev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001685
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301686 rc = pm8058_init_regulator(vreg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 if (rc)
1688 goto bail;
1689
1690 /* Disallow idle and normal modes if pin control isn't set. */
1691 if (vreg->pdata->pin_ctrl == 0)
1692 vreg->pdata->init_data.constraints.valid_modes_mask
1693 &= ~(REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE);
1694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 vreg->rdev = regulator_register(rdesc, &pdev->dev,
Rajendra Nayak11eafc62011-11-18 16:47:19 +05301696 &vreg->pdata->init_data, vreg, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 if (IS_ERR(vreg->rdev)) {
1698 rc = PTR_ERR(vreg->rdev);
1699 pr_err("%s: regulator_register failed for %s, rc=%d\n",
1700 __func__, reg_name, rc);
1701 }
1702 } else {
1703 rc = -ENODEV;
1704 }
1705
1706bail:
1707 if (rc)
1708 pr_err("%s: error for %s, rc=%d\n", __func__, reg_name, rc);
1709
1710 return rc;
1711}
1712
1713static int __devexit pm8058_vreg_remove(struct platform_device *pdev)
1714{
1715 regulator_unregister(pm8058_vreg[pdev->id].rdev);
1716 return 0;
1717}
1718
1719static struct platform_driver pm8058_vreg_driver = {
1720 .probe = pm8058_vreg_probe,
1721 .remove = __devexit_p(pm8058_vreg_remove),
1722 .driver = {
1723 .name = "pm8058-regulator",
1724 .owner = THIS_MODULE,
1725 },
1726};
1727
1728static int __init pm8058_vreg_init(void)
1729{
1730 return platform_driver_register(&pm8058_vreg_driver);
1731}
1732
1733static void __exit pm8058_vreg_exit(void)
1734{
1735 platform_driver_unregister(&pm8058_vreg_driver);
1736}
1737
1738static void print_write_error(struct pm8058_vreg *vreg, int rc,
1739 const char *func)
1740{
1741 const char *reg_name = NULL;
1742 ptrdiff_t id = vreg - pm8058_vreg;
1743
1744 if (id >= 0 && id < PM8058_VREG_MAX)
1745 reg_name = pm8058_vreg_descrip[id].name;
1746 pr_err("%s: pm8058_vreg_write failed for %s, rc=%d\n",
1747 func, reg_name, rc);
1748}
1749
1750subsys_initcall(pm8058_vreg_init);
1751module_exit(pm8058_vreg_exit);
1752
1753MODULE_LICENSE("GPL v2");
1754MODULE_DESCRIPTION("PMIC8058 regulator driver");
1755MODULE_VERSION("1.0");
1756MODULE_ALIAS("platform:pm8058-regulator");