blob: 0f94a833934e208c55aa92f8fb3f0137b0909cbb [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/slab.h>
18#include <linux/spinlock.h>
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +053019#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020#include <linux/platform_device.h>
21#include <linux/mfd/pm8xxx/core.h>
22#include <linux/mfd/pm8xxx/misc.h>
23
24/* PON CTRL 1 register */
Anirudh Ghayala23c1ca2011-11-01 14:36:24 +053025#define REG_PM8XXX_PON_CTRL_1 0x01C
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026
27#define PON_CTRL_1_PULL_UP_MASK 0xE0
28#define PON_CTRL_1_USB_PWR_EN 0x10
29
30#define PON_CTRL_1_WD_EN_MASK 0x08
31#define PON_CTRL_1_WD_EN_RESET 0x08
32#define PON_CTRL_1_WD_EN_PWR_OFF 0x00
33
Anirudh Ghayala4262a32011-11-10 00:02:18 +053034/* PON CNTL registers */
35#define REG_PM8058_PON_CNTL_4 0x098
36#define REG_PM8901_PON_CNTL_4 0x099
37#define REG_PM8018_PON_CNTL_4 0x01E
38#define REG_PM8921_PON_CNTL_4 0x01E
39#define REG_PM8058_PON_CNTL_5 0x07B
40#define REG_PM8901_PON_CNTL_5 0x09A
41#define REG_PM8018_PON_CNTL_5 0x01F
42#define REG_PM8921_PON_CNTL_5 0x01F
43
44#define PON_CTRL_4_RESET_EN_MASK 0x01
45#define PON_CTRL_4_SHUTDOWN_ON_RESET 0x0
46#define PON_CTRL_4_RESTART_ON_RESET 0x1
47#define PON_CTRL_5_HARD_RESET_EN_MASK 0x08
48#define PON_CTRL_5_HARD_RESET_EN 0x08
49#define PON_CTRL_5_HARD_RESET_DIS 0x00
50
Anirudh Ghayal9e1bd642011-11-01 13:57:40 +053051/* Regulator master enable addresses */
52#define REG_PM8058_VREG_EN_MSM 0x018
53#define REG_PM8058_VREG_EN_GRP_5_4 0x1C8
54
55/* Regulator control registers for shutdown/reset */
56#define REG_PM8058_S0_CTRL 0x004
57#define REG_PM8058_S1_CTRL 0x005
58#define REG_PM8058_S3_CTRL 0x111
59#define REG_PM8058_L21_CTRL 0x120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#define REG_PM8058_L22_CTRL 0x121
61
Anirudh Ghayal9e1bd642011-11-01 13:57:40 +053062#define PM8058_REGULATOR_ENABLE_MASK 0x80
63#define PM8058_REGULATOR_ENABLE 0x80
64#define PM8058_REGULATOR_DISABLE 0x00
65#define PM8058_REGULATOR_PULL_DOWN_MASK 0x40
66#define PM8058_REGULATOR_PULL_DOWN_EN 0x40
67
68/* Buck CTRL register */
69#define PM8058_SMPS_LEGACY_VREF_SEL 0x20
70#define PM8058_SMPS_LEGACY_VPROG_MASK 0x1F
71#define PM8058_SMPS_ADVANCED_BAND_MASK 0xC0
72#define PM8058_SMPS_ADVANCED_BAND_SHIFT 6
73#define PM8058_SMPS_ADVANCED_VPROG_MASK 0x3F
74
75/* Buck TEST2 registers for shutdown/reset */
76#define REG_PM8058_S0_TEST2 0x084
77#define REG_PM8058_S1_TEST2 0x085
78#define REG_PM8058_S3_TEST2 0x11A
79
80#define PM8058_REGULATOR_BANK_WRITE 0x80
81#define PM8058_REGULATOR_BANK_MASK 0x70
82#define PM8058_REGULATOR_BANK_SHIFT 4
83#define PM8058_REGULATOR_BANK_SEL(n) ((n) << PM8058_REGULATOR_BANK_SHIFT)
84
85/* Buck TEST2 register bank 1 */
86#define PM8058_SMPS_LEGACY_VLOW_SEL 0x01
87
88/* Buck TEST2 register bank 7 */
89#define PM8058_SMPS_ADVANCED_MODE_MASK 0x02
90#define PM8058_SMPS_ADVANCED_MODE 0x02
91#define PM8058_SMPS_LEGACY_MODE 0x00
92
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093/* SLEEP CTRL register */
94#define REG_PM8058_SLEEP_CTRL 0x02B
95#define REG_PM8921_SLEEP_CTRL 0x10A
Jay Chokshi86580f22011-10-17 12:27:52 -070096#define REG_PM8018_SLEEP_CTRL 0x10A
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097
98#define SLEEP_CTRL_SMPL_EN_MASK 0x04
99#define SLEEP_CTRL_SMPL_EN_RESET 0x04
100#define SLEEP_CTRL_SMPL_EN_PWR_OFF 0x00
101
Anirudh Ghayalbfbaf822011-11-01 14:28:34 +0530102#define SLEEP_CTRL_SMPL_SEL_MASK 0x03
103#define SLEEP_CTRL_SMPL_SEL_MIN 0
104#define SLEEP_CTRL_SMPL_SEL_MAX 3
105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106/* FTS regulator PMR registers */
107#define REG_PM8901_REGULATOR_S1_PMR 0xA7
108#define REG_PM8901_REGULATOR_S2_PMR 0xA8
109#define REG_PM8901_REGULATOR_S3_PMR 0xA9
110#define REG_PM8901_REGULATOR_S4_PMR 0xAA
111
112#define PM8901_REGULATOR_PMR_STATE_MASK 0x60
113#define PM8901_REGULATOR_PMR_STATE_OFF 0x20
114
Anirudh Ghayal7b382292011-11-01 14:08:34 +0530115/* COINCELL CHG registers */
116#define REG_PM8058_COIN_CHG 0x02F
117#define REG_PM8921_COIN_CHG 0x09C
118#define REG_PM8018_COIN_CHG 0x09C
119
120#define COINCELL_RESISTOR_SHIFT 0x2
121
Anirudh Ghayal5213eb82011-10-24 14:44:58 +0530122/* GPIO UART MUX CTRL registers */
123#define REG_PM8XXX_GPIO_MUX_CTRL 0x1CC
124
125#define UART_PATH_SEL_MASK 0x60
126#define UART_PATH_SEL_SHIFT 0x5
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128struct pm8xxx_misc_chip {
129 struct list_head link;
130 struct pm8xxx_misc_platform_data pdata;
131 struct device *dev;
132 enum pm8xxx_version version;
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530133 u64 osc_halt_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134};
135
136static LIST_HEAD(pm8xxx_misc_chips);
137static DEFINE_SPINLOCK(pm8xxx_misc_chips_lock);
138
139static int pm8xxx_misc_masked_write(struct pm8xxx_misc_chip *chip, u16 addr,
140 u8 mask, u8 val)
141{
142 int rc;
143 u8 reg;
144
145 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
146 if (rc) {
147 pr_err("pm8xxx_readb(0x%03X) failed, rc=%d\n", addr, rc);
148 return rc;
149 }
150 reg &= ~mask;
151 reg |= val & mask;
152 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
153 if (rc)
154 pr_err("pm8xxx_writeb(0x%03X)=0x%02X failed, rc=%d\n", addr,
155 reg, rc);
156 return rc;
157}
158
Anirudh Ghayal9e1bd642011-11-01 13:57:40 +0530159/*
160 * Set an SMPS regulator to be disabled in its CTRL register, but enabled
161 * in the master enable register. Also set it's pull down enable bit.
162 * Take care to make sure that the output voltage doesn't change if switching
163 * from advanced mode to legacy mode.
164 */
165static int
166__pm8058_disable_smps_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
167 u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr,
168 u8 master_enable_bit)
169{
170 int rc = 0;
171 u8 vref_sel, vlow_sel, band, vprog, bank, reg;
172
173 bank = PM8058_REGULATOR_BANK_SEL(7);
174 rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
175 if (rc) {
176 pr_err("%s: pm8xxx_writeb(0x%03X) failed: rc=%d\n", __func__,
177 test2_addr, rc);
178 goto done;
179 }
180
181 rc = pm8xxx_readb(chip->dev->parent, test2_addr, &reg);
182 if (rc) {
183 pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
184 __func__, test2_addr, rc);
185 goto done;
186 }
187
188 /* Check if in advanced mode. */
189 if ((reg & PM8058_SMPS_ADVANCED_MODE_MASK) ==
190 PM8058_SMPS_ADVANCED_MODE) {
191 /* Determine current output voltage. */
192 rc = pm8xxx_readb(chip->dev->parent, ctrl_addr, &reg);
193 if (rc) {
194 pr_err("%s: FAIL pm8xxx_readb(0x%03X): rc=%d\n",
195 __func__, ctrl_addr, rc);
196 goto done;
197 }
198
199 band = (reg & PM8058_SMPS_ADVANCED_BAND_MASK)
200 >> PM8058_SMPS_ADVANCED_BAND_SHIFT;
201 switch (band) {
202 case 3:
203 vref_sel = 0;
204 vlow_sel = 0;
205 break;
206 case 2:
207 vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
208 vlow_sel = 0;
209 break;
210 case 1:
211 vref_sel = PM8058_SMPS_LEGACY_VREF_SEL;
212 vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL;
213 break;
214 default:
215 pr_err("%s: regulator already disabled\n", __func__);
216 return -EPERM;
217 }
218 vprog = (reg & PM8058_SMPS_ADVANCED_VPROG_MASK);
219 /* Round up if fine step is in use. */
220 vprog = (vprog + 1) >> 1;
221 if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK)
222 vprog = PM8058_SMPS_LEGACY_VPROG_MASK;
223
224 /* Set VLOW_SEL bit. */
225 bank = PM8058_REGULATOR_BANK_SEL(1);
226 rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
227 if (rc) {
228 pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
229 __func__, test2_addr, rc);
230 goto done;
231 }
232
233 rc = pm8xxx_misc_masked_write(chip, test2_addr,
234 PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK
235 | PM8058_SMPS_LEGACY_VLOW_SEL,
236 PM8058_REGULATOR_BANK_WRITE |
237 PM8058_REGULATOR_BANK_SEL(1) | vlow_sel);
238 if (rc)
239 goto done;
240
241 /* Switch to legacy mode */
242 bank = PM8058_REGULATOR_BANK_SEL(7);
243 rc = pm8xxx_writeb(chip->dev->parent, test2_addr, bank);
244 if (rc) {
245 pr_err("%s: FAIL pm8xxx_writeb(0x%03X): rc=%d\n",
246 __func__, test2_addr, rc);
247 goto done;
248 }
249 rc = pm8xxx_misc_masked_write(chip, test2_addr,
250 PM8058_REGULATOR_BANK_WRITE |
251 PM8058_REGULATOR_BANK_MASK |
252 PM8058_SMPS_ADVANCED_MODE_MASK,
253 PM8058_REGULATOR_BANK_WRITE |
254 PM8058_REGULATOR_BANK_SEL(7) |
255 PM8058_SMPS_LEGACY_MODE);
256 if (rc)
257 goto done;
258
259 /* Enable locally, enable pull down, keep voltage the same. */
260 rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
261 PM8058_REGULATOR_ENABLE_MASK |
262 PM8058_REGULATOR_PULL_DOWN_MASK |
263 PM8058_SMPS_LEGACY_VREF_SEL |
264 PM8058_SMPS_LEGACY_VPROG_MASK,
265 PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN
266 | vref_sel | vprog);
267 if (rc)
268 goto done;
269 }
270
271 /* Enable in master control register. */
272 rc = pm8xxx_misc_masked_write(chip, master_enable_addr,
273 master_enable_bit, master_enable_bit);
274 if (rc)
275 goto done;
276
277 /* Disable locally and enable pull down. */
278 rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
279 PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK,
280 PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN);
281
282done:
283 return rc;
284}
285
286static int
287__pm8058_disable_ldo_locally_set_pull_down(struct pm8xxx_misc_chip *chip,
288 u16 ctrl_addr, u16 master_enable_addr, u8 master_enable_bit)
289{
290 int rc;
291
292 /* Enable LDO in master control register. */
293 rc = pm8xxx_misc_masked_write(chip, master_enable_addr,
294 master_enable_bit, master_enable_bit);
295 if (rc)
296 goto done;
297
298 /* Disable LDO in CTRL register and set pull down */
299 rc = pm8xxx_misc_masked_write(chip, ctrl_addr,
300 PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK,
301 PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN);
302
303done:
304 return rc;
305}
306
Jay Chokshi86580f22011-10-17 12:27:52 -0700307static int __pm8018_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
308{
309 int rc;
310
311 /* Enable SMPL if resetting is desired. */
312 rc = pm8xxx_misc_masked_write(chip, REG_PM8018_SLEEP_CTRL,
313 SLEEP_CTRL_SMPL_EN_MASK,
314 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
315 if (rc) {
316 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
317 return rc;
318 }
319
320 /*
321 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
322 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
323 * USB charging is enabled.
324 */
Anirudh Ghayala23c1ca2011-11-01 14:36:24 +0530325 rc = pm8xxx_misc_masked_write(chip, REG_PM8XXX_PON_CTRL_1,
Jay Chokshi86580f22011-10-17 12:27:52 -0700326 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
327 | PON_CTRL_1_WD_EN_MASK,
328 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
329 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
330 if (rc)
331 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
332
333 return rc;
334}
335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700336static int __pm8058_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
337{
338 int rc;
339
Anirudh Ghayal9e1bd642011-11-01 13:57:40 +0530340 /* When shutting down, enable active pulldowns on important rails. */
341 if (!reset) {
342 /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */
343 __pm8058_disable_smps_locally_set_pull_down(chip,
344 REG_PM8058_S0_CTRL, REG_PM8058_S0_TEST2,
345 REG_PM8058_VREG_EN_MSM, BIT(7));
346 __pm8058_disable_smps_locally_set_pull_down(chip,
347 REG_PM8058_S1_CTRL, REG_PM8058_S1_TEST2,
348 REG_PM8058_VREG_EN_MSM, BIT(6));
349 __pm8058_disable_smps_locally_set_pull_down(chip,
350 REG_PM8058_S3_CTRL, REG_PM8058_S3_TEST2,
351 REG_PM8058_VREG_EN_GRP_5_4, BIT(7) | BIT(4));
352 /* Disable LDO 21 locally and set pulldown enable bit. */
353 __pm8058_disable_ldo_locally_set_pull_down(chip,
354 REG_PM8058_L21_CTRL, REG_PM8058_VREG_EN_GRP_5_4,
355 BIT(1));
356 }
357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 /*
359 * Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its
360 * pull-down state intact. This ensures a safe shutdown.
361 */
362 rc = pm8xxx_misc_masked_write(chip, REG_PM8058_L22_CTRL, 0xBF, 0x93);
363 if (rc) {
364 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
365 goto read_write_err;
366 }
367
368 /* Enable SMPL if resetting is desired. */
369 rc = pm8xxx_misc_masked_write(chip, REG_PM8058_SLEEP_CTRL,
370 SLEEP_CTRL_SMPL_EN_MASK,
371 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
372 if (rc) {
373 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
374 goto read_write_err;
375 }
376
377 /*
378 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
379 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
380 * USB charging is enabled.
381 */
Anirudh Ghayala23c1ca2011-11-01 14:36:24 +0530382 rc = pm8xxx_misc_masked_write(chip, REG_PM8XXX_PON_CTRL_1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
384 | PON_CTRL_1_WD_EN_MASK,
385 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
386 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
387 if (rc) {
388 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
389 goto read_write_err;
390 }
391
392read_write_err:
393 return rc;
394}
395
396static int __pm8901_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
397{
398 int rc = 0, i;
399 u8 pmr_addr[4] = {
400 REG_PM8901_REGULATOR_S2_PMR,
401 REG_PM8901_REGULATOR_S3_PMR,
402 REG_PM8901_REGULATOR_S4_PMR,
403 REG_PM8901_REGULATOR_S1_PMR,
404 };
405
406 /* Fix-up: Turn off regulators S1, S2, S3, S4 when shutting down. */
407 if (!reset) {
408 for (i = 0; i < 4; i++) {
409 rc = pm8xxx_misc_masked_write(chip, pmr_addr[i],
410 PM8901_REGULATOR_PMR_STATE_MASK,
411 PM8901_REGULATOR_PMR_STATE_OFF);
412 if (rc) {
413 pr_err("pm8xxx_misc_masked_write failed, "
414 "rc=%d\n", rc);
415 goto read_write_err;
416 }
417 }
418 }
419
420read_write_err:
421 return rc;
422}
423
424static int __pm8921_reset_pwr_off(struct pm8xxx_misc_chip *chip, int reset)
425{
426 int rc;
427
428 /* Enable SMPL if resetting is desired. */
429 rc = pm8xxx_misc_masked_write(chip, REG_PM8921_SLEEP_CTRL,
430 SLEEP_CTRL_SMPL_EN_MASK,
431 (reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
432 if (rc) {
433 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
434 goto read_write_err;
435 }
436
437 /*
438 * Select action to perform (reset or shutdown) when PS_HOLD goes low.
439 * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
440 * USB charging is enabled.
441 */
Anirudh Ghayala23c1ca2011-11-01 14:36:24 +0530442 rc = pm8xxx_misc_masked_write(chip, REG_PM8XXX_PON_CTRL_1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
444 | PON_CTRL_1_WD_EN_MASK,
445 PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
446 | (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
447 if (rc) {
448 pr_err("pm8xxx_misc_masked_write failed, rc=%d\n", rc);
449 goto read_write_err;
450 }
451
452read_write_err:
453 return rc;
454}
455
456/**
457 * pm8xxx_reset_pwr_off - switch all PM8XXX PMIC chips attached to the system to
458 * either reset or shutdown when they are turned off
459 * @reset: 0 = shudown the PMICs, 1 = shutdown and then restart the PMICs
460 *
461 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
462 */
463int pm8xxx_reset_pwr_off(int reset)
464{
465 struct pm8xxx_misc_chip *chip;
466 unsigned long flags;
467 int rc = 0;
468
469 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
470
471 /* Loop over all attached PMICs and call specific functions for them. */
472 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
473 switch (chip->version) {
Jay Chokshi86580f22011-10-17 12:27:52 -0700474 case PM8XXX_VERSION_8018:
475 rc = __pm8018_reset_pwr_off(chip, reset);
476 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 case PM8XXX_VERSION_8058:
478 rc = __pm8058_reset_pwr_off(chip, reset);
479 break;
480 case PM8XXX_VERSION_8901:
481 rc = __pm8901_reset_pwr_off(chip, reset);
482 break;
483 case PM8XXX_VERSION_8921:
484 rc = __pm8921_reset_pwr_off(chip, reset);
485 break;
486 default:
487 /* PMIC doesn't have reset_pwr_off; do nothing. */
488 break;
489 }
490 if (rc) {
491 pr_err("reset_pwr_off failed, rc=%d\n", rc);
492 break;
493 }
494 }
495
496 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
497
498 return rc;
499}
500EXPORT_SYMBOL_GPL(pm8xxx_reset_pwr_off);
501
Anirudh Ghayal7b382292011-11-01 14:08:34 +0530502/**
Anirudh Ghayalbfbaf822011-11-01 14:28:34 +0530503 * pm8xxx_smpl_control - enables/disables SMPL detection
504 * @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
505 *
506 * This function enables or disables the Sudden Momentary Power Loss detection
507 * module. If SMPL detection is enabled, then when a sufficiently long power
508 * loss event occurs, the PMIC will automatically reset itself. If SMPL
509 * detection is disabled, then the PMIC will shutdown when power loss occurs.
510 *
511 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
512 */
513int pm8xxx_smpl_control(int enable)
514{
515 struct pm8xxx_misc_chip *chip;
516 unsigned long flags;
517 int rc = 0;
518
519 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
520
521 /* Loop over all attached PMICs and call specific functions for them. */
522 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
523 switch (chip->version) {
524 case PM8XXX_VERSION_8018:
525 rc = pm8xxx_misc_masked_write(chip,
526 REG_PM8018_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
527 (enable ? SLEEP_CTRL_SMPL_EN_PWR_OFF
528 : SLEEP_CTRL_SMPL_EN_PWR_OFF));
529 break;
530 case PM8XXX_VERSION_8058:
531 rc = pm8xxx_misc_masked_write(chip,
532 REG_PM8058_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
533 (enable ? SLEEP_CTRL_SMPL_EN_RESET
534 : SLEEP_CTRL_SMPL_EN_PWR_OFF));
535 break;
536 case PM8XXX_VERSION_8921:
537 rc = pm8xxx_misc_masked_write(chip,
538 REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_EN_MASK,
539 (enable ? SLEEP_CTRL_SMPL_EN_PWR_OFF
540 : SLEEP_CTRL_SMPL_EN_PWR_OFF));
541 break;
542 default:
543 /* PMIC doesn't have reset_pwr_off; do nothing. */
544 break;
545 }
546 if (rc) {
547 pr_err("setting smpl control failed, rc=%d\n", rc);
548 break;
549 }
550 }
551
552 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
553
554 return rc;
555}
556EXPORT_SYMBOL(pm8xxx_smpl_control);
557
558
559/**
560 * pm8xxx_smpl_set_delay - sets the SMPL detection time delay
561 * @delay: enum value corresponding to delay time
562 *
563 * This function sets the time delay of the SMPL detection module. If power
564 * is reapplied within this interval, then the PMIC reset automatically. The
565 * SMPL detection module must be enabled for this delay time to take effect.
566 *
567 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
568 */
569int pm8xxx_smpl_set_delay(enum pm8xxx_smpl_delay delay)
570{
571 struct pm8xxx_misc_chip *chip;
572 unsigned long flags;
573 int rc = 0;
574
575 if (delay < SLEEP_CTRL_SMPL_SEL_MIN
576 || delay > SLEEP_CTRL_SMPL_SEL_MAX) {
577 pr_err("%s: invalid delay specified: %d\n", __func__, delay);
578 return -EINVAL;
579 }
580
581 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
582
583 /* Loop over all attached PMICs and call specific functions for them. */
584 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
585 switch (chip->version) {
586 case PM8XXX_VERSION_8018:
587 rc = pm8xxx_misc_masked_write(chip,
588 REG_PM8018_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
589 delay);
590 break;
591 case PM8XXX_VERSION_8058:
592 rc = pm8xxx_misc_masked_write(chip,
593 REG_PM8058_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
594 delay);
595 break;
596 case PM8XXX_VERSION_8921:
597 rc = pm8xxx_misc_masked_write(chip,
598 REG_PM8921_SLEEP_CTRL, SLEEP_CTRL_SMPL_SEL_MASK,
599 delay);
600 break;
601 default:
602 /* PMIC doesn't have reset_pwr_off; do nothing. */
603 break;
604 }
605 if (rc) {
606 pr_err("setting smpl delay failed, rc=%d\n", rc);
607 break;
608 }
609 }
610
611 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
612
613 return rc;
614}
615EXPORT_SYMBOL(pm8xxx_smpl_set_delay);
616
617/**
Anirudh Ghayal7b382292011-11-01 14:08:34 +0530618 * pm8xxx_coincell_chg_config - Disables or enables the coincell charger, and
619 * configures its voltage and resistor settings.
620 * @chg_config: Holds both voltage and resistor values, and a
621 * switch to change the state of charger.
622 * If state is to disable the charger then
623 * both voltage and resistor are disregarded.
624 *
625 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
626 */
627int pm8xxx_coincell_chg_config(struct pm8xxx_coincell_chg *chg_config)
628{
629 struct pm8xxx_misc_chip *chip;
630 unsigned long flags;
631 u8 reg = 0, voltage, resistor;
632 int rc = 0;
633
634 if (chg_config == NULL) {
635 pr_err("chg_config is NULL\n");
636 return -EINVAL;
637 }
638
639 voltage = chg_config->voltage;
640 resistor = chg_config->resistor;
641
642 if (resistor < PM8XXX_COINCELL_RESISTOR_2100_OHMS ||
643 resistor > PM8XXX_COINCELL_RESISTOR_800_OHMS) {
644 pr_err("Invalid resistor value provided\n");
645 return -EINVAL;
646 }
647
648 if (voltage < PM8XXX_COINCELL_VOLTAGE_3p2V ||
649 (voltage > PM8XXX_COINCELL_VOLTAGE_3p0V &&
650 voltage != PM8XXX_COINCELL_VOLTAGE_2p5V)) {
651 pr_err("Invalid voltage value provided\n");
652 return -EINVAL;
653 }
654
655 if (chg_config->state == PM8XXX_COINCELL_CHG_DISABLE) {
656 reg = 0;
657 } else {
658 reg |= voltage;
659 reg |= (resistor << COINCELL_RESISTOR_SHIFT);
660 }
661
662 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
663
664 /* Loop over all attached PMICs and call specific functions for them. */
665 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
666 switch (chip->version) {
667 case PM8XXX_VERSION_8018:
668 rc = pm8xxx_writeb(chip->dev->parent,
669 REG_PM8018_COIN_CHG, reg);
670 break;
671 case PM8XXX_VERSION_8058:
672 rc = pm8xxx_writeb(chip->dev->parent,
673 REG_PM8058_COIN_CHG, reg);
674 break;
675 case PM8XXX_VERSION_8921:
676 rc = pm8xxx_writeb(chip->dev->parent,
677 REG_PM8921_COIN_CHG, reg);
678 break;
679 default:
680 /* PMIC doesn't have reset_pwr_off; do nothing. */
681 break;
682 }
683 if (rc) {
684 pr_err("coincell chg. config failed, rc=%d\n", rc);
685 break;
686 }
687 }
688
689 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
690
691 return rc;
692}
693EXPORT_SYMBOL(pm8xxx_coincell_chg_config);
694
Anirudh Ghayala23c1ca2011-11-01 14:36:24 +0530695/**
696 * pm8xxx_watchdog_reset_control - enables/disables watchdog reset detection
697 * @enable: 0 = shutdown when PS_HOLD goes low, 1 = reset when PS_HOLD goes low
698 *
699 * This function enables or disables the PMIC watchdog reset detection feature.
700 * If watchdog reset detection is enabled, then the PMIC will reset itself
701 * when PS_HOLD goes low. If it is not enabled, then the PMIC will shutdown
702 * when PS_HOLD goes low.
703 *
704 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
705 */
706int pm8xxx_watchdog_reset_control(int enable)
707{
708 struct pm8xxx_misc_chip *chip;
709 unsigned long flags;
710 int rc = 0;
711
712 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
713
714 /* Loop over all attached PMICs and call specific functions for them. */
715 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
716 switch (chip->version) {
717 case PM8XXX_VERSION_8018:
718 case PM8XXX_VERSION_8058:
719 case PM8XXX_VERSION_8921:
720 rc = pm8xxx_misc_masked_write(chip,
721 REG_PM8XXX_PON_CTRL_1, PON_CTRL_1_WD_EN_MASK,
722 (enable ? PON_CTRL_1_WD_EN_RESET
723 : PON_CTRL_1_WD_EN_PWR_OFF));
724 break;
725 default:
726 /* WD reset control not supported */
727 break;
728 }
729 if (rc) {
730 pr_err("setting WD reset control failed, rc=%d\n", rc);
731 break;
732 }
733 }
734
735 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
736
737 return rc;
738}
739EXPORT_SYMBOL(pm8xxx_watchdog_reset_control);
740
Anirudh Ghayala4262a32011-11-10 00:02:18 +0530741static int
742__pm8xxx_hard_reset_config(struct pm8xxx_misc_chip *chip,
743 enum pm8xxx_pon_config config, u16 pon4_addr, u16 pon5_addr)
744{
745 int rc = 0;
746
747 switch (config) {
748 case PM8XXX_DISABLE_HARD_RESET:
749 rc = pm8xxx_misc_masked_write(chip, pon5_addr,
750 PON_CTRL_5_HARD_RESET_EN_MASK,
751 PON_CTRL_5_HARD_RESET_DIS);
752 break;
753 case PM8XXX_SHUTDOWN_ON_HARD_RESET:
754 rc = pm8xxx_misc_masked_write(chip, pon5_addr,
755 PON_CTRL_5_HARD_RESET_EN_MASK,
756 PON_CTRL_5_HARD_RESET_EN);
757 if (!rc) {
758 rc = pm8xxx_misc_masked_write(chip, pon4_addr,
759 PON_CTRL_4_RESET_EN_MASK,
760 PON_CTRL_4_SHUTDOWN_ON_RESET);
761 }
762 break;
763 case PM8XXX_RESTART_ON_HARD_RESET:
764 rc = pm8xxx_misc_masked_write(chip, pon5_addr,
765 PON_CTRL_5_HARD_RESET_EN_MASK,
766 PON_CTRL_5_HARD_RESET_EN);
767 if (!rc) {
768 rc = pm8xxx_misc_masked_write(chip, pon4_addr,
769 PON_CTRL_4_RESET_EN_MASK,
770 PON_CTRL_4_RESTART_ON_RESET);
771 }
772 break;
773 default:
774 rc = -EINVAL;
775 break;
776 }
777 return rc;
778}
779
780/**
781 * pm8xxx_hard_reset_config - Allows different reset configurations
782 *
783 * config = PM8XXX_DISABLE_HARD_RESET to disable hard reset
784 * = PM8XXX_SHUTDOWN_ON_HARD_RESET to turn off the system on hard reset
785 * = PM8XXX_RESTART_ON_HARD_RESET to restart the system on hard reset
786 *
787 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
788 */
789int pm8xxx_hard_reset_config(enum pm8xxx_pon_config config)
790{
791 struct pm8xxx_misc_chip *chip;
792 unsigned long flags;
793 int rc = 0;
794
795 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
796
797 /* Loop over all attached PMICs and call specific functions for them. */
798 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
799 switch (chip->version) {
800 case PM8XXX_VERSION_8018:
801 __pm8xxx_hard_reset_config(chip, config,
802 REG_PM8018_PON_CNTL_4, REG_PM8018_PON_CNTL_5);
803 break;
804 case PM8XXX_VERSION_8058:
805 __pm8xxx_hard_reset_config(chip, config,
806 REG_PM8058_PON_CNTL_4, REG_PM8058_PON_CNTL_5);
807 break;
808 case PM8XXX_VERSION_8901:
809 __pm8xxx_hard_reset_config(chip, config,
810 REG_PM8901_PON_CNTL_4, REG_PM8901_PON_CNTL_5);
811 break;
812 case PM8XXX_VERSION_8921:
813 __pm8xxx_hard_reset_config(chip, config,
814 REG_PM8921_PON_CNTL_4, REG_PM8921_PON_CNTL_5);
815 break;
816 default:
817 /* hard reset config. no supported */
818 break;
819 }
820 if (rc) {
821 pr_err("hard reset config. failed, rc=%d\n", rc);
822 break;
823 }
824 }
825
826 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
827
828 return rc;
829}
830EXPORT_SYMBOL(pm8xxx_hard_reset_config);
831
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530832/* Handle the OSC_HALT interrupt: 32 kHz XTAL oscillator has stopped. */
833static irqreturn_t pm8xxx_osc_halt_isr(int irq, void *data)
834{
835 struct pm8xxx_misc_chip *chip = data;
836 u64 count = 0;
837
838 if (chip) {
839 chip->osc_halt_count++;
840 count = chip->osc_halt_count;
841 }
842
843 pr_crit("%s: OSC_HALT interrupt has triggered, 32 kHz XTAL oscillator"
844 " has halted (%llu)!\n", __func__, count);
845
846 return IRQ_HANDLED;
847}
848
Anirudh Ghayal5213eb82011-10-24 14:44:58 +0530849/**
850 * pm8xxx_uart_gpio_mux_ctrl - Mux configuration to select the UART
851 *
852 * @uart_path_sel: Input argument to select either UART1/2/3
853 *
854 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
855 */
856int pm8xxx_uart_gpio_mux_ctrl(enum pm8xxx_uart_path_sel uart_path_sel)
857{
858 struct pm8xxx_misc_chip *chip;
859 unsigned long flags;
860 int rc = 0;
861
862 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
863
864 /* Loop over all attached PMICs and call specific functions for them. */
865 list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
866 switch (chip->version) {
867 case PM8XXX_VERSION_8018:
868 case PM8XXX_VERSION_8058:
869 case PM8XXX_VERSION_8921:
870 rc = pm8xxx_misc_masked_write(chip,
871 REG_PM8XXX_GPIO_MUX_CTRL, UART_PATH_SEL_MASK,
872 uart_path_sel << UART_PATH_SEL_SHIFT);
873 break;
874 default:
875 /* Functionality not supported */
876 break;
877 }
878 if (rc) {
879 pr_err("uart_gpio_mux_ctrl failed, rc=%d\n", rc);
880 break;
881 }
882 }
883
884 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
885
886 return rc;
887}
888EXPORT_SYMBOL(pm8xxx_uart_gpio_mux_ctrl);
889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890static int __devinit pm8xxx_misc_probe(struct platform_device *pdev)
891{
892 const struct pm8xxx_misc_platform_data *pdata = pdev->dev.platform_data;
893 struct pm8xxx_misc_chip *chip;
894 struct pm8xxx_misc_chip *sibling;
895 struct list_head *prev;
896 unsigned long flags;
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530897 int rc = 0, irq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898
899 if (!pdata) {
900 pr_err("missing platform data\n");
901 return -EINVAL;
902 }
903
904 chip = kzalloc(sizeof(struct pm8xxx_misc_chip), GFP_KERNEL);
905 if (!chip) {
906 pr_err("Cannot allocate %d bytes\n",
907 sizeof(struct pm8xxx_misc_chip));
908 return -ENOMEM;
909 }
910
911 chip->dev = &pdev->dev;
912 chip->version = pm8xxx_get_version(chip->dev->parent);
913 memcpy(&(chip->pdata), pdata, sizeof(struct pm8xxx_misc_platform_data));
914
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530915 irq = platform_get_irq_byname(pdev, "pm8xxx_osc_halt_irq");
916 if (irq > 0) {
917 rc = request_any_context_irq(irq, pm8xxx_osc_halt_isr,
918 IRQF_TRIGGER_RISING | IRQF_DISABLED,
919 "pm8xxx_osc_halt_irq", chip);
920 if (rc < 0) {
921 pr_err("%s: request_any_context_irq(%d) FAIL: %d\n",
922 __func__, irq, rc);
923 goto fail_irq;
924 }
925 }
926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 /* Insert PMICs in priority order (lowest value first). */
928 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
929 prev = &pm8xxx_misc_chips;
930 list_for_each_entry(sibling, &pm8xxx_misc_chips, link) {
931 if (chip->pdata.priority < sibling->pdata.priority)
932 break;
933 else
934 prev = &sibling->link;
935 }
936 list_add(&chip->link, prev);
937 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
938
939 platform_set_drvdata(pdev, chip);
940
941 return rc;
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530942
943fail_irq:
944 platform_set_drvdata(pdev, NULL);
945 kfree(chip);
946 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947}
948
949static int __devexit pm8xxx_misc_remove(struct platform_device *pdev)
950{
951 struct pm8xxx_misc_chip *chip = platform_get_drvdata(pdev);
952 unsigned long flags;
Anirudh Ghayal8b8f1892011-11-11 10:48:41 +0530953 int irq = platform_get_irq_byname(pdev, "pm8xxx_osc_halt_irq");
954 if (irq > 0)
955 free_irq(irq, chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956
957 spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
958 list_del(&chip->link);
959 spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
960
961 platform_set_drvdata(pdev, NULL);
962 kfree(chip);
963
964 return 0;
965}
966
967static struct platform_driver pm8xxx_misc_driver = {
968 .probe = pm8xxx_misc_probe,
969 .remove = __devexit_p(pm8xxx_misc_remove),
970 .driver = {
971 .name = PM8XXX_MISC_DEV_NAME,
972 .owner = THIS_MODULE,
973 },
974};
975
976static int __init pm8xxx_misc_init(void)
977{
978 return platform_driver_register(&pm8xxx_misc_driver);
979}
980postcore_initcall(pm8xxx_misc_init);
981
982static void __exit pm8xxx_misc_exit(void)
983{
984 platform_driver_unregister(&pm8xxx_misc_driver);
985}
986module_exit(pm8xxx_misc_exit);
987
988MODULE_LICENSE("GPL v2");
989MODULE_DESCRIPTION("PMIC 8XXX misc driver");
990MODULE_VERSION("1.0");
991MODULE_ALIAS("platform:" PM8XXX_MISC_DEV_NAME);