blob: ae721e44cca6021c4dc9d9f59a86dea514951356 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * Qualcomm PMIC8058 driver
15 *
16 */
Anirudh Ghayalc2019332011-11-12 06:29:10 +053017#include <linux/kernel.h>
18#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019#include <linux/slab.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053020#include <linux/irq.h>
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +053021#include <linux/msm_ssbi.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/mfd/core.h>
23#include <linux/mfd/pmic8058.h>
Anirudh Ghayalc2019332011-11-12 06:29:10 +053024#include <linux/mfd/pm8xxx/core.h>
25#include <linux/msm_adc.h>
26
27#define REG_MPP_BASE 0x50
Anirudh Ghayalca42c7de2011-11-21 10:42:07 +053028#define REG_IRQ_BASE 0x1BB
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
30/* PMIC8058 Revision */
Anirudh Ghayalc2019332011-11-12 06:29:10 +053031#define PM8058_REG_REV 0x002 /* PMIC4 revision */
32#define PM8058_VERSION_MASK 0xF0
33#define PM8058_REVISION_MASK 0x0F
34#define PM8058_VERSION_VALUE 0xE0
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035
Anirudh Ghayalc2019332011-11-12 06:29:10 +053036/* PMIC 8058 Battery Alarm SSBI registers */
37#define REG_BATT_ALARM_THRESH 0x023
38#define REG_BATT_ALARM_CTRL1 0x024
39#define REG_BATT_ALARM_CTRL2 0x0AA
40#define REG_BATT_ALARM_PWM_CTRL 0x0A3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
Anirudh Ghayalc2019332011-11-12 06:29:10 +053042#define REG_TEMP_ALRM_CTRL 0x1B
43#define REG_TEMP_ALRM_PWM 0x9B
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044
45/* PON CNTL 1 register */
46#define SSBI_REG_ADDR_PON_CNTL_1 0x01C
47
48#define PM8058_PON_PUP_MASK 0xF0
49
50#define PM8058_PON_WD_EN_MASK 0x08
51#define PM8058_PON_WD_EN_RESET 0x08
52#define PM8058_PON_WD_EN_PWR_OFF 0x00
53
54/* PON CNTL 4 register */
55#define SSBI_REG_ADDR_PON_CNTL_4 0x98
56#define PM8058_PON_RESET_EN_MASK 0x01
57
58/* PON CNTL 5 register */
59#define SSBI_REG_ADDR_PON_CNTL_5 0x7B
60#define PM8058_HARD_RESET_EN_MASK 0x08
61
David Collins0a911602011-06-15 15:03:13 -070062/* Regulator master enable addresses */
63#define SSBI_REG_ADDR_VREG_EN_MSM 0x018
64#define SSBI_REG_ADDR_VREG_EN_GRP_5_4 0x1C8
65
66/* Regulator control registers for shutdown/reset */
67#define SSBI_REG_ADDR_S0_CTRL 0x004
68#define SSBI_REG_ADDR_S1_CTRL 0x005
69#define SSBI_REG_ADDR_S3_CTRL 0x111
70#define SSBI_REG_ADDR_L21_CTRL 0x120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071#define SSBI_REG_ADDR_L22_CTRL 0x121
72
David Collins0a911602011-06-15 15:03:13 -070073#define REGULATOR_ENABLE_MASK 0x80
74#define REGULATOR_ENABLE 0x80
75#define REGULATOR_DISABLE 0x00
76#define REGULATOR_PULL_DOWN_MASK 0x40
77#define REGULATOR_PULL_DOWN_EN 0x40
78#define REGULATOR_PULL_DOWN_DIS 0x00
79
80/* Buck CTRL register */
81#define SMPS_LEGACY_VREF_SEL 0x20
82#define SMPS_LEGACY_VPROG_MASK 0x1F
83#define SMPS_ADVANCED_BAND_MASK 0xC0
84#define SMPS_ADVANCED_BAND_SHIFT 6
85#define SMPS_ADVANCED_VPROG_MASK 0x3F
86
87/* Buck TEST2 registers for shutdown/reset */
88#define SSBI_REG_ADDR_S0_TEST2 0x084
89#define SSBI_REG_ADDR_S1_TEST2 0x085
90#define SSBI_REG_ADDR_S3_TEST2 0x11A
91
92#define REGULATOR_BANK_WRITE 0x80
93#define REGULATOR_BANK_MASK 0x70
94#define REGULATOR_BANK_SHIFT 4
95#define REGULATOR_BANK_SEL(n) ((n) << REGULATOR_BANK_SHIFT)
96
97/* Buck TEST2 register bank 1 */
98#define SMPS_LEGACY_VLOW_SEL 0x01
99
100/* Buck TEST2 register bank 7 */
101#define SMPS_ADVANCED_MODE_MASK 0x02
102#define SMPS_ADVANCED_MODE 0x02
103#define SMPS_LEGACY_MODE 0x00
104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105/* SLEEP CNTL register */
106#define SSBI_REG_ADDR_SLEEP_CNTL 0x02B
107
108#define PM8058_SLEEP_SMPL_EN_MASK 0x04
109#define PM8058_SLEEP_SMPL_EN_RESET 0x04
110#define PM8058_SLEEP_SMPL_EN_PWR_OFF 0x00
111
112#define PM8058_SLEEP_SMPL_SEL_MASK 0x03
113#define PM8058_SLEEP_SMPL_SEL_MIN 0
114#define PM8058_SLEEP_SMPL_SEL_MAX 3
115
Willie Ruan6a3c9142011-07-14 16:52:41 -0700116/* GP_TEST1 register */
117#define SSBI_REG_ADDR_GP_TEST_1 0x07A
118
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530119#define PM8058_RTC_BASE 0x1E8
120#define PM8058_OTHC_CNTR_BASE0 0xA0
121#define PM8058_OTHC_CNTR_BASE1 0x134
122#define PM8058_OTHC_CNTR_BASE2 0x137
123
124#define SINGLE_IRQ_RESOURCE(_name, _irq) \
125{ \
126 .name = _name, \
127 .start = _irq, \
128 .end = _irq, \
129 .flags = IORESOURCE_IRQ, \
130}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131
132struct pm8058_chip {
133 struct pm8058_platform_data pdata;
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +0530134 struct device *dev;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530135 struct pm_irq_chip *irq_chip;
136 struct mfd_cell *mfd_regulators, *mfd_xo_buffers;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530138 u8 revision;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139
140 struct mutex pm_lock;
141};
142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143static struct pm8058_chip *pmic_chip;
144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145static inline int
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +0530146ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147{
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +0530148 return msm_ssbi_read(dev->parent, addr, buf, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149}
150
151static inline int
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +0530152ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153{
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +0530154 return msm_ssbi_write(dev->parent, addr, buf, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155}
156
157static int pm8058_masked_write(u16 addr, u8 val, u8 mask)
158{
159 int rc;
160 u8 reg;
161
162 if (pmic_chip == NULL)
163 return -ENODEV;
164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 rc = ssbi_read(pmic_chip->dev, addr, &reg, 1);
166 if (rc) {
167 pr_err("%s: ssbi_read(0x%03X) failed: rc=%d\n", __func__, addr,
168 rc);
169 goto done;
170 }
171
172 reg &= ~mask;
173 reg |= val & mask;
174
175 rc = ssbi_write(pmic_chip->dev, addr, &reg, 1);
176 if (rc)
177 pr_err("%s: ssbi_write(0x%03X)=0x%02X failed: rc=%d\n",
178 __func__, addr, reg, rc);
179done:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180 return rc;
181}
182
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183/**
184 * pm8058_smpl_control - enables/disables SMPL detection
185 * @enable: 0 = shutdown PMIC on power loss, 1 = reset PMIC on power loss
186 *
187 * This function enables or disables the Sudden Momentary Power Loss detection
188 * module. If SMPL detection is enabled, then when a sufficiently long power
189 * loss event occurs, the PMIC will automatically reset itself. If SMPL
190 * detection is disabled, then the PMIC will shutdown when power loss occurs.
191 *
192 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
193 */
194int pm8058_smpl_control(int enable)
195{
196 return pm8058_masked_write(SSBI_REG_ADDR_SLEEP_CNTL,
197 (enable ? PM8058_SLEEP_SMPL_EN_RESET
198 : PM8058_SLEEP_SMPL_EN_PWR_OFF),
199 PM8058_SLEEP_SMPL_EN_MASK);
200}
201EXPORT_SYMBOL(pm8058_smpl_control);
202
203/**
204 * pm8058_smpl_set_delay - sets the SMPL detection time delay
205 * @delay: enum value corresponding to delay time
206 *
207 * This function sets the time delay of the SMPL detection module. If power
208 * is reapplied within this interval, then the PMIC reset automatically. The
209 * SMPL detection module must be enabled for this delay time to take effect.
210 *
211 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
212 */
213int pm8058_smpl_set_delay(enum pm8058_smpl_delay delay)
214{
215 if (delay < PM8058_SLEEP_SMPL_SEL_MIN
216 || delay > PM8058_SLEEP_SMPL_SEL_MAX) {
217 pr_err("%s: invalid delay specified: %d\n", __func__, delay);
218 return -EINVAL;
219 }
220
221 return pm8058_masked_write(SSBI_REG_ADDR_SLEEP_CNTL, delay,
222 PM8058_SLEEP_SMPL_SEL_MASK);
223}
224EXPORT_SYMBOL(pm8058_smpl_set_delay);
225
226/**
227 * pm8058_watchdog_reset_control - enables/disables watchdog reset detection
228 * @enable: 0 = shutdown when PS_HOLD goes low, 1 = reset when PS_HOLD goes low
229 *
230 * This function enables or disables the PMIC watchdog reset detection feature.
231 * If watchdog reset detection is enabled, then the PMIC will reset itself
232 * when PS_HOLD goes low. If it is not enabled, then the PMIC will shutdown
233 * when PS_HOLD goes low.
234 *
235 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
236 */
237int pm8058_watchdog_reset_control(int enable)
238{
239 return pm8058_masked_write(SSBI_REG_ADDR_PON_CNTL_1,
240 (enable ? PM8058_PON_WD_EN_RESET
241 : PM8058_PON_WD_EN_PWR_OFF),
242 PM8058_PON_WD_EN_MASK);
243}
244EXPORT_SYMBOL(pm8058_watchdog_reset_control);
245
David Collins0a911602011-06-15 15:03:13 -0700246/*
247 * Set an SMPS regulator to be disabled in its CTRL register, but enabled
248 * in the master enable register. Also set it's pull down enable bit.
249 * Take care to make sure that the output voltage doesn't change if switching
250 * from advanced mode to legacy mode.
251 */
252static int disable_smps_locally_set_pull_down(u16 ctrl_addr, u16 test2_addr,
253 u16 master_enable_addr, u8 master_enable_bit)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254{
David Collins0a911602011-06-15 15:03:13 -0700255 int rc = 0;
256 u8 vref_sel, vlow_sel, band, vprog, bank, reg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
258 if (pmic_chip == NULL)
259 return -ENODEV;
260
David Collins0a911602011-06-15 15:03:13 -0700261 bank = REGULATOR_BANK_SEL(7);
262 rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
263 if (rc) {
264 pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
265 test2_addr, rc);
266 goto done;
267 }
268
269 rc = ssbi_read(pmic_chip->dev, test2_addr, &reg, 1);
270 if (rc) {
271 pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
272 __func__, test2_addr, rc);
273 goto done;
274 }
275
276 /* Check if in advanced mode. */
277 if ((reg & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE) {
278 /* Determine current output voltage. */
279 rc = ssbi_read(pmic_chip->dev, ctrl_addr, &reg, 1);
280 if (rc) {
281 pr_err("%s: FAIL pm8058_read(0x%03X): rc=%d\n",
282 __func__, ctrl_addr, rc);
283 goto done;
284 }
285
286 band = (reg & SMPS_ADVANCED_BAND_MASK)
287 >> SMPS_ADVANCED_BAND_SHIFT;
288 switch (band) {
289 case 3:
290 vref_sel = 0;
291 vlow_sel = 0;
292 break;
293 case 2:
294 vref_sel = SMPS_LEGACY_VREF_SEL;
295 vlow_sel = 0;
296 break;
297 case 1:
298 vref_sel = SMPS_LEGACY_VREF_SEL;
299 vlow_sel = SMPS_LEGACY_VLOW_SEL;
300 break;
301 default:
302 pr_err("%s: regulator already disabled\n", __func__);
303 return -EPERM;
304 }
305 vprog = (reg & SMPS_ADVANCED_VPROG_MASK);
306 /* Round up if fine step is in use. */
307 vprog = (vprog + 1) >> 1;
308 if (vprog > SMPS_LEGACY_VPROG_MASK)
309 vprog = SMPS_LEGACY_VPROG_MASK;
310
311 /* Set VLOW_SEL bit. */
312 bank = REGULATOR_BANK_SEL(1);
313 rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
314 if (rc) {
315 pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n",
316 __func__, test2_addr, rc);
317 goto done;
318 }
319 rc = pm8058_masked_write(test2_addr,
320 REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1)
321 | vlow_sel,
322 REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
323 | SMPS_LEGACY_VLOW_SEL);
324 if (rc)
325 goto done;
326
327 /* Switch to legacy mode */
328 bank = REGULATOR_BANK_SEL(7);
329 rc = ssbi_write(pmic_chip->dev, test2_addr, &bank, 1);
330 if (rc) {
331 pr_err("%s: FAIL ssbi_write(0x%03X): rc=%d\n", __func__,
332 test2_addr, rc);
333 goto done;
334 }
335 rc = pm8058_masked_write(test2_addr,
336 REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7)
337 | SMPS_LEGACY_MODE,
338 REGULATOR_BANK_WRITE | REGULATOR_BANK_MASK
339 | SMPS_ADVANCED_MODE_MASK);
340 if (rc)
341 goto done;
342
343 /* Enable locally, enable pull down, keep voltage the same. */
344 rc = pm8058_masked_write(ctrl_addr,
345 REGULATOR_ENABLE | REGULATOR_PULL_DOWN_EN
346 | vref_sel | vprog,
347 REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK
348 | SMPS_LEGACY_VREF_SEL | SMPS_LEGACY_VPROG_MASK);
349 if (rc)
350 goto done;
351 }
352
353 /* Enable in master control register. */
354 rc = pm8058_masked_write(master_enable_addr, master_enable_bit,
355 master_enable_bit);
356 if (rc)
357 goto done;
358
359 /* Disable locally and enable pull down. */
360 rc = pm8058_masked_write(ctrl_addr,
361 REGULATOR_DISABLE | REGULATOR_PULL_DOWN_EN,
362 REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK);
363
364done:
365 return rc;
366}
367
368static int disable_ldo_locally_set_pull_down(u16 ctrl_addr,
369 u16 master_enable_addr, u8 master_enable_bit)
370{
371 int rc;
372
373 /* Enable LDO in master control register. */
374 rc = pm8058_masked_write(master_enable_addr, master_enable_bit,
375 master_enable_bit);
376 if (rc)
377 goto done;
378
379 /* Disable LDO in CTRL register and set pull down */
380 rc = pm8058_masked_write(ctrl_addr,
381 REGULATOR_DISABLE | REGULATOR_PULL_DOWN_EN,
382 REGULATOR_ENABLE_MASK | REGULATOR_PULL_DOWN_MASK);
383
384done:
385 return rc;
386}
387
388int pm8058_reset_pwr_off(int reset)
389{
390 int rc;
391 u8 pon, ctrl, smpl;
392
393 if (pmic_chip == NULL)
394 return -ENODEV;
395
396 /* When shutting down, enable active pulldowns on important rails. */
397 if (!reset) {
398 /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */
399 disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S0_CTRL,
400 SSBI_REG_ADDR_S0_TEST2, SSBI_REG_ADDR_VREG_EN_MSM, BIT(7));
401 disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S1_CTRL,
402 SSBI_REG_ADDR_S1_TEST2, SSBI_REG_ADDR_VREG_EN_MSM, BIT(6));
403 disable_smps_locally_set_pull_down(SSBI_REG_ADDR_S3_CTRL,
404 SSBI_REG_ADDR_S3_TEST2, SSBI_REG_ADDR_VREG_EN_GRP_5_4,
405 BIT(7) | BIT(4));
406 /* Disable LDO 21 locally and set pulldown enable bit. */
407 disable_ldo_locally_set_pull_down(SSBI_REG_ADDR_L21_CTRL,
408 SSBI_REG_ADDR_VREG_EN_GRP_5_4, BIT(1));
409 }
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 /* Set regulator L22 to 1.225V in high power mode. */
412 rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
413 if (rc) {
414 pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n", __func__,
415 SSBI_REG_ADDR_L22_CTRL, rc);
416 goto get_out3;
417 }
418 /* Leave pull-down state intact. */
419 ctrl &= 0x40;
420 ctrl |= 0x93;
421 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_L22_CTRL, &ctrl, 1);
422 if (rc)
423 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n", __func__,
424 SSBI_REG_ADDR_L22_CTRL, ctrl, rc);
425
426get_out3:
427 if (!reset) {
428 /* Only modify the SLEEP_CNTL reg if shutdown is desired. */
429 rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_SLEEP_CNTL,
430 &smpl, 1);
431 if (rc) {
432 pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
433 __func__, SSBI_REG_ADDR_SLEEP_CNTL, rc);
434 goto get_out2;
435 }
436
437 smpl &= ~PM8058_SLEEP_SMPL_EN_MASK;
438 smpl |= PM8058_SLEEP_SMPL_EN_PWR_OFF;
439
440 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_SLEEP_CNTL,
441 &smpl, 1);
442 if (rc)
443 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
444 __func__, SSBI_REG_ADDR_SLEEP_CNTL, smpl, rc);
445 }
446
447get_out2:
448 rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
449 if (rc) {
450 pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
451 __func__, SSBI_REG_ADDR_PON_CNTL_1, rc);
452 goto get_out;
453 }
454
455 pon &= ~PM8058_PON_WD_EN_MASK;
456 pon |= reset ? PM8058_PON_WD_EN_RESET : PM8058_PON_WD_EN_PWR_OFF;
457
458 /* Enable all pullups */
459 pon |= PM8058_PON_PUP_MASK;
460
461 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_1, &pon, 1);
462 if (rc) {
463 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
464 __func__, SSBI_REG_ADDR_PON_CNTL_1, pon, rc);
465 goto get_out;
466 }
467
468get_out:
469 return rc;
470}
471EXPORT_SYMBOL(pm8058_reset_pwr_off);
472
Willie Ruan6a3c9142011-07-14 16:52:41 -0700473/**
474 * pm8058_stay_on - enables stay_on feature
475 *
476 * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
477 * signal so that some special functions like debugging could be
478 * performed.
479 *
480 * This feature should not be used in any product release.
481 *
482 * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
483 */
484int pm8058_stay_on(void)
485{
486 u8 ctrl = 0x92;
487 int rc;
488
489 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_GP_TEST_1, &ctrl, 1);
490 pr_info("%s: set stay-on: rc = %d\n", __func__, rc);
491 return rc;
492}
493EXPORT_SYMBOL(pm8058_stay_on);
494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495/*
496 power on hard reset configuration
497 config = DISABLE_HARD_RESET to disable hard reset
498 = SHUTDOWN_ON_HARD_RESET to turn off the system on hard reset
499 = RESTART_ON_HARD_RESET to restart the system on hard reset
500 */
501int pm8058_hard_reset_config(enum pon_config config)
502{
503 int rc, ret;
504 u8 pon, pon_5;
505
506 if (config >= MAX_PON_CONFIG)
507 return -EINVAL;
508
509 if (pmic_chip == NULL)
510 return -ENODEV;
511
512 mutex_lock(&pmic_chip->pm_lock);
513
514 rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
515 if (rc) {
516 pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
517 __func__, SSBI_REG_ADDR_PON_CNTL_5, rc);
518 mutex_unlock(&pmic_chip->pm_lock);
519 return rc;
520 }
521
522 pon_5 = pon;
523 (config != DISABLE_HARD_RESET) ? (pon |= PM8058_HARD_RESET_EN_MASK) :
524 (pon &= ~PM8058_HARD_RESET_EN_MASK);
525
526 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
527 if (rc) {
528 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
529 __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, rc);
530 mutex_unlock(&pmic_chip->pm_lock);
531 return rc;
532 }
533
534 if (config == DISABLE_HARD_RESET) {
535 mutex_unlock(&pmic_chip->pm_lock);
536 return 0;
537 }
538
539 rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
540 if (rc) {
541 pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
542 __func__, SSBI_REG_ADDR_PON_CNTL_4, rc);
543 goto err_restore_pon_5;
544 }
545
546 (config == RESTART_ON_HARD_RESET) ? (pon |= PM8058_PON_RESET_EN_MASK) :
547 (pon &= ~PM8058_PON_RESET_EN_MASK);
548
549 rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
550 if (rc) {
551 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
552 __func__, SSBI_REG_ADDR_PON_CNTL_4, pon, rc);
553 goto err_restore_pon_5;
554 }
555 mutex_unlock(&pmic_chip->pm_lock);
556 return 0;
557
558err_restore_pon_5:
559 ret = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon_5, 1);
560 if (ret)
561 pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
562 __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, ret);
563 mutex_unlock(&pmic_chip->pm_lock);
564 return rc;
565}
566EXPORT_SYMBOL(pm8058_hard_reset_config);
567
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530568static int pm8058_readb(const struct device *dev, u16 addr, u8 *val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530570 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
571 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530573 return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574}
575
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530576static int pm8058_writeb(const struct device *dev, u16 addr, u8 val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530578 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
579 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700580
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530581 return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582}
583
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530584static int pm8058_read_buf(const struct device *dev, u16 addr, u8 *buf,
585 int cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530587 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
588 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530590 return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591}
592
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530593static int pm8058_write_buf(const struct device *dev, u16 addr, u8 *buf,
594 int cnt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530596 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
597 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530599 return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600}
601
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530602static int pm8058_read_irq_stat(const struct device *dev, int irq)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530604 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
605 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530607 return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608
609 return 0;
610}
611
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530612static enum pm8xxx_version pm8058_get_version(const struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530614 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
615 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
616 enum pm8xxx_version version = -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530618 if ((pmic->revision & PM8058_VERSION_MASK) == PM8058_VERSION_VALUE)
619 version = PM8XXX_VERSION_8058;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530621 return version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622}
623
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530624static int pm8058_get_revision(const struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625{
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530626 const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
627 const struct pm8058_chip *pmic = pm8058_drvdata->pm_chip_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530629 return pmic->revision & PM8058_REVISION_MASK;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630}
631
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530632static struct pm8xxx_drvdata pm8058_drvdata = {
633 .pmic_readb = pm8058_readb,
634 .pmic_writeb = pm8058_writeb,
635 .pmic_read_buf = pm8058_read_buf,
636 .pmic_write_buf = pm8058_write_buf,
637 .pmic_read_irq_stat = pm8058_read_irq_stat,
638 .pmic_get_version = pm8058_get_version,
639 .pmic_get_revision = pm8058_get_revision,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640};
641
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530642static const struct resource pm8058_charger_resources[] __devinitconst = {
643 SINGLE_IRQ_RESOURCE("CHGVAL", PM8058_CHGVAL_IRQ),
644 SINGLE_IRQ_RESOURCE("CHGINVAL", PM8058_CHGINVAL_IRQ),
645 SINGLE_IRQ_RESOURCE("CHGILIM", PM8058_CHGILIM_IRQ),
646 SINGLE_IRQ_RESOURCE("VCP", PM8058_VCP_IRQ),
647 SINGLE_IRQ_RESOURCE("ATC_DONE", PM8058_ATC_DONE_IRQ),
648 SINGLE_IRQ_RESOURCE("ATCFAIL", PM8058_ATCFAIL_IRQ),
649 SINGLE_IRQ_RESOURCE("AUTO_CHGDONE", PM8058_AUTO_CHGDONE_IRQ),
650 SINGLE_IRQ_RESOURCE("AUTO_CHGFAIL", PM8058_AUTO_CHGFAIL_IRQ),
651 SINGLE_IRQ_RESOURCE("CHGSTATE", PM8058_CHGSTATE_IRQ),
652 SINGLE_IRQ_RESOURCE("FASTCHG", PM8058_FASTCHG_IRQ),
653 SINGLE_IRQ_RESOURCE("CHG_END", PM8058_CHG_END_IRQ),
654 SINGLE_IRQ_RESOURCE("BATTTEMP", PM8058_BATTTEMP_IRQ),
655 SINGLE_IRQ_RESOURCE("CHGHOT", PM8058_CHGHOT_IRQ),
656 SINGLE_IRQ_RESOURCE("CHGTLIMIT", PM8058_CHGTLIMIT_IRQ),
657 SINGLE_IRQ_RESOURCE("CHG_GONE", PM8058_CHG_GONE_IRQ),
658 SINGLE_IRQ_RESOURCE("VCPMAJOR", PM8058_VCPMAJOR_IRQ),
659 SINGLE_IRQ_RESOURCE("VBATDET", PM8058_VBATDET_IRQ),
660 SINGLE_IRQ_RESOURCE("BATFET", PM8058_BATFET_IRQ),
661 SINGLE_IRQ_RESOURCE("BATT_REPLACE", PM8058_BATT_REPLACE_IRQ),
662 SINGLE_IRQ_RESOURCE("BATTCONNECT", PM8058_BATTCONNECT_IRQ),
663 SINGLE_IRQ_RESOURCE("VBATDET_LOW", PM8058_VBATDET_LOW_IRQ),
Abhijeet Dharmapurikara3c0d942011-07-25 17:53:45 -0700664};
665
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530666static struct mfd_cell pm8058_charger_cell __devinitdata = {
667 .name = "pm8058-charger",
668 .id = -1,
669 .resources = pm8058_charger_resources,
670 .num_resources = ARRAY_SIZE(pm8058_charger_resources),
671};
672
673static const struct resource misc_cell_resources[] __devinitconst = {
674 SINGLE_IRQ_RESOURCE("pm8xxx_osc_halt_irq", PM8058_OSCHALT_IRQ),
675};
676
677static struct mfd_cell misc_cell __devinitdata = {
678 .name = PM8XXX_MISC_DEV_NAME,
679 .id = -1,
680 .resources = misc_cell_resources,
681 .num_resources = ARRAY_SIZE(misc_cell_resources),
682};
683
684static struct mfd_cell pm8058_pwm_cell __devinitdata = {
685 .name = "pm8058-pwm",
686 .id = -1,
687};
688
689static struct resource xoadc_resources[] = {
690 SINGLE_IRQ_RESOURCE(NULL, PM8058_ADC_IRQ),
691};
692
693static struct mfd_cell xoadc_cell __devinitdata = {
694 .name = "pm8058-xoadc",
695 .id = -1,
696 .resources = xoadc_resources,
697 .num_resources = ARRAY_SIZE(xoadc_resources),
698};
699
700static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
701 SINGLE_IRQ_RESOURCE("pm8058_tempstat_irq", PM8058_TEMPSTAT_IRQ),
702 SINGLE_IRQ_RESOURCE("pm8058_overtemp_irq", PM8058_OVERTEMP_IRQ),
703};
704
705static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
706 .adc_channel = CHANNEL_ADC_DIE_TEMP,
707 .adc_type = PM8XXX_TM_ADC_PM8058_ADC,
708 .reg_addr_temp_alarm_ctrl = REG_TEMP_ALRM_CTRL,
709 .reg_addr_temp_alarm_pwm = REG_TEMP_ALRM_PWM,
710 .tm_name = "pm8058_tz",
711 .irq_name_temp_stat = "pm8058_tempstat_irq",
712 .irq_name_over_temp = "pm8058_overtemp_irq",
713};
714
715static struct mfd_cell thermal_alarm_cell __devinitdata = {
716 .name = PM8XXX_TM_DEV_NAME,
717 .id = -1,
718 .resources = thermal_alarm_cell_resources,
719 .num_resources = ARRAY_SIZE(thermal_alarm_cell_resources),
720 .platform_data = &thermal_alarm_cdata,
721 .pdata_size = sizeof(struct pm8xxx_tm_core_data),
722};
723
724static struct mfd_cell debugfs_cell __devinitdata = {
725 .name = "pm8xxx-debug",
726 .id = -1,
727 .platform_data = "pm8058-dbg",
728 .pdata_size = sizeof("pm8058-dbg"),
729};
730
731static const struct resource othc0_cell_resources[] __devinitconst = {
732 {
733 .name = "othc_base",
734 .start = PM8058_OTHC_CNTR_BASE0,
735 .end = PM8058_OTHC_CNTR_BASE0,
736 .flags = IORESOURCE_IO,
737 },
738};
739
740static const struct resource othc1_cell_resources[] __devinitconst = {
741 SINGLE_IRQ_RESOURCE(NULL, PM8058_SW_1_IRQ),
742 SINGLE_IRQ_RESOURCE(NULL, PM8058_IR_1_IRQ),
743 {
744 .name = "othc_base",
745 .start = PM8058_OTHC_CNTR_BASE1,
746 .end = PM8058_OTHC_CNTR_BASE1,
747 .flags = IORESOURCE_IO,
748 },
749};
750
751static const struct resource othc2_cell_resources[] __devinitconst = {
752 {
753 .name = "othc_base",
754 .start = PM8058_OTHC_CNTR_BASE2,
755 .end = PM8058_OTHC_CNTR_BASE2,
756 .flags = IORESOURCE_IO,
757 },
758};
759
760static const struct resource batt_alarm_cell_resources[] __devinitconst = {
761 SINGLE_IRQ_RESOURCE("pm8058_batt_alarm_irq", PM8058_BATT_ALARM_IRQ),
762};
763
764static struct mfd_cell leds_cell __devinitdata = {
765 .name = "pm8058-led",
766 .id = -1,
767};
768
769static struct mfd_cell othc0_cell __devinitdata = {
770 .name = "pm8058-othc",
771 .id = 0,
772 .resources = othc0_cell_resources,
773 .num_resources = ARRAY_SIZE(othc0_cell_resources),
774};
775
776static struct mfd_cell othc1_cell __devinitdata = {
777 .name = "pm8058-othc",
778 .id = 1,
779 .resources = othc1_cell_resources,
780 .num_resources = ARRAY_SIZE(othc1_cell_resources),
781};
782
783static struct mfd_cell othc2_cell __devinitdata = {
784 .name = "pm8058-othc",
785 .id = 2,
786 .resources = othc2_cell_resources,
787 .num_resources = ARRAY_SIZE(othc2_cell_resources),
788};
789
790static struct pm8xxx_batt_alarm_core_data batt_alarm_cdata = {
791 .irq_name = "pm8058_batt_alarm_irq",
792 .reg_addr_threshold = REG_BATT_ALARM_THRESH,
793 .reg_addr_ctrl1 = REG_BATT_ALARM_CTRL1,
794 .reg_addr_ctrl2 = REG_BATT_ALARM_CTRL2,
795 .reg_addr_pwm_ctrl = REG_BATT_ALARM_PWM_CTRL,
796};
797
798static struct mfd_cell batt_alarm_cell __devinitdata = {
799 .name = PM8XXX_BATT_ALARM_DEV_NAME,
800 .id = -1,
801 .resources = batt_alarm_cell_resources,
802 .num_resources = ARRAY_SIZE(batt_alarm_cell_resources),
803 .platform_data = &batt_alarm_cdata,
804 .pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
805};
806
807static struct mfd_cell upl_cell __devinitdata = {
808 .name = PM8XXX_UPL_DEV_NAME,
809 .id = -1,
810};
811
812static struct mfd_cell nfc_cell __devinitdata = {
813 .name = PM8XXX_NFC_DEV_NAME,
814 .id = -1,
815};
816
817static const struct resource rtc_cell_resources[] __devinitconst = {
818 [0] = SINGLE_IRQ_RESOURCE(NULL, PM8058_RTC_ALARM_IRQ),
819 [1] = {
820 .name = "pmic_rtc_base",
821 .start = PM8058_RTC_BASE,
822 .end = PM8058_RTC_BASE,
823 .flags = IORESOURCE_IO,
824 },
825};
826
827static struct mfd_cell rtc_cell __devinitdata = {
828 .name = PM8XXX_RTC_DEV_NAME,
829 .id = -1,
830 .resources = rtc_cell_resources,
831 .num_resources = ARRAY_SIZE(rtc_cell_resources),
832};
833
834static const struct resource resources_pwrkey[] __devinitconst = {
835 SINGLE_IRQ_RESOURCE(NULL, PM8058_PWRKEY_REL_IRQ),
836 SINGLE_IRQ_RESOURCE(NULL, PM8058_PWRKEY_PRESS_IRQ),
837};
838
839static struct mfd_cell vibrator_cell __devinitdata = {
840 .name = PM8XXX_VIBRATOR_DEV_NAME,
841 .id = -1,
842};
843
844static struct mfd_cell pwrkey_cell __devinitdata = {
845 .name = PM8XXX_PWRKEY_DEV_NAME,
846 .id = -1,
847 .num_resources = ARRAY_SIZE(resources_pwrkey),
848 .resources = resources_pwrkey,
849};
850
851static const struct resource resources_keypad[] = {
852 SINGLE_IRQ_RESOURCE(NULL, PM8058_KEYPAD_IRQ),
853 SINGLE_IRQ_RESOURCE(NULL, PM8058_KEYSTUCK_IRQ),
854};
855
856static struct mfd_cell keypad_cell __devinitdata = {
857 .name = PM8XXX_KEYPAD_DEV_NAME,
858 .id = -1,
859 .num_resources = ARRAY_SIZE(resources_keypad),
860 .resources = resources_keypad,
861};
862
863static const struct resource mpp_cell_resources[] __devinitconst = {
864 {
865 .start = PM8058_IRQ_BLOCK_BIT(PM8058_MPP_BLOCK_START, 0),
866 .end = PM8058_IRQ_BLOCK_BIT(PM8058_MPP_BLOCK_START, 0)
867 + PM8058_MPPS - 1,
868 .flags = IORESOURCE_IRQ,
869 },
870};
871
872static struct mfd_cell mpp_cell __devinitdata = {
873 .name = PM8XXX_MPP_DEV_NAME,
874 .id = 0,
875 .resources = mpp_cell_resources,
876 .num_resources = ARRAY_SIZE(mpp_cell_resources),
877};
878
879static const struct resource gpio_cell_resources[] __devinitconst = {
880 [0] = {
881 .start = PM8058_IRQ_BLOCK_BIT(PM8058_GPIO_BLOCK_START, 0),
882 .end = PM8058_IRQ_BLOCK_BIT(PM8058_GPIO_BLOCK_START, 0)
883 + PM8058_GPIOS - 1,
884 .flags = IORESOURCE_IRQ,
885 },
886};
887
888static struct mfd_cell gpio_cell __devinitdata = {
889 .name = PM8XXX_GPIO_DEV_NAME,
890 .id = -1,
891 .resources = gpio_cell_resources,
892 .num_resources = ARRAY_SIZE(gpio_cell_resources),
893};
894
895static int __devinit
896pm8058_add_subdevices(const struct pm8058_platform_data *pdata,
897 struct pm8058_chip *pmic)
898{
899 int rc = 0, irq_base = 0, i;
900 struct pm_irq_chip *irq_chip;
901 static struct mfd_cell *mfd_regulators, *mfd_xo_buffers;
902
903 if (pdata->irq_pdata) {
904 pdata->irq_pdata->irq_cdata.nirqs = PM8058_NR_IRQS;
Anirudh Ghayalca42c7de2011-11-21 10:42:07 +0530905 pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
Anirudh Ghayalc2019332011-11-12 06:29:10 +0530906 irq_base = pdata->irq_pdata->irq_base;
907 irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
908
909 if (IS_ERR(irq_chip)) {
910 pr_err("Failed to init interrupts ret=%ld\n",
911 PTR_ERR(irq_chip));
912 return PTR_ERR(irq_chip);
913 }
914 pmic->irq_chip = irq_chip;
915 }
916
917 if (pdata->gpio_pdata) {
918 pdata->gpio_pdata->gpio_cdata.ngpios = PM8058_GPIOS;
919 gpio_cell.platform_data = pdata->gpio_pdata;
920 gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
921 rc = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
922 NULL, irq_base);
923 if (rc) {
924 pr_err("Failed to add gpio subdevice ret=%d\n", rc);
925 goto bail;
926 }
927 }
928
929 if (pdata->mpp_pdata) {
930 pdata->mpp_pdata->core_data.nmpps = PM8058_MPPS;
931 pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
932 mpp_cell.platform_data = pdata->mpp_pdata;
933 mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
934 rc = mfd_add_devices(pmic->dev, 0, &mpp_cell, 1, NULL,
935 irq_base);
936 if (rc) {
937 pr_err("Failed to add mpp subdevice ret=%d\n", rc);
938 goto bail;
939 }
940 }
941
942 if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
943 mfd_regulators = kzalloc(sizeof(struct mfd_cell)
944 * (pdata->num_regulators), GFP_KERNEL);
945 if (!mfd_regulators) {
946 pr_err("Cannot allocate %d bytes for pm8058 regulator "
947 "mfd cells\n", sizeof(struct mfd_cell)
948 * (pdata->num_regulators));
949 rc = -ENOMEM;
950 goto bail;
951 }
952 for (i = 0; i < pdata->num_regulators; i++) {
953 mfd_regulators[i].name = "pm8058-regulator";
954 mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
955 mfd_regulators[i].platform_data =
956 &(pdata->regulator_pdatas[i]);
957 mfd_regulators[i].pdata_size =
958 sizeof(struct pm8058_vreg_pdata);
959 }
960 rc = mfd_add_devices(pmic->dev, 0, mfd_regulators,
961 pdata->num_regulators, NULL, irq_base);
962 if (rc) {
963 pr_err("Failed to add regulator subdevices ret=%d\n",
964 rc);
965 kfree(mfd_regulators);
966 goto bail;
967 }
968 pmic->mfd_regulators = mfd_regulators;
969 }
970
971 if (pdata->num_xo_buffers > 0 && pdata->xo_buffer_pdata) {
972 mfd_xo_buffers = kzalloc(sizeof(struct mfd_cell)
973 * (pdata->num_xo_buffers), GFP_KERNEL);
974 if (!mfd_xo_buffers) {
975 pr_err("Cannot allocate %d bytes for pm8058 XO buffer "
976 "mfd cells\n", sizeof(struct mfd_cell)
977 * (pdata->num_xo_buffers));
978 rc = -ENOMEM;
979 goto bail;
980 }
981 for (i = 0; i < pdata->num_xo_buffers; i++) {
982 mfd_xo_buffers[i].name = PM8058_XO_BUFFER_DEV_NAME;
983 mfd_xo_buffers[i].id = pdata->xo_buffer_pdata[i].id;
984 mfd_xo_buffers[i].platform_data =
985 &(pdata->xo_buffer_pdata[i]);
986 mfd_xo_buffers[i].pdata_size =
987 sizeof(struct pm8058_xo_pdata);
988 }
989 rc = mfd_add_devices(pmic->dev, 0, mfd_xo_buffers,
990 pdata->num_xo_buffers, NULL, irq_base);
991 if (rc) {
992 pr_err("Failed to add XO buffer subdevices ret=%d\n",
993 rc);
994 kfree(mfd_xo_buffers);
995 goto bail;
996 }
997 pmic->mfd_xo_buffers = mfd_xo_buffers;
998 }
999
1000 if (pdata->keypad_pdata) {
1001 keypad_cell.platform_data = pdata->keypad_pdata;
1002 keypad_cell.pdata_size =
1003 sizeof(struct pm8xxx_keypad_platform_data);
1004 rc = mfd_add_devices(pmic->dev, 0, &keypad_cell, 1, NULL,
1005 irq_base);
1006 if (rc) {
1007 pr_err("Failed to add keypad subdevice ret=%d\n", rc);
1008 goto bail;
1009 }
1010 }
1011
1012 if (pdata->rtc_pdata) {
1013 rtc_cell.platform_data = pdata->rtc_pdata;
1014 rtc_cell.pdata_size = sizeof(struct pm8xxx_rtc_platform_data);
1015 rc = mfd_add_devices(pmic->dev, 0, &rtc_cell, 1, NULL,
1016 irq_base);
1017 if (rc) {
1018 pr_err("Failed to add rtc subdevice ret=%d\n", rc);
1019 goto bail;
1020 }
1021 }
1022
1023 if (pdata->pwrkey_pdata) {
1024 pwrkey_cell.platform_data = pdata->pwrkey_pdata;
1025 pwrkey_cell.pdata_size =
1026 sizeof(struct pm8xxx_pwrkey_platform_data);
1027 rc = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
1028 irq_base);
1029 if (rc) {
1030 pr_err("Failed to add pwrkey subdevice ret=%d\n", rc);
1031 goto bail;
1032 }
1033 }
1034
1035 if (pdata->vibrator_pdata) {
1036 vibrator_cell.platform_data = pdata->vibrator_pdata;
1037 vibrator_cell.pdata_size =
1038 sizeof(struct pm8xxx_vibrator_platform_data);
1039 rc = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL,
1040 irq_base);
1041 if (rc) {
1042 pr_err("Failed to add vibrator subdevice ret=%d\n",
1043 rc);
1044 goto bail;
1045 }
1046 }
1047
1048 if (pdata->leds_pdata) {
1049 leds_cell.platform_data = pdata->leds_pdata;
1050 leds_cell.pdata_size =
1051 sizeof(struct pmic8058_leds_platform_data);
1052 rc = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL,
1053 irq_base);
1054 if (rc) {
1055 pr_err("Failed to add leds subdevice ret=%d\n", rc);
1056 goto bail;
1057 }
1058 }
1059
1060 if (pdata->xoadc_pdata) {
1061 xoadc_cell.platform_data = pdata->xoadc_pdata;
1062 xoadc_cell.pdata_size =
1063 sizeof(struct xoadc_platform_data);
1064 rc = mfd_add_devices(pmic->dev, 0, &xoadc_cell, 1, NULL,
1065 irq_base);
1066 if (rc) {
1067 pr_err("Failed to add leds subdevice ret=%d\n", rc);
1068 goto bail;
1069 }
1070 }
1071
1072 if (pdata->othc0_pdata) {
1073 othc0_cell.platform_data = pdata->othc0_pdata;
1074 othc0_cell.pdata_size =
1075 sizeof(struct pmic8058_othc_config_pdata);
1076 rc = mfd_add_devices(pmic->dev, 0, &othc0_cell, 1, NULL, 0);
1077 if (rc) {
1078 pr_err("Failed to add othc0 subdevice ret=%d\n", rc);
1079 goto bail;
1080 }
1081 }
1082
1083 if (pdata->othc1_pdata) {
1084 othc1_cell.platform_data = pdata->othc1_pdata;
1085 othc1_cell.pdata_size =
1086 sizeof(struct pmic8058_othc_config_pdata);
1087 rc = mfd_add_devices(pmic->dev, 0, &othc1_cell, 1, NULL,
1088 irq_base);
1089 if (rc) {
1090 pr_err("Failed to add othc1 subdevice ret=%d\n", rc);
1091 goto bail;
1092 }
1093 }
1094
1095 if (pdata->othc2_pdata) {
1096 othc2_cell.platform_data = pdata->othc2_pdata;
1097 othc2_cell.pdata_size =
1098 sizeof(struct pmic8058_othc_config_pdata);
1099 rc = mfd_add_devices(pmic->dev, 0, &othc2_cell, 1, NULL, 0);
1100 if (rc) {
1101 pr_err("Failed to add othc2 subdevice ret=%d\n", rc);
1102 goto bail;
1103 }
1104 }
1105
1106 if (pdata->pwm_pdata) {
1107 pm8058_pwm_cell.platform_data = pdata->pwm_pdata;
1108 pm8058_pwm_cell.pdata_size = sizeof(struct pm8058_pwm_pdata);
1109 rc = mfd_add_devices(pmic->dev, 0, &pm8058_pwm_cell, 1, NULL,
1110 irq_base);
1111 if (rc) {
1112 pr_err("Failed to add pwm subdevice ret=%d\n", rc);
1113 goto bail;
1114 }
1115 }
1116
1117 if (pdata->misc_pdata) {
1118 misc_cell.platform_data = pdata->misc_pdata;
1119 misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
1120 rc = mfd_add_devices(pmic->dev, 0, &misc_cell, 1, NULL,
1121 irq_base);
1122 if (rc) {
1123 pr_err("Failed to add misc subdevice ret=%d\n", rc);
1124 goto bail;
1125 }
1126 }
1127
1128 rc = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
1129 irq_base);
1130 if (rc) {
1131 pr_err("Failed to add thermal alarm subdevice ret=%d\n",
1132 rc);
1133 goto bail;
1134 }
1135
1136 rc = mfd_add_devices(pmic->dev, 0, &batt_alarm_cell, 1, NULL,
1137 irq_base);
1138 if (rc) {
1139 pr_err("Failed to add battery alarm subdevice ret=%d\n",
1140 rc);
1141 goto bail;
1142 }
1143
1144 rc = mfd_add_devices(pmic->dev, 0, &upl_cell, 1, NULL, 0);
1145 if (rc) {
1146 pr_err("Failed to add upl subdevice ret=%d\n", rc);
1147 goto bail;
1148 }
1149
1150 rc = mfd_add_devices(pmic->dev, 0, &nfc_cell, 1, NULL, 0);
1151 if (rc) {
1152 pr_err("Failed to add upl subdevice ret=%d\n", rc);
1153 goto bail;
1154 }
1155
1156 if (pdata->charger_pdata) {
1157 pm8058_charger_cell.platform_data = pdata->charger_pdata;
1158 pm8058_charger_cell.pdata_size = sizeof(struct
1159 pmic8058_charger_data);
1160 rc = mfd_add_devices(pmic->dev, 0, &pm8058_charger_cell,
1161 1, NULL, irq_base);
1162 if (rc) {
1163 pr_err("Failed to add charger subdevice ret=%d\n", rc);
1164 goto bail;
1165 }
1166 }
1167
1168 rc = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
1169 if (rc) {
1170 pr_err("Failed to add debugfs subdevice ret=%d\n", rc);
1171 goto bail;
1172 }
1173
1174 return rc;
1175bail:
1176 if (pmic->irq_chip) {
1177 pm8xxx_irq_exit(pmic->irq_chip);
1178 pmic->irq_chip = NULL;
1179 }
1180 return rc;
1181}
1182
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301183static int __devinit pm8058_probe(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184{
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301185 int rc;
1186 struct pm8058_platform_data *pdata = pdev->dev.platform_data;
1187 struct pm8058_chip *pmic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301189 if (pdata == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 pr_err("%s: No platform_data or IRQ.\n", __func__);
1191 return -ENODEV;
1192 }
1193
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301194 pmic = kzalloc(sizeof *pmic, GFP_KERNEL);
1195 if (pmic == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 pr_err("%s: kzalloc() failed.\n", __func__);
1197 return -ENOMEM;
1198 }
1199
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301200 pmic->dev = &pdev->dev;
1201
1202 pm8058_drvdata.pm_chip_data = pmic;
1203 platform_set_drvdata(pdev, &pm8058_drvdata);
1204
1205 mutex_init(&pmic->pm_lock);
1206 pmic_chip = pmic;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207
1208 /* Read PMIC chip revision */
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301209 rc = pm8058_readb(pmic->dev, PM8058_REG_REV, &pmic->revision);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 if (rc)
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301211 pr_err("%s: Failed on pm8058_readb for revision: rc=%d.\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 __func__, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301214 pr_info("%s: PMIC revision: %X\n", __func__, pmic->revision);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301216 (void) memcpy((void *)&pmic->pdata, (const void *)pdata,
1217 sizeof(pmic->pdata));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301219 rc = pm8058_add_subdevices(pdata, pmic);
1220 if (rc) {
1221 pr_err("Cannot add subdevices rc=%d\n", rc);
1222 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 }
1224
Abhijeet Dharmapurikara4a3eaf2011-09-22 15:27:28 -07001225 rc = pm8058_hard_reset_config(SHUTDOWN_ON_HARD_RESET);
1226 if (rc < 0)
1227 pr_err("%s: failed to config shutdown on hard reset: %d\n",
1228 __func__, rc);
1229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 return 0;
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301231
1232err:
1233 mfd_remove_devices(pmic->dev);
1234 platform_set_drvdata(pdev, NULL);
1235 kfree(pmic);
1236 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237}
1238
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301239static int __devexit pm8058_remove(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240{
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301241 struct pm8xxx_drvdata *drvdata;
1242 struct pm8058_chip *pmic = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301244 drvdata = platform_get_drvdata(pdev);
1245 if (drvdata)
1246 pmic = drvdata->pm_chip_data;
1247 if (pmic) {
1248 if (pmic->dev)
1249 mfd_remove_devices(pmic->dev);
1250 if (pmic->irq_chip)
1251 pm8xxx_irq_exit(pmic->irq_chip);
1252 mutex_destroy(&pmic->pm_lock);
1253 kfree(pmic->mfd_regulators);
1254 kfree(pmic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001255 }
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301256 platform_set_drvdata(pdev, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257
1258 return 0;
1259}
1260
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301261static struct platform_driver pm8058_driver = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 .probe = pm8058_probe,
1263 .remove = __devexit_p(pm8058_remove),
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301264 .driver = {
1265 .name = "pm8058-core",
1266 .owner = THIS_MODULE,
1267 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268};
1269
1270static int __init pm8058_init(void)
1271{
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301272 return platform_driver_register(&pm8058_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273}
Anirudh Ghayalc2019332011-11-12 06:29:10 +05301274postcore_initcall(pm8058_init);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275
1276static void __exit pm8058_exit(void)
1277{
Anirudh Ghayalf1f1e142011-10-10 17:47:45 +05301278 platform_driver_unregister(&pm8058_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280module_exit(pm8058_exit);
1281
1282MODULE_LICENSE("GPL v2");
1283MODULE_DESCRIPTION("PMIC8058 core driver");
1284MODULE_VERSION("1.0");
1285MODULE_ALIAS("platform:pmic8058-core");