blob: c40f13eb827db2294f3f645ebbe94ec0e6a85b83 [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. 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#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
80
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070081/* check EOC every 10 seconds */
82#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080083/* check for USB unplug every 200 msecs */
84#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086enum chg_fsm_state {
87 FSM_STATE_OFF_0 = 0,
88 FSM_STATE_BATFETDET_START_12 = 12,
89 FSM_STATE_BATFETDET_END_16 = 16,
90 FSM_STATE_ON_CHG_HIGHI_1 = 1,
91 FSM_STATE_ATC_2A = 2,
92 FSM_STATE_ATC_2B = 18,
93 FSM_STATE_ON_BAT_3 = 3,
94 FSM_STATE_ATC_FAIL_4 = 4 ,
95 FSM_STATE_DELAY_5 = 5,
96 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
97 FSM_STATE_FAST_CHG_7 = 7,
98 FSM_STATE_TRKL_CHG_8 = 8,
99 FSM_STATE_CHG_FAIL_9 = 9,
100 FSM_STATE_EOC_10 = 10,
101 FSM_STATE_ON_CHG_VREGOK_11 = 11,
102 FSM_STATE_ATC_PAUSE_13 = 13,
103 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
104 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
105 FSM_STATE_START_BOOT = 20,
106 FSM_STATE_FLCB_VREGOK = 21,
107 FSM_STATE_FLCB = 22,
108};
109
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700110struct fsm_state_to_batt_status {
111 enum chg_fsm_state fsm_state;
112 int batt_state;
113};
114
115static struct fsm_state_to_batt_status map[] = {
116 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
117 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
118 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
119 /*
120 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
121 * too hot/cold, charger too hot
122 */
123 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
124 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
125 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
126 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
127 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
128 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
129 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
130 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
133 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
134 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
135 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
136 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
141};
142
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700143enum chg_regulation_loop {
144 VDD_LOOP = BIT(3),
145 BAT_CURRENT_LOOP = BIT(2),
146 INPUT_CURRENT_LOOP = BIT(1),
147 INPUT_VOLTAGE_LOOP = BIT(0),
148 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
149 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
150};
151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152enum pmic_chg_interrupts {
153 USBIN_VALID_IRQ = 0,
154 USBIN_OV_IRQ,
155 BATT_INSERTED_IRQ,
156 VBATDET_LOW_IRQ,
157 USBIN_UV_IRQ,
158 VBAT_OV_IRQ,
159 CHGWDOG_IRQ,
160 VCP_IRQ,
161 ATCDONE_IRQ,
162 ATCFAIL_IRQ,
163 CHGDONE_IRQ,
164 CHGFAIL_IRQ,
165 CHGSTATE_IRQ,
166 LOOP_CHANGE_IRQ,
167 FASTCHG_IRQ,
168 TRKLCHG_IRQ,
169 BATT_REMOVED_IRQ,
170 BATTTEMP_HOT_IRQ,
171 CHGHOT_IRQ,
172 BATTTEMP_COLD_IRQ,
173 CHG_GONE_IRQ,
174 BAT_TEMP_OK_IRQ,
175 COARSE_DET_LOW_IRQ,
176 VDD_LOOP_IRQ,
177 VREG_OV_IRQ,
178 VBATDET_IRQ,
179 BATFET_IRQ,
180 PSI_IRQ,
181 DCIN_VALID_IRQ,
182 DCIN_OV_IRQ,
183 DCIN_UV_IRQ,
184 PM_CHG_MAX_INTS,
185};
186
187struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700188 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 int is_charging;
190 struct work_struct work;
191};
192
193/**
194 * struct pm8921_chg_chip -device information
195 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 * @usb_present: present status of usb
197 * @dc_present: present status of dc
198 * @usb_charger_current: usb current to charge the battery with used when
199 * the usb path is enabled or charging is resumed
200 * @safety_time: max time for which charging will happen
201 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800202 * @max_voltage_mv: the max volts the batt should be charged up to
203 * @min_voltage_mv: the min battery voltage before turning the FETon
204 * @cool_temp_dc: the cool temp threshold in deciCelcius
205 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700206 * @resume_voltage_delta: the voltage delta from vdd max at which the
207 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @term_current: The charging based term current
209 *
210 */
211struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700212 struct device *dev;
213 unsigned int usb_present;
214 unsigned int dc_present;
215 unsigned int usb_charger_current;
216 unsigned int max_bat_chg_current;
217 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
218 unsigned int safety_time;
219 unsigned int ttrkl_time;
220 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800221 unsigned int max_voltage_mv;
222 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800223 int cool_temp_dc;
224 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700225 unsigned int temp_check_period;
226 unsigned int cool_bat_chg_current;
227 unsigned int warm_bat_chg_current;
228 unsigned int cool_bat_voltage;
229 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700230 unsigned int is_bat_cool;
231 unsigned int is_bat_warm;
232 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700233 unsigned int term_current;
234 unsigned int vbat_channel;
235 unsigned int batt_temp_channel;
236 unsigned int batt_id_channel;
237 struct power_supply usb_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800238 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700239 struct power_supply batt_psy;
240 struct dentry *dent;
241 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800242 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200243 bool ext_charging;
244 bool ext_charge_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700246 struct work_struct battery_id_valid_work;
247 int64_t batt_id_min;
248 int64_t batt_id_max;
249 int trkl_voltage;
250 int weak_voltage;
251 int trkl_current;
252 int weak_current;
253 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800254 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700255 int thermal_levels;
256 struct delayed_work update_heartbeat_work;
257 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800258 struct delayed_work unplug_wrkarnd_restore_work;
259 struct delayed_work unplug_check_work;
260 struct wake_lock unplug_wrkarnd_restore_wake_lock;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700261 struct wake_lock eoc_wake_lock;
262 enum pm8921_chg_cold_thr cold_thr;
263 enum pm8921_chg_hot_thr hot_thr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264};
265
266static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700267static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268
269static struct pm8921_chg_chip *the_chip;
270
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700271static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
274 u8 mask, u8 val)
275{
276 int rc;
277 u8 reg;
278
279 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
280 if (rc) {
281 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
282 return rc;
283 }
284 reg &= ~mask;
285 reg |= val & mask;
286 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
287 if (rc) {
288 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
289 return rc;
290 }
291 return 0;
292}
293
294#define CAPTURE_FSM_STATE_CMD 0xC2
295#define READ_BANK_7 0x70
296#define READ_BANK_4 0x40
297static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
298{
299 u8 temp;
300 int err, ret = 0;
301
302 temp = CAPTURE_FSM_STATE_CMD;
303 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
304 if (err) {
305 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
306 return err;
307 }
308
309 temp = READ_BANK_7;
310 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
311 if (err) {
312 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
313 return err;
314 }
315
316 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
317 if (err) {
318 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
319 return err;
320 }
321 /* get the lower 4 bits */
322 ret = temp & 0xF;
323
324 temp = READ_BANK_4;
325 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
326 if (err) {
327 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
328 return err;
329 }
330
331 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
332 if (err) {
333 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
334 return err;
335 }
336 /* get the upper 1 bit */
337 ret |= (temp & 0x1) << 4;
338 return ret;
339}
340
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700341#define READ_BANK_6 0x60
342static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
343{
344 u8 temp;
345 int err;
346
347 temp = READ_BANK_6;
348 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
349 if (err) {
350 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
351 return err;
352 }
353
354 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
355 if (err) {
356 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
357 return err;
358 }
359
360 /* return the lower 4 bits */
361 return temp & CHG_ALL_LOOPS;
362}
363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364#define CHG_USB_SUSPEND_BIT BIT(2)
365static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
366{
367 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
368 enable ? CHG_USB_SUSPEND_BIT : 0);
369}
370
371#define CHG_EN_BIT BIT(7)
372static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
373{
374 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
375 enable ? CHG_EN_BIT : 0);
376}
377
David Keitel753ec8d2011-11-02 10:56:37 -0700378#define CHG_FAILED_CLEAR BIT(0)
379#define ATC_FAILED_CLEAR BIT(1)
380static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
381{
382 int rc;
383
384 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
385 clear ? ATC_FAILED_CLEAR : 0);
386 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
387 clear ? CHG_FAILED_CLEAR : 0);
388 return rc;
389}
390
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391#define CHG_CHARGE_DIS_BIT BIT(1)
392static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
393{
394 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
395 disable ? CHG_CHARGE_DIS_BIT : 0);
396}
397
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800398static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip)
399{
400 u8 temp = 0;
401
402 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
403 return !!(temp & CHG_CHARGE_DIS_BIT);
404}
405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406#define PM8921_CHG_V_MIN_MV 3240
407#define PM8921_CHG_V_STEP_MV 20
408#define PM8921_CHG_VDDMAX_MAX 4500
409#define PM8921_CHG_VDDMAX_MIN 3400
410#define PM8921_CHG_V_MASK 0x7F
411static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
412{
413 u8 temp;
414
415 if (voltage < PM8921_CHG_VDDMAX_MIN
416 || voltage > PM8921_CHG_VDDMAX_MAX) {
417 pr_err("bad mV=%d asked to set\n", voltage);
418 return -EINVAL;
419 }
420 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
421 pr_debug("voltage=%d setting %02x\n", voltage, temp);
422 return pm_chg_masked_write(chip, CHG_VDD_MAX, PM8921_CHG_V_MASK, temp);
423}
424
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700425static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
426{
427 u8 temp;
428 int rc;
429
430 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
431 if (rc) {
432 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700433 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700434 return rc;
435 }
436 temp &= PM8921_CHG_V_MASK;
437 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
438 return 0;
439}
440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441#define PM8921_CHG_VDDSAFE_MIN 3400
442#define PM8921_CHG_VDDSAFE_MAX 4500
443static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
444{
445 u8 temp;
446
447 if (voltage < PM8921_CHG_VDDSAFE_MIN
448 || voltage > PM8921_CHG_VDDSAFE_MAX) {
449 pr_err("bad mV=%d asked to set\n", voltage);
450 return -EINVAL;
451 }
452 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
453 pr_debug("voltage=%d setting %02x\n", voltage, temp);
454 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
455}
456
457#define PM8921_CHG_VBATDET_MIN 3240
458#define PM8921_CHG_VBATDET_MAX 5780
459static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
460{
461 u8 temp;
462
463 if (voltage < PM8921_CHG_VBATDET_MIN
464 || voltage > PM8921_CHG_VBATDET_MAX) {
465 pr_err("bad mV=%d asked to set\n", voltage);
466 return -EINVAL;
467 }
468 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
469 pr_debug("voltage=%d setting %02x\n", voltage, temp);
470 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
471}
472
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700473#define PM8921_CHG_VINMIN_MIN_MV 3800
474#define PM8921_CHG_VINMIN_STEP_MV 100
475#define PM8921_CHG_VINMIN_USABLE_MAX 6500
476#define PM8921_CHG_VINMIN_USABLE_MIN 4300
477#define PM8921_CHG_VINMIN_MASK 0x1F
478static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
479{
480 u8 temp;
481
482 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
483 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
484 pr_err("bad mV=%d asked to set\n", voltage);
485 return -EINVAL;
486 }
487 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
488 pr_debug("voltage=%d setting %02x\n", voltage, temp);
489 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
490 temp);
491}
492
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800493static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
494{
495 u8 temp;
496 int rc, voltage_mv;
497
498 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
499 temp &= PM8921_CHG_VINMIN_MASK;
500
501 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
502 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
503
504 return voltage_mv;
505}
506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507#define PM8921_CHG_IBATMAX_MIN 325
508#define PM8921_CHG_IBATMAX_MAX 2000
509#define PM8921_CHG_I_MIN_MA 225
510#define PM8921_CHG_I_STEP_MA 50
511#define PM8921_CHG_I_MASK 0x3F
512static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
513{
514 u8 temp;
515
516 if (chg_current < PM8921_CHG_IBATMAX_MIN
517 || chg_current > PM8921_CHG_IBATMAX_MAX) {
518 pr_err("bad mA=%d asked to set\n", chg_current);
519 return -EINVAL;
520 }
521 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
522 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
523}
524
525#define PM8921_CHG_IBATSAFE_MIN 225
526#define PM8921_CHG_IBATSAFE_MAX 3375
527static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
528{
529 u8 temp;
530
531 if (chg_current < PM8921_CHG_IBATSAFE_MIN
532 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
533 pr_err("bad mA=%d asked to set\n", chg_current);
534 return -EINVAL;
535 }
536 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
537 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
538 PM8921_CHG_I_MASK, temp);
539}
540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700542#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#define PM8921_CHG_ITERM_STEP_MA 10
544#define PM8921_CHG_ITERM_MASK 0xF
545static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
546{
547 u8 temp;
548
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700549 if (chg_current < PM8921_CHG_ITERM_MIN_MA
550 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 pr_err("bad mA=%d asked to set\n", chg_current);
552 return -EINVAL;
553 }
554
555 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
556 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700557 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 temp);
559}
560
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700561static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
562{
563 u8 temp;
564 int rc;
565
566 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
567 if (rc) {
568 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700569 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700570 return rc;
571 }
572 temp &= PM8921_CHG_ITERM_MASK;
573 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
574 + PM8921_CHG_ITERM_MIN_MA;
575 return 0;
576}
577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578#define PM8921_CHG_IUSB_MASK 0x1C
579#define PM8921_CHG_IUSB_MAX 7
580#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700581static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582{
583 u8 temp;
584
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700585 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
586 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 return -EINVAL;
588 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700589 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
591 temp);
592}
593
594#define PM8921_CHG_WD_MASK 0x1F
595static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
596{
597 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700598 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
599}
600
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700601#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700602#define PM8921_CHG_TCHG_MIN 4
603#define PM8921_CHG_TCHG_MAX 512
604#define PM8921_CHG_TCHG_STEP 4
605static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
606{
607 u8 temp;
608
609 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
610 pr_err("bad max minutes =%d asked to set\n", minutes);
611 return -EINVAL;
612 }
613
614 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
615 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
616 temp);
617}
618
619#define PM8921_CHG_TTRKL_MASK 0x1F
620#define PM8921_CHG_TTRKL_MIN 1
621#define PM8921_CHG_TTRKL_MAX 64
622static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
623{
624 u8 temp;
625
626 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
627 pr_err("bad max minutes =%d asked to set\n", minutes);
628 return -EINVAL;
629 }
630
631 temp = minutes - 1;
632 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
633 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634}
635
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700636#define PM8921_CHG_VTRKL_MIN_MV 2050
637#define PM8921_CHG_VTRKL_MAX_MV 2800
638#define PM8921_CHG_VTRKL_STEP_MV 50
639#define PM8921_CHG_VTRKL_SHIFT 4
640#define PM8921_CHG_VTRKL_MASK 0xF0
641static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
642{
643 u8 temp;
644
645 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
646 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
647 pr_err("bad voltage = %dmV asked to set\n", millivolts);
648 return -EINVAL;
649 }
650
651 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
652 temp = temp << PM8921_CHG_VTRKL_SHIFT;
653 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
654 temp);
655}
656
657#define PM8921_CHG_VWEAK_MIN_MV 2100
658#define PM8921_CHG_VWEAK_MAX_MV 3600
659#define PM8921_CHG_VWEAK_STEP_MV 100
660#define PM8921_CHG_VWEAK_MASK 0x0F
661static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
662{
663 u8 temp;
664
665 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
666 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
667 pr_err("bad voltage = %dmV asked to set\n", millivolts);
668 return -EINVAL;
669 }
670
671 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
672 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
673 temp);
674}
675
676#define PM8921_CHG_ITRKL_MIN_MA 50
677#define PM8921_CHG_ITRKL_MAX_MA 200
678#define PM8921_CHG_ITRKL_MASK 0x0F
679#define PM8921_CHG_ITRKL_STEP_MA 10
680static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
681{
682 u8 temp;
683
684 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
685 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
686 pr_err("bad current = %dmA asked to set\n", milliamps);
687 return -EINVAL;
688 }
689
690 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
691
692 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
693 temp);
694}
695
696#define PM8921_CHG_IWEAK_MIN_MA 325
697#define PM8921_CHG_IWEAK_MAX_MA 525
698#define PM8921_CHG_IWEAK_SHIFT 7
699#define PM8921_CHG_IWEAK_MASK 0x80
700static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
701{
702 u8 temp;
703
704 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
705 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
706 pr_err("bad current = %dmA asked to set\n", milliamps);
707 return -EINVAL;
708 }
709
710 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
711 temp = 0;
712 else
713 temp = 1;
714
715 temp = temp << PM8921_CHG_IWEAK_SHIFT;
716 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
717 temp);
718}
719
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700720#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
721#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
722static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
723 enum pm8921_chg_cold_thr cold_thr)
724{
725 u8 temp;
726
727 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
728 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
729 return pm_chg_masked_write(chip, CHG_CNTRL_2,
730 PM8921_CHG_BATT_TEMP_THR_COLD,
731 temp);
732}
733
734#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
735#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
736static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
737 enum pm8921_chg_hot_thr hot_thr)
738{
739 u8 temp;
740
741 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
742 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
743 return pm_chg_masked_write(chip, CHG_CNTRL_2,
744 PM8921_CHG_BATT_TEMP_THR_HOT,
745 temp);
746}
747
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700748static int64_t read_battery_id(struct pm8921_chg_chip *chip)
749{
750 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700751 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700752
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700753 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700754 if (rc) {
755 pr_err("error reading batt id channel = %d, rc = %d\n",
756 chip->vbat_channel, rc);
757 return rc;
758 }
759 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
760 result.measurement);
761 return result.physical;
762}
763
764static int is_battery_valid(struct pm8921_chg_chip *chip)
765{
766 int64_t rc;
767
768 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
769 return 1;
770
771 rc = read_battery_id(chip);
772 if (rc < 0) {
773 pr_err("error reading batt id channel = %d, rc = %lld\n",
774 chip->vbat_channel, rc);
775 /* assume battery id is valid when adc error happens */
776 return 1;
777 }
778
779 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
780 pr_err("batt_id phy =%lld is not valid\n", rc);
781 return 0;
782 }
783 return 1;
784}
785
786static void check_battery_valid(struct pm8921_chg_chip *chip)
787{
788 if (is_battery_valid(chip) == 0) {
789 pr_err("batt_id not valid, disbling charging\n");
790 pm_chg_auto_enable(chip, 0);
791 } else {
792 pm_chg_auto_enable(chip, !charging_disabled);
793 }
794}
795
796static void battery_id_valid(struct work_struct *work)
797{
798 struct pm8921_chg_chip *chip = container_of(work,
799 struct pm8921_chg_chip, battery_id_valid_work);
800
801 check_battery_valid(chip);
802}
803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
805{
806 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
807 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
808 enable_irq(chip->pmic_chg_irq[interrupt]);
809 }
810}
811
812static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
813{
814 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
815 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
816 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
817 }
818}
819
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800820static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
821{
822 return test_bit(interrupt, chip->enabled_irqs);
823}
824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
826{
827 return pm8xxx_read_irq_stat(chip->dev->parent,
828 chip->pmic_chg_irq[irq_id]);
829}
830
831/* Treat OverVoltage/UnderVoltage as source missing */
832static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
833{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700834 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835}
836
837/* Treat OverVoltage/UnderVoltage as source missing */
838static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
839{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700840 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841}
842
Amir Samuelovd31ef502011-10-26 14:41:36 +0200843static bool is_ext_charging(struct pm8921_chg_chip *chip)
844{
David Keitel88e1b572012-01-11 11:57:14 -0800845 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200846
David Keitel88e1b572012-01-11 11:57:14 -0800847 if (!chip->ext_psy)
848 return false;
849 if (chip->ext_psy->get_property(chip->ext_psy,
850 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
851 return false;
852 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
853 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200854
855 return false;
856}
857
858static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
859{
David Keitel88e1b572012-01-11 11:57:14 -0800860 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200861
David Keitel88e1b572012-01-11 11:57:14 -0800862 if (!chip->ext_psy)
863 return false;
864 if (chip->ext_psy->get_property(chip->ext_psy,
865 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
866 return false;
867 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +0200868 return true;
869
870 return false;
871}
872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873static int is_battery_charging(int fsm_state)
874{
Amir Samuelovd31ef502011-10-26 14:41:36 +0200875 if (is_ext_charging(the_chip))
876 return 1;
877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 switch (fsm_state) {
879 case FSM_STATE_ATC_2A:
880 case FSM_STATE_ATC_2B:
881 case FSM_STATE_ON_CHG_AND_BAT_6:
882 case FSM_STATE_FAST_CHG_7:
883 case FSM_STATE_TRKL_CHG_8:
884 return 1;
885 }
886 return 0;
887}
888
889static void bms_notify(struct work_struct *work)
890{
891 struct bms_notify *n = container_of(work, struct bms_notify, work);
892
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700893 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700895 } else {
896 pm8921_bms_charging_end(n->is_battery_full);
897 n->is_battery_full = 0;
898 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899}
900
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -0700901static void bms_notify_check(struct pm8921_chg_chip *chip)
902{
903 int fsm_state, new_is_charging;
904
905 fsm_state = pm_chg_get_fsm_state(chip);
906 new_is_charging = is_battery_charging(fsm_state);
907
908 if (chip->bms_notify.is_charging ^ new_is_charging) {
909 chip->bms_notify.is_charging = new_is_charging;
910 schedule_work(&(chip->bms_notify.work));
911 }
912}
913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914static enum power_supply_property pm_power_props[] = {
915 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -0700916 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917};
918
919static char *pm_power_supplied_to[] = {
920 "battery",
921};
922
923static int pm_power_get_property(struct power_supply *psy,
924 enum power_supply_property psp,
925 union power_supply_propval *val)
926{
927 struct pm8921_chg_chip *chip;
928
929 switch (psp) {
930 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -0700931 case POWER_SUPPLY_PROP_ONLINE:
David Keitel6df9cea2011-12-21 12:36:45 -0800932 if (psy->type == POWER_SUPPLY_TYPE_USB ||
933 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
934 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
935 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 chip = container_of(psy, struct pm8921_chg_chip,
937 usb_psy);
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800938 if (pm_is_chg_charge_dis_bit_set(chip))
939 val->intval = 0;
940 else
941 val->intval = is_usb_chg_plugged_in(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 }
943 break;
944 default:
945 return -EINVAL;
946 }
947 return 0;
948}
949
950static enum power_supply_property msm_batt_power_props[] = {
951 POWER_SUPPLY_PROP_STATUS,
952 POWER_SUPPLY_PROP_CHARGE_TYPE,
953 POWER_SUPPLY_PROP_HEALTH,
954 POWER_SUPPLY_PROP_PRESENT,
955 POWER_SUPPLY_PROP_TECHNOLOGY,
956 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
957 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
958 POWER_SUPPLY_PROP_VOLTAGE_NOW,
959 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -0700960 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700961 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -0700962 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963};
964
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800965static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966{
967 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700968 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700970 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 if (rc) {
972 pr_err("error reading adc channel = %d, rc = %d\n",
973 chip->vbat_channel, rc);
974 return rc;
975 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700976 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 result.measurement);
978 return (int)result.physical;
979}
980
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800981static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
982{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800983 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
984 unsigned int current_voltage_mv = current_voltage_uv / 1000;
985 unsigned int low_voltage = chip->min_voltage_mv;
986 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800987
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800988 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800989 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800990 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800991 return 100;
992 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800993 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800994 / (high_voltage - low_voltage);
995}
996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
998{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -0700999 int percent_soc = pm8921_bms_get_percent_charge();
1000
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001001 if (percent_soc == -ENXIO)
1002 percent_soc = voltage_based_capacity(chip);
1003
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001004 if (percent_soc <= 10)
1005 pr_warn("low battery charge = %d%%\n", percent_soc);
1006
1007 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001008}
1009
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001010static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1011{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001012 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001013
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001014 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001015 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001016 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001017 }
1018
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001019 if (rc) {
1020 pr_err("unable to get batt current rc = %d\n", rc);
1021 return rc;
1022 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001023 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001024 }
1025}
1026
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001027static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1028{
1029 int rc;
1030
1031 rc = pm8921_bms_get_fcc();
1032 if (rc < 0)
1033 pr_err("unable to get batt fcc rc = %d\n", rc);
1034 return rc;
1035}
1036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1038{
1039 int temp;
1040
1041 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1042 if (temp)
1043 return POWER_SUPPLY_HEALTH_OVERHEAT;
1044
1045 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1046 if (temp)
1047 return POWER_SUPPLY_HEALTH_COLD;
1048
1049 return POWER_SUPPLY_HEALTH_GOOD;
1050}
1051
1052static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1053{
1054 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1055}
1056
1057static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1058{
1059 int temp;
1060
Amir Samuelovd31ef502011-10-26 14:41:36 +02001061 if (!get_prop_batt_present(chip))
1062 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1063
1064 if (is_ext_trickle_charging(chip))
1065 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1066
1067 if (is_ext_charging(chip))
1068 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1069
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1071 if (temp)
1072 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1073
1074 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1075 if (temp)
1076 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1077
1078 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1079}
1080
1081static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1082{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001083 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1084 int fsm_state = pm_chg_get_fsm_state(chip);
1085 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086
David Keitel88e1b572012-01-11 11:57:14 -08001087 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001088 if (chip->ext_charge_done)
1089 return POWER_SUPPLY_STATUS_FULL;
1090 if (chip->ext_charging)
1091 return POWER_SUPPLY_STATUS_CHARGING;
1092 }
1093
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001094 for (i = 0; i < ARRAY_SIZE(map); i++)
1095 if (map[i].fsm_state == fsm_state)
1096 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001097
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001098 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1099 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1100 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001101 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1102 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001103
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001104 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001105 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001106 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107}
1108
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001109#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001110static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1111{
1112 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001113 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001114
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001115 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001116 if (rc) {
1117 pr_err("error reading adc channel = %d, rc = %d\n",
1118 chip->vbat_channel, rc);
1119 return rc;
1120 }
1121 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1122 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001123 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1124 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1125 (int) result.physical);
1126
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001127 return (int)result.physical;
1128}
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130static int pm_batt_power_get_property(struct power_supply *psy,
1131 enum power_supply_property psp,
1132 union power_supply_propval *val)
1133{
1134 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1135 batt_psy);
1136
1137 switch (psp) {
1138 case POWER_SUPPLY_PROP_STATUS:
1139 val->intval = get_prop_batt_status(chip);
1140 break;
1141 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1142 val->intval = get_prop_charge_type(chip);
1143 break;
1144 case POWER_SUPPLY_PROP_HEALTH:
1145 val->intval = get_prop_batt_health(chip);
1146 break;
1147 case POWER_SUPPLY_PROP_PRESENT:
1148 val->intval = get_prop_batt_present(chip);
1149 break;
1150 case POWER_SUPPLY_PROP_TECHNOLOGY:
1151 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1152 break;
1153 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001154 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 break;
1156 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001157 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 break;
1159 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001160 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 break;
1162 case POWER_SUPPLY_PROP_CAPACITY:
1163 val->intval = get_prop_batt_capacity(chip);
1164 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001165 case POWER_SUPPLY_PROP_CURRENT_NOW:
1166 val->intval = get_prop_batt_current(chip);
1167 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001168 case POWER_SUPPLY_PROP_TEMP:
1169 val->intval = get_prop_batt_temp(chip);
1170 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001171 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001172 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001173 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 default:
1175 return -EINVAL;
1176 }
1177
1178 return 0;
1179}
1180
1181static void (*notify_vbus_state_func_ptr)(int);
1182static int usb_chg_current;
1183static DEFINE_SPINLOCK(vbus_lock);
1184
1185int pm8921_charger_register_vbus_sn(void (*callback)(int))
1186{
1187 pr_debug("%p\n", callback);
1188 notify_vbus_state_func_ptr = callback;
1189 return 0;
1190}
1191EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1192
1193/* this is passed to the hsusb via platform_data msm_otg_pdata */
1194void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1195{
1196 pr_debug("%p\n", callback);
1197 notify_vbus_state_func_ptr = NULL;
1198}
1199EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1200
1201static void notify_usb_of_the_plugin_event(int plugin)
1202{
1203 plugin = !!plugin;
1204 if (notify_vbus_state_func_ptr) {
1205 pr_debug("notifying plugin\n");
1206 (*notify_vbus_state_func_ptr) (plugin);
1207 } else {
1208 pr_debug("unable to notify plugin\n");
1209 }
1210}
1211
1212struct usb_ma_limit_entry {
1213 int usb_ma;
1214 u8 chg_iusb_value;
1215};
1216
1217static struct usb_ma_limit_entry usb_ma_table[] = {
1218 {100, 0},
1219 {500, 1},
1220 {700, 2},
1221 {850, 3},
1222 {900, 4},
1223 {1100, 5},
1224 {1300, 6},
1225 {1500, 7},
1226};
1227
1228/* assumes vbus_lock is held */
1229static void __pm8921_charger_vbus_draw(unsigned int mA)
1230{
1231 int i, rc;
1232
1233 if (mA > 0 && mA <= 2) {
1234 usb_chg_current = 0;
1235 rc = pm_chg_iusbmax_set(the_chip,
1236 usb_ma_table[0].chg_iusb_value);
1237 if (rc) {
1238 pr_err("unable to set iusb to %d rc = %d\n",
1239 usb_ma_table[0].chg_iusb_value, rc);
1240 }
1241 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1242 if (rc)
1243 pr_err("fail to set suspend bit rc=%d\n", rc);
1244 } else {
1245 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1246 if (rc)
1247 pr_err("fail to reset suspend bit rc=%d\n", rc);
1248 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1249 if (usb_ma_table[i].usb_ma <= mA)
1250 break;
1251 }
1252 if (i < 0)
1253 i = 0;
1254 rc = pm_chg_iusbmax_set(the_chip,
1255 usb_ma_table[i].chg_iusb_value);
1256 if (rc) {
1257 pr_err("unable to set iusb to %d rc = %d\n",
1258 usb_ma_table[i].chg_iusb_value, rc);
1259 }
1260 }
1261}
1262
1263/* USB calls these to tell us how much max usb current the system can draw */
1264void pm8921_charger_vbus_draw(unsigned int mA)
1265{
1266 unsigned long flags;
1267
1268 pr_debug("Enter charge=%d\n", mA);
1269 spin_lock_irqsave(&vbus_lock, flags);
1270 if (the_chip) {
1271 __pm8921_charger_vbus_draw(mA);
1272 } else {
1273 /*
1274 * called before pmic initialized,
1275 * save this value and use it at probe
1276 */
1277 usb_chg_current = mA;
1278 }
1279 spin_unlock_irqrestore(&vbus_lock, flags);
1280}
1281EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1282
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001283int pm8921_charger_enable(bool enable)
1284{
1285 int rc;
1286
1287 if (!the_chip) {
1288 pr_err("called before init\n");
1289 return -EINVAL;
1290 }
1291 enable = !!enable;
1292 rc = pm_chg_auto_enable(the_chip, enable);
1293 if (rc)
1294 pr_err("Failed rc=%d\n", rc);
1295 return rc;
1296}
1297EXPORT_SYMBOL(pm8921_charger_enable);
1298
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001299int pm8921_is_usb_chg_plugged_in(void)
1300{
1301 if (!the_chip) {
1302 pr_err("called before init\n");
1303 return -EINVAL;
1304 }
1305 return is_usb_chg_plugged_in(the_chip);
1306}
1307EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1308
1309int pm8921_is_dc_chg_plugged_in(void)
1310{
1311 if (!the_chip) {
1312 pr_err("called before init\n");
1313 return -EINVAL;
1314 }
1315 return is_dc_chg_plugged_in(the_chip);
1316}
1317EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1318
1319int pm8921_is_battery_present(void)
1320{
1321 if (!the_chip) {
1322 pr_err("called before init\n");
1323 return -EINVAL;
1324 }
1325 return get_prop_batt_present(the_chip);
1326}
1327EXPORT_SYMBOL(pm8921_is_battery_present);
1328
David Keitel012deef2011-12-02 11:49:33 -08001329/*
1330 * Disabling the charge current limit causes current
1331 * current limits to have no monitoring. An adequate charger
1332 * capable of supplying high current while sustaining VIN_MIN
1333 * is required if the limiting is disabled.
1334 */
1335int pm8921_disable_input_current_limit(bool disable)
1336{
1337 if (!the_chip) {
1338 pr_err("called before init\n");
1339 return -EINVAL;
1340 }
1341 if (disable) {
1342 pr_warn("Disabling input current limit!\n");
1343
1344 return pm8xxx_writeb(the_chip->dev->parent,
1345 CHG_BUCK_CTRL_TEST3, 0xF2);
1346 }
1347 return 0;
1348}
1349EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1350
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001351int pm8921_set_max_battery_charge_current(int ma)
1352{
1353 if (!the_chip) {
1354 pr_err("called before init\n");
1355 return -EINVAL;
1356 }
1357 return pm_chg_ibatmax_set(the_chip, ma);
1358}
1359EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1360
1361int pm8921_disable_source_current(bool disable)
1362{
1363 if (!the_chip) {
1364 pr_err("called before init\n");
1365 return -EINVAL;
1366 }
1367 if (disable)
1368 pr_warn("current drawn from chg=0, battery provides current\n");
1369 return pm_chg_charge_dis(the_chip, disable);
1370}
1371EXPORT_SYMBOL(pm8921_disable_source_current);
1372
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001373int pm8921_regulate_input_voltage(int voltage)
1374{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001375 int rc;
1376
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001377 if (!the_chip) {
1378 pr_err("called before init\n");
1379 return -EINVAL;
1380 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001381 rc = pm_chg_vinmin_set(the_chip, voltage);
1382
1383 if (rc == 0)
1384 the_chip->vin_min = voltage;
1385
1386 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001387}
1388
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001389#define USB_OV_THRESHOLD_MASK 0x60
1390#define USB_OV_THRESHOLD_SHIFT 5
1391int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1392{
1393 u8 temp;
1394
1395 if (!the_chip) {
1396 pr_err("called before init\n");
1397 return -EINVAL;
1398 }
1399
1400 if (ov > PM_USB_OV_7V) {
1401 pr_err("limiting to over voltage threshold to 7volts\n");
1402 ov = PM_USB_OV_7V;
1403 }
1404
1405 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1406
1407 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1408 USB_OV_THRESHOLD_MASK, temp);
1409}
1410EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1411
1412#define USB_DEBOUNCE_TIME_MASK 0x06
1413#define USB_DEBOUNCE_TIME_SHIFT 1
1414int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1415{
1416 u8 temp;
1417
1418 if (!the_chip) {
1419 pr_err("called before init\n");
1420 return -EINVAL;
1421 }
1422
1423 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1424 pr_err("limiting debounce to 80.5ms\n");
1425 ms = PM_USB_DEBOUNCE_80P5MS;
1426 }
1427
1428 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1429
1430 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1431 USB_DEBOUNCE_TIME_MASK, temp);
1432}
1433EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1434
1435#define USB_OVP_DISABLE_MASK 0x80
1436int pm8921_usb_ovp_disable(int disable)
1437{
1438 u8 temp = 0;
1439
1440 if (!the_chip) {
1441 pr_err("called before init\n");
1442 return -EINVAL;
1443 }
1444
1445 if (disable)
1446 temp = USB_OVP_DISABLE_MASK;
1447
1448 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1449 USB_OVP_DISABLE_MASK, temp);
1450}
1451
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001452bool pm8921_is_battery_charging(int *source)
1453{
1454 int fsm_state, is_charging, dc_present, usb_present;
1455
1456 if (!the_chip) {
1457 pr_err("called before init\n");
1458 return -EINVAL;
1459 }
1460 fsm_state = pm_chg_get_fsm_state(the_chip);
1461 is_charging = is_battery_charging(fsm_state);
1462 if (is_charging == 0) {
1463 *source = PM8921_CHG_SRC_NONE;
1464 return is_charging;
1465 }
1466
1467 if (source == NULL)
1468 return is_charging;
1469
1470 /* the battery is charging, the source is requested, find it */
1471 dc_present = is_dc_chg_plugged_in(the_chip);
1472 usb_present = is_usb_chg_plugged_in(the_chip);
1473
1474 if (dc_present && !usb_present)
1475 *source = PM8921_CHG_SRC_DC;
1476
1477 if (usb_present && !dc_present)
1478 *source = PM8921_CHG_SRC_USB;
1479
1480 if (usb_present && dc_present)
1481 /*
1482 * The system always chooses dc for charging since it has
1483 * higher priority.
1484 */
1485 *source = PM8921_CHG_SRC_DC;
1486
1487 return is_charging;
1488}
1489EXPORT_SYMBOL(pm8921_is_battery_charging);
1490
David Keitel6df9cea2011-12-21 12:36:45 -08001491int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1492{
1493 if (!the_chip) {
1494 pr_err("called before init\n");
1495 return -EINVAL;
1496 }
1497
1498 if (type < POWER_SUPPLY_TYPE_USB)
1499 return -EINVAL;
1500
1501 the_chip->usb_psy.type = type;
1502 power_supply_changed(&the_chip->usb_psy);
1503 return 0;
1504}
1505EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1506
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001507int pm8921_batt_temperature(void)
1508{
1509 if (!the_chip) {
1510 pr_err("called before init\n");
1511 return -EINVAL;
1512 }
1513 return get_prop_batt_temp(the_chip);
1514}
1515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1517{
1518 int usb_present;
1519
1520 usb_present = is_usb_chg_plugged_in(chip);
1521 if (chip->usb_present ^ usb_present) {
1522 notify_usb_of_the_plugin_event(usb_present);
1523 chip->usb_present = usb_present;
1524 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001525 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001527 if (usb_present) {
1528 schedule_delayed_work(&chip->unplug_check_work,
1529 round_jiffies_relative(msecs_to_jiffies
1530 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1531 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001532 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533}
1534
Amir Samuelovd31ef502011-10-26 14:41:36 +02001535static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1536{
David Keitel88e1b572012-01-11 11:57:14 -08001537 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001538 pr_debug("external charger not registered.\n");
1539 return;
1540 }
1541
1542 if (!chip->ext_charging) {
1543 pr_debug("already not charging.\n");
1544 return;
1545 }
1546
David Keitel88e1b572012-01-11 11:57:14 -08001547 power_supply_set_charge_type(chip->ext_psy,
1548 POWER_SUPPLY_CHARGE_TYPE_NONE);
1549 pm8921_disable_source_current(false); /* release BATFET */
Amir Samuelovd31ef502011-10-26 14:41:36 +02001550 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001551 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001552 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001553}
1554
1555static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1556{
1557 int dc_present;
1558 int batt_present;
1559 int batt_temp_ok;
1560 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001561 unsigned long delay =
1562 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1563
David Keitel88e1b572012-01-11 11:57:14 -08001564 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001565 pr_debug("external charger not registered.\n");
1566 return;
1567 }
1568
1569 if (chip->ext_charging) {
1570 pr_debug("already charging.\n");
1571 return;
1572 }
1573
David Keitel88e1b572012-01-11 11:57:14 -08001574 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001575 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1576 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001577
1578 if (!dc_present) {
1579 pr_warn("%s. dc not present.\n", __func__);
1580 return;
1581 }
1582 if (!batt_present) {
1583 pr_warn("%s. battery not present.\n", __func__);
1584 return;
1585 }
1586 if (!batt_temp_ok) {
1587 pr_warn("%s. battery temperature not ok.\n", __func__);
1588 return;
1589 }
David Keitel88e1b572012-01-11 11:57:14 -08001590 pm8921_disable_source_current(true); /* Force BATFET=ON */
1591 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001592 if (vbat_ov) {
1593 pr_warn("%s. battery over voltage.\n", __func__);
1594 return;
1595 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001596
David Keitel88e1b572012-01-11 11:57:14 -08001597 power_supply_set_charge_type(chip->ext_psy,
1598 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001599 chip->ext_charging = true;
1600 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001601 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001602 /* Start BMS */
1603 schedule_delayed_work(&chip->eoc_work, delay);
1604 wake_lock(&chip->eoc_wake_lock);
1605}
1606
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001607#define WRITE_BANK_4 0xC0
1608static void unplug_wrkarnd_restore_worker(struct work_struct *work)
1609{
1610 u8 temp;
1611 int rc;
1612 struct delayed_work *dwork = to_delayed_work(work);
1613 struct pm8921_chg_chip *chip = container_of(dwork,
1614 struct pm8921_chg_chip,
1615 unplug_wrkarnd_restore_work);
1616
1617 pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
1618 rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
1619
1620 temp = WRITE_BANK_4 | 0xA;
1621 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1622 if (rc) {
1623 pr_err("Error %d writing %d to addr %d\n", rc,
1624 temp, CHG_BUCK_CTRL_TEST3);
1625 }
1626 wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
1627}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1629{
1630 handle_usb_insertion_removal(data);
1631 return IRQ_HANDLED;
1632}
1633
1634static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1635{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001636 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 return IRQ_HANDLED;
1638}
1639
1640static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1641{
1642 struct pm8921_chg_chip *chip = data;
1643 int status;
1644
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001645 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1646 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001647 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 pr_debug("battery present=%d", status);
1649 power_supply_changed(&chip->batt_psy);
1650 return IRQ_HANDLED;
1651}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001652
1653/*
1654 * this interrupt used to restart charging a battery.
1655 *
1656 * Note: When DC-inserted the VBAT can't go low.
1657 * VPH_PWR is provided by the ext-charger.
1658 * After End-Of-Charging from DC, charging can be resumed only
1659 * if DC is removed and then inserted after the battery was in use.
1660 * Therefore the handle_start_ext_chg() is not called.
1661 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1663{
1664 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001665 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001667 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001668
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001669 if (high_transition) {
1670 /* enable auto charging */
1671 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001672 pr_info("batt fell below resume voltage %s\n",
1673 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001674 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001675 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 power_supply_changed(&chip->batt_psy);
1678 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 return IRQ_HANDLED;
1681}
1682
1683static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1684{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001685 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 return IRQ_HANDLED;
1687}
1688
1689static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1690{
1691 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1692 return IRQ_HANDLED;
1693}
1694
1695static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1696{
1697 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1698 return IRQ_HANDLED;
1699}
1700
1701static irqreturn_t vcp_irq_handler(int irq, void *data)
1702{
1703 pr_warning("VCP triggered BATDET forced on\n");
1704 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1705 return IRQ_HANDLED;
1706}
1707
1708static irqreturn_t atcdone_irq_handler(int irq, void *data)
1709{
1710 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1711 return IRQ_HANDLED;
1712}
1713
1714static irqreturn_t atcfail_irq_handler(int irq, void *data)
1715{
1716 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1717 return IRQ_HANDLED;
1718}
1719
1720static irqreturn_t chgdone_irq_handler(int irq, void *data)
1721{
1722 struct pm8921_chg_chip *chip = data;
1723
1724 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001725
1726 handle_stop_ext_chg(chip);
1727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 power_supply_changed(&chip->batt_psy);
1729 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001730
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001731 bms_notify_check(chip);
1732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 return IRQ_HANDLED;
1734}
1735
1736static irqreturn_t chgfail_irq_handler(int irq, void *data)
1737{
1738 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001739 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740
David Keitel753ec8d2011-11-02 10:56:37 -07001741 ret = pm_chg_failed_clear(chip, 1);
1742 if (ret)
1743 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1744
1745 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1746 get_prop_batt_present(chip),
1747 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1748 pm_chg_get_fsm_state(data));
1749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750 power_supply_changed(&chip->batt_psy);
1751 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 return IRQ_HANDLED;
1753}
1754
1755static irqreturn_t chgstate_irq_handler(int irq, void *data)
1756{
1757 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758
1759 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1760 power_supply_changed(&chip->batt_psy);
1761 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001763 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 return IRQ_HANDLED;
1766}
1767
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001768#define VIN_ACTIVE_BIT BIT(0)
1769#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
1770#define VIN_MIN_INCREASE_MV 100
1771static void unplug_check_worker(struct work_struct *work)
1772{
1773 struct delayed_work *dwork = to_delayed_work(work);
1774 struct pm8921_chg_chip *chip = container_of(dwork,
1775 struct pm8921_chg_chip, unplug_check_work);
1776 u8 reg_loop;
1777 int ibat, usb_chg_plugged_in;
1778
1779 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1780 if (!usb_chg_plugged_in) {
1781 pr_debug("Stopping Unplug Check Worker since USB is removed"
1782 "reg_loop = %d, fsm = %d ibat = %d\n",
1783 pm_chg_get_regulation_loop(chip),
1784 pm_chg_get_fsm_state(chip),
1785 get_prop_batt_current(chip)
1786 );
1787 return;
1788 }
1789 reg_loop = pm_chg_get_regulation_loop(chip);
1790 pr_debug("reg_loop=0x%x\n", reg_loop);
1791
1792 if (reg_loop & VIN_ACTIVE_BIT) {
1793 ibat = get_prop_batt_current(chip);
1794
1795 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
1796 ibat, pm_chg_get_fsm_state(chip), reg_loop);
1797 if (ibat > 0) {
1798 int err;
1799 u8 temp;
1800
1801 temp = WRITE_BANK_4 | 0xE;
1802 err = pm8xxx_writeb(chip->dev->parent,
1803 CHG_BUCK_CTRL_TEST3, temp);
1804 if (err) {
1805 pr_err("Error %d writing %d to addr %d\n", err,
1806 temp, CHG_BUCK_CTRL_TEST3);
1807 }
1808
1809 pm_chg_vinmin_set(chip,
1810 chip->vin_min + VIN_MIN_INCREASE_MV);
1811
1812 wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
1813 schedule_delayed_work(
1814 &chip->unplug_wrkarnd_restore_work,
1815 round_jiffies_relative(usecs_to_jiffies
1816 (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
1817 }
1818 }
1819
1820 schedule_delayed_work(&chip->unplug_check_work,
1821 round_jiffies_relative(msecs_to_jiffies
1822 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1823}
1824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825static irqreturn_t loop_change_irq_handler(int irq, void *data)
1826{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001827 struct pm8921_chg_chip *chip = data;
1828
1829 pr_debug("fsm_state=%d reg_loop=0x%x\n",
1830 pm_chg_get_fsm_state(data),
1831 pm_chg_get_regulation_loop(data));
1832 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 return IRQ_HANDLED;
1834}
1835
1836static irqreturn_t fastchg_irq_handler(int irq, void *data)
1837{
1838 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001839 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001841 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1842 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
1843 wake_lock(&chip->eoc_wake_lock);
1844 schedule_delayed_work(&chip->eoc_work,
1845 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001846 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001847 }
1848 power_supply_changed(&chip->batt_psy);
1849 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 return IRQ_HANDLED;
1851}
1852
1853static irqreturn_t trklchg_irq_handler(int irq, void *data)
1854{
1855 struct pm8921_chg_chip *chip = data;
1856
1857 power_supply_changed(&chip->batt_psy);
1858 return IRQ_HANDLED;
1859}
1860
1861static irqreturn_t batt_removed_irq_handler(int irq, void *data)
1862{
1863 struct pm8921_chg_chip *chip = data;
1864 int status;
1865
1866 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
1867 pr_debug("battery present=%d state=%d", !status,
1868 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001869 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 power_supply_changed(&chip->batt_psy);
1871 return IRQ_HANDLED;
1872}
1873
1874static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
1875{
1876 struct pm8921_chg_chip *chip = data;
1877
Amir Samuelovd31ef502011-10-26 14:41:36 +02001878 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001879 power_supply_changed(&chip->batt_psy);
1880 return IRQ_HANDLED;
1881}
1882
1883static irqreturn_t chghot_irq_handler(int irq, void *data)
1884{
1885 struct pm8921_chg_chip *chip = data;
1886
1887 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
1888 power_supply_changed(&chip->batt_psy);
1889 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08001890 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891 return IRQ_HANDLED;
1892}
1893
1894static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
1895{
1896 struct pm8921_chg_chip *chip = data;
1897
1898 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001899 handle_stop_ext_chg(chip);
1900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 power_supply_changed(&chip->batt_psy);
1902 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 return IRQ_HANDLED;
1904}
1905
1906static irqreturn_t chg_gone_irq_handler(int irq, void *data)
1907{
1908 struct pm8921_chg_chip *chip = data;
1909
1910 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
1911 power_supply_changed(&chip->batt_psy);
1912 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913 return IRQ_HANDLED;
1914}
David Keitel52fda532011-11-10 10:43:44 -08001915/*
1916 *
1917 * bat_temp_ok_irq_handler - is edge triggered, hence it will
1918 * fire for two cases:
1919 *
1920 * If the interrupt line switches to high temperature is okay
1921 * and thus charging begins.
1922 * If bat_temp_ok is low this means the temperature is now
1923 * too hot or cold, so charging is stopped.
1924 *
1925 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
1927{
David Keitel52fda532011-11-10 10:43:44 -08001928 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929 struct pm8921_chg_chip *chip = data;
1930
David Keitel52fda532011-11-10 10:43:44 -08001931 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
1932
1933 pr_debug("batt_temp_ok = %d fsm_state%d\n",
1934 bat_temp_ok, pm_chg_get_fsm_state(data));
1935
1936 if (bat_temp_ok)
1937 handle_start_ext_chg(chip);
1938 else
1939 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 power_supply_changed(&chip->batt_psy);
1942 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001943 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944 return IRQ_HANDLED;
1945}
1946
1947static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
1948{
1949 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1950 return IRQ_HANDLED;
1951}
1952
1953static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
1954{
1955 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1956 return IRQ_HANDLED;
1957}
1958
1959static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
1960{
1961 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1962 return IRQ_HANDLED;
1963}
1964
1965static irqreturn_t vbatdet_irq_handler(int irq, void *data)
1966{
1967 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1968 return IRQ_HANDLED;
1969}
1970
1971static irqreturn_t batfet_irq_handler(int irq, void *data)
1972{
1973 struct pm8921_chg_chip *chip = data;
1974
1975 pr_debug("vreg ov\n");
1976 power_supply_changed(&chip->batt_psy);
1977 return IRQ_HANDLED;
1978}
1979
1980static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
1981{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001982 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08001983 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001984
David Keitel88e1b572012-01-11 11:57:14 -08001985 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
1986 if (chip->ext_psy)
1987 power_supply_set_online(chip->ext_psy, dc_present);
1988 chip->dc_present = dc_present;
1989 if (dc_present)
1990 handle_start_ext_chg(chip);
1991 else
1992 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 return IRQ_HANDLED;
1994}
1995
1996static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
1997{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001998 struct pm8921_chg_chip *chip = data;
1999
Amir Samuelovd31ef502011-10-26 14:41:36 +02002000 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 return IRQ_HANDLED;
2002}
2003
2004static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2005{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002006 struct pm8921_chg_chip *chip = data;
2007
Amir Samuelovd31ef502011-10-26 14:41:36 +02002008 handle_stop_ext_chg(chip);
2009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 return IRQ_HANDLED;
2011}
2012
David Keitel88e1b572012-01-11 11:57:14 -08002013static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2014{
2015 struct power_supply *psy = &the_chip->batt_psy;
2016 struct power_supply *epsy = dev_get_drvdata(dev);
2017 int i, dcin_irq;
2018
2019 /* Only search for external supply if none is registered */
2020 if (!the_chip->ext_psy) {
2021 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2022 for (i = 0; i < epsy->num_supplicants; i++) {
2023 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2024 if (!strncmp(epsy->name, "dc", 2)) {
2025 the_chip->ext_psy = epsy;
2026 dcin_valid_irq_handler(dcin_irq,
2027 the_chip);
2028 }
2029 }
2030 }
2031 }
2032 return 0;
2033}
2034
2035static void pm_batt_external_power_changed(struct power_supply *psy)
2036{
2037 /* Only look for an external supply if it hasn't been registered */
2038 if (!the_chip->ext_psy)
2039 class_for_each_device(power_supply_class, NULL, psy,
2040 __pm_batt_external_power_changed_work);
2041}
2042
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002043/**
2044 * update_heartbeat - internal function to update userspace
2045 * per update_time minutes
2046 *
2047 */
2048static void update_heartbeat(struct work_struct *work)
2049{
2050 struct delayed_work *dwork = to_delayed_work(work);
2051 struct pm8921_chg_chip *chip = container_of(dwork,
2052 struct pm8921_chg_chip, update_heartbeat_work);
2053
2054 power_supply_changed(&chip->batt_psy);
2055 schedule_delayed_work(&chip->update_heartbeat_work,
2056 round_jiffies_relative(msecs_to_jiffies
2057 (chip->update_time)));
2058}
2059
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002060enum {
2061 CHG_IN_PROGRESS,
2062 CHG_NOT_IN_PROGRESS,
2063 CHG_FINISHED,
2064};
2065
2066#define VBAT_TOLERANCE_MV 70
2067#define CHG_DISABLE_MSLEEP 100
2068static int is_charging_finished(struct pm8921_chg_chip *chip)
2069{
2070 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2071 int ichg_meas_ma, iterm_programmed;
2072 int regulation_loop, fast_chg, vcp;
2073 int rc;
2074 static int last_vbat_programmed = -EINVAL;
2075
2076 if (!is_ext_charging(chip)) {
2077 /* return if the battery is not being fastcharged */
2078 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2079 pr_debug("fast_chg = %d\n", fast_chg);
2080 if (fast_chg == 0)
2081 return CHG_NOT_IN_PROGRESS;
2082
2083 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2084 pr_debug("vcp = %d\n", vcp);
2085 if (vcp == 1)
2086 return CHG_IN_PROGRESS;
2087
2088 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2089 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2090 if (vbatdet_low == 1)
2091 return CHG_IN_PROGRESS;
2092
2093 /* reset count if battery is hot/cold */
2094 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2095 pr_debug("batt_temp_ok = %d\n", rc);
2096 if (rc == 0)
2097 return CHG_IN_PROGRESS;
2098
2099 /* reset count if battery voltage is less than vddmax */
2100 vbat_meas_uv = get_prop_battery_uvolts(chip);
2101 if (vbat_meas_uv < 0)
2102 return CHG_IN_PROGRESS;
2103 vbat_meas_mv = vbat_meas_uv / 1000;
2104
2105 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2106 if (rc) {
2107 pr_err("couldnt read vddmax rc = %d\n", rc);
2108 return CHG_IN_PROGRESS;
2109 }
2110 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2111 vbat_programmed, vbat_meas_mv);
2112 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2113 return CHG_IN_PROGRESS;
2114
2115 if (last_vbat_programmed == -EINVAL)
2116 last_vbat_programmed = vbat_programmed;
2117 if (last_vbat_programmed != vbat_programmed) {
2118 /* vddmax changed, reset and check again */
2119 pr_debug("vddmax = %d last_vdd_max=%d\n",
2120 vbat_programmed, last_vbat_programmed);
2121 last_vbat_programmed = vbat_programmed;
2122 return CHG_IN_PROGRESS;
2123 }
2124
2125 /*
2126 * TODO if charging from an external charger
2127 * check SOC instead of regulation loop
2128 */
2129 regulation_loop = pm_chg_get_regulation_loop(chip);
2130 if (regulation_loop < 0) {
2131 pr_err("couldnt read the regulation loop err=%d\n",
2132 regulation_loop);
2133 return CHG_IN_PROGRESS;
2134 }
2135 pr_debug("regulation_loop=%d\n", regulation_loop);
2136
2137 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2138 return CHG_IN_PROGRESS;
2139 } /* !is_ext_charging */
2140
2141 /* reset count if battery chg current is more than iterm */
2142 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2143 if (rc) {
2144 pr_err("couldnt read iterm rc = %d\n", rc);
2145 return CHG_IN_PROGRESS;
2146 }
2147
2148 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2149 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2150 iterm_programmed, ichg_meas_ma);
2151 /*
2152 * ichg_meas_ma < 0 means battery is drawing current
2153 * ichg_meas_ma > 0 means battery is providing current
2154 */
2155 if (ichg_meas_ma > 0)
2156 return CHG_IN_PROGRESS;
2157
2158 if (ichg_meas_ma * -1 > iterm_programmed)
2159 return CHG_IN_PROGRESS;
2160
2161 return CHG_FINISHED;
2162}
2163
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002164/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002165 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002166 * has happened
2167 *
2168 * If all conditions favouring, if the charge current is
2169 * less than the term current for three consecutive times
2170 * an EOC has happened.
2171 * The wakelock is released if there is no need to reshedule
2172 * - this happens when the battery is removed or EOC has
2173 * happened
2174 */
2175#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002176static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002177{
2178 struct delayed_work *dwork = to_delayed_work(work);
2179 struct pm8921_chg_chip *chip = container_of(dwork,
2180 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002181 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002182 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002183
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002184 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002185 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002186 count = 0;
2187 wake_unlock(&chip->eoc_wake_lock);
2188 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002189 }
2190
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002191 if (end == CHG_FINISHED) {
2192 count++;
2193 } else {
2194 count = 0;
2195 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002196
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002197 if (count == CONSECUTIVE_COUNT) {
2198 count = 0;
2199 pr_info("End of Charging\n");
2200
2201 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002202
Amir Samuelovd31ef502011-10-26 14:41:36 +02002203 if (is_ext_charging(chip))
2204 chip->ext_charge_done = true;
2205
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002206 if (chip->is_bat_warm || chip->is_bat_cool)
2207 chip->bms_notify.is_battery_full = 0;
2208 else
2209 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002210 /* declare end of charging by invoking chgdone interrupt */
2211 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2212 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002213 } else {
2214 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002215 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002216 round_jiffies_relative(msecs_to_jiffies
2217 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002218 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002219}
2220
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002221static void btm_configure_work(struct work_struct *work)
2222{
2223 int rc;
2224
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002225 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002226 if (rc)
2227 pr_err("failed to configure btm rc=%d", rc);
2228}
2229
2230DECLARE_WORK(btm_config_work, btm_configure_work);
2231
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002232static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2233{
2234 unsigned int chg_current = chip->max_bat_chg_current;
2235
2236 if (chip->is_bat_cool)
2237 chg_current = min(chg_current, chip->cool_bat_chg_current);
2238
2239 if (chip->is_bat_warm)
2240 chg_current = min(chg_current, chip->warm_bat_chg_current);
2241
David Keitelfdef3a42011-12-14 19:02:54 -08002242 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002243 chg_current = min(chg_current,
2244 chip->thermal_mitigation[thermal_mitigation]);
2245
2246 pm_chg_ibatmax_set(the_chip, chg_current);
2247}
2248
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002249#define TEMP_HYSTERISIS_DEGC 2
2250static void battery_cool(bool enter)
2251{
2252 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002253 if (enter == the_chip->is_bat_cool)
2254 return;
2255 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002256 if (enter) {
2257 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002258 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002259 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002260 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002261 pm_chg_vbatdet_set(the_chip,
2262 the_chip->cool_bat_voltage
2263 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002264 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002265 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002266 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002267 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002268 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002269 the_chip->max_voltage_mv
2270 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002271 }
2272 schedule_work(&btm_config_work);
2273}
2274
2275static void battery_warm(bool enter)
2276{
2277 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002278 if (enter == the_chip->is_bat_warm)
2279 return;
2280 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002281 if (enter) {
2282 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002283 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002284 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002285 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002286 pm_chg_vbatdet_set(the_chip,
2287 the_chip->warm_bat_voltage
2288 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002289 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002290 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002291 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002292 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002293 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002294 the_chip->max_voltage_mv
2295 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002296 }
2297 schedule_work(&btm_config_work);
2298}
2299
2300static int configure_btm(struct pm8921_chg_chip *chip)
2301{
2302 int rc;
2303
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002304 if (chip->warm_temp_dc != INT_MIN)
2305 btm_config.btm_warm_fn = battery_warm;
2306 else
2307 btm_config.btm_warm_fn = NULL;
2308
2309 if (chip->cool_temp_dc != INT_MIN)
2310 btm_config.btm_cool_fn = battery_cool;
2311 else
2312 btm_config.btm_cool_fn = NULL;
2313
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002314 btm_config.low_thr_temp = chip->cool_temp_dc;
2315 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002316 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002317 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002318 if (rc)
2319 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002320 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002321 if (rc)
2322 pr_err("failed to start btm rc = %d\n", rc);
2323
2324 return rc;
2325}
2326
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002327/**
2328 * set_disable_status_param -
2329 *
2330 * Internal function to disable battery charging and also disable drawing
2331 * any current from the source. The device is forced to run on a battery
2332 * after this.
2333 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334static int set_disable_status_param(const char *val, struct kernel_param *kp)
2335{
2336 int ret;
2337 struct pm8921_chg_chip *chip = the_chip;
2338
2339 ret = param_set_int(val, kp);
2340 if (ret) {
2341 pr_err("error setting value %d\n", ret);
2342 return ret;
2343 }
2344 pr_info("factory set disable param to %d\n", charging_disabled);
2345 if (chip) {
2346 pm_chg_auto_enable(chip, !charging_disabled);
2347 pm_chg_charge_dis(chip, charging_disabled);
2348 }
2349 return 0;
2350}
2351module_param_call(disabled, set_disable_status_param, param_get_uint,
2352 &charging_disabled, 0644);
2353
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002354/**
2355 * set_thermal_mitigation_level -
2356 *
2357 * Internal function to control battery charging current to reduce
2358 * temperature
2359 */
2360static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2361{
2362 int ret;
2363 struct pm8921_chg_chip *chip = the_chip;
2364
2365 ret = param_set_int(val, kp);
2366 if (ret) {
2367 pr_err("error setting value %d\n", ret);
2368 return ret;
2369 }
2370
2371 if (!chip) {
2372 pr_err("called before init\n");
2373 return -EINVAL;
2374 }
2375
2376 if (!chip->thermal_mitigation) {
2377 pr_err("no thermal mitigation\n");
2378 return -EINVAL;
2379 }
2380
2381 if (thermal_mitigation < 0
2382 || thermal_mitigation >= chip->thermal_levels) {
2383 pr_err("out of bound level selected\n");
2384 return -EINVAL;
2385 }
2386
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002387 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002388 return ret;
2389}
2390module_param_call(thermal_mitigation, set_therm_mitigation_level,
2391 param_get_uint,
2392 &thermal_mitigation, 0644);
2393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394static void free_irqs(struct pm8921_chg_chip *chip)
2395{
2396 int i;
2397
2398 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2399 if (chip->pmic_chg_irq[i]) {
2400 free_irq(chip->pmic_chg_irq[i], chip);
2401 chip->pmic_chg_irq[i] = 0;
2402 }
2403}
2404
David Keitel88e1b572012-01-11 11:57:14 -08002405/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002406static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2407{
2408 unsigned long flags;
2409 int fsm_state;
2410
2411 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2412 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2413
2414 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002415 if (chip->usb_present) {
2416 schedule_delayed_work(&chip->unplug_check_work,
2417 round_jiffies_relative(msecs_to_jiffies
2418 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2419 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002420
2421 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2422 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2423 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002424 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2425 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2426 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2427 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2428 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002429 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002430 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2431 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002432 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002433
2434 spin_lock_irqsave(&vbus_lock, flags);
2435 if (usb_chg_current) {
2436 /* reissue a vbus draw call */
2437 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002438 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002439 }
2440 spin_unlock_irqrestore(&vbus_lock, flags);
2441
2442 fsm_state = pm_chg_get_fsm_state(chip);
2443 if (is_battery_charging(fsm_state)) {
2444 chip->bms_notify.is_charging = 1;
2445 pm8921_bms_charging_began();
2446 }
2447
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002448 check_battery_valid(chip);
2449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2451 chip->usb_present,
2452 chip->dc_present,
2453 get_prop_batt_present(chip),
2454 fsm_state);
2455}
2456
2457struct pm_chg_irq_init_data {
2458 unsigned int irq_id;
2459 char *name;
2460 unsigned long flags;
2461 irqreturn_t (*handler)(int, void *);
2462};
2463
2464#define CHG_IRQ(_id, _flags, _handler) \
2465{ \
2466 .irq_id = _id, \
2467 .name = #_id, \
2468 .flags = _flags, \
2469 .handler = _handler, \
2470}
2471struct pm_chg_irq_init_data chg_irq_data[] = {
2472 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2473 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002474 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2476 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002477 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2478 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2480 usbin_uv_irq_handler),
2481 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2482 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2483 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2484 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2485 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2486 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2487 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2488 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2489 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002490 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2491 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2493 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2494 batt_removed_irq_handler),
2495 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2496 batttemp_hot_irq_handler),
2497 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2498 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2499 batttemp_cold_irq_handler),
2500 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002501 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2502 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2504 coarse_det_low_irq_handler),
2505 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2506 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2507 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2508 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2509 batfet_irq_handler),
2510 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2511 dcin_valid_irq_handler),
2512 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2513 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002514 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515};
2516
2517static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2518 struct platform_device *pdev)
2519{
2520 struct resource *res;
2521 int ret, i;
2522
2523 ret = 0;
2524 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2525
2526 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2527 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2528 chg_irq_data[i].name);
2529 if (res == NULL) {
2530 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2531 goto err_out;
2532 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002533 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 ret = request_irq(res->start, chg_irq_data[i].handler,
2535 chg_irq_data[i].flags,
2536 chg_irq_data[i].name, chip);
2537 if (ret < 0) {
2538 pr_err("couldn't request %d (%s) %d\n", res->start,
2539 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002540 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 goto err_out;
2542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2544 }
2545 return 0;
2546
2547err_out:
2548 free_irqs(chip);
2549 return -EINVAL;
2550}
2551
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002552static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2553{
2554 int err;
2555 u8 temp;
2556
2557 temp = 0xD1;
2558 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2559 if (err) {
2560 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2561 return;
2562 }
2563
2564 temp = 0xD3;
2565 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2566 if (err) {
2567 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2568 return;
2569 }
2570
2571 temp = 0xD1;
2572 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2573 if (err) {
2574 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2575 return;
2576 }
2577
2578 temp = 0xD5;
2579 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2580 if (err) {
2581 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2582 return;
2583 }
2584
2585 udelay(183);
2586
2587 temp = 0xD1;
2588 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2589 if (err) {
2590 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2591 return;
2592 }
2593
2594 temp = 0xD0;
2595 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2596 if (err) {
2597 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2598 return;
2599 }
2600 udelay(32);
2601
2602 temp = 0xD1;
2603 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2604 if (err) {
2605 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2606 return;
2607 }
2608
2609 temp = 0xD3;
2610 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2611 if (err) {
2612 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2613 return;
2614 }
2615}
2616
2617static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2618{
2619 int err;
2620 u8 temp;
2621
2622 temp = 0xD1;
2623 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2624 if (err) {
2625 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2626 return;
2627 }
2628
2629 temp = 0xD0;
2630 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2631 if (err) {
2632 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2633 return;
2634 }
2635}
2636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002637#define ENUM_TIMER_STOP_BIT BIT(1)
2638#define BOOT_DONE_BIT BIT(6)
2639#define CHG_BATFET_ON_BIT BIT(3)
2640#define CHG_VCP_EN BIT(0)
2641#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2642#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002643#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2645{
2646 int rc;
2647
2648 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2649 BOOT_DONE_BIT, BOOT_DONE_BIT);
2650 if (rc) {
2651 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2652 return rc;
2653 }
2654
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002655 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002656 if (rc) {
2657 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002658 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 return rc;
2660 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002661 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002662 chip->max_voltage_mv
2663 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664 if (rc) {
2665 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002666 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 return rc;
2668 }
2669
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002670 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671 if (rc) {
2672 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002673 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 return rc;
2675 }
2676 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2677 if (rc) {
2678 pr_err("Failed to set max voltage to %d rc=%d\n",
2679 SAFE_CURRENT_MA, rc);
2680 return rc;
2681 }
2682
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002683 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 if (rc) {
2685 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2686 return rc;
2687 }
2688
2689 rc = pm_chg_iterm_set(chip, chip->term_current);
2690 if (rc) {
2691 pr_err("Failed to set term current to %d rc=%d\n",
2692 chip->term_current, rc);
2693 return rc;
2694 }
2695
2696 /* Disable the ENUM TIMER */
2697 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2698 ENUM_TIMER_STOP_BIT);
2699 if (rc) {
2700 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2701 return rc;
2702 }
2703
2704 /* init with the lowest USB current */
2705 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
2706 if (rc) {
2707 pr_err("Failed to set usb max to %d rc=%d\n",
2708 usb_ma_table[0].chg_iusb_value, rc);
2709 return rc;
2710 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002711
2712 if (chip->safety_time != 0) {
2713 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
2714 if (rc) {
2715 pr_err("Failed to set max time to %d minutes rc=%d\n",
2716 chip->safety_time, rc);
2717 return rc;
2718 }
2719 }
2720
2721 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07002722 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002723 if (rc) {
2724 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
2725 chip->safety_time, rc);
2726 return rc;
2727 }
2728 }
2729
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002730 if (chip->vin_min != 0) {
2731 rc = pm_chg_vinmin_set(chip, chip->vin_min);
2732 if (rc) {
2733 pr_err("Failed to set vin min to %d mV rc=%d\n",
2734 chip->vin_min, rc);
2735 return rc;
2736 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002737 } else {
2738 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002739 }
2740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 rc = pm_chg_disable_wd(chip);
2742 if (rc) {
2743 pr_err("Failed to disable wd rc=%d\n", rc);
2744 return rc;
2745 }
2746
2747 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
2748 CHG_BAT_TEMP_DIS_BIT, 0);
2749 if (rc) {
2750 pr_err("Failed to enable temp control chg rc=%d\n", rc);
2751 return rc;
2752 }
2753 /* switch to a 3.2Mhz for the buck */
2754 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
2755 if (rc) {
2756 pr_err("Failed to switch buck clk rc=%d\n", rc);
2757 return rc;
2758 }
2759
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07002760 if (chip->trkl_voltage != 0) {
2761 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
2762 if (rc) {
2763 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
2764 chip->trkl_voltage, rc);
2765 return rc;
2766 }
2767 }
2768
2769 if (chip->weak_voltage != 0) {
2770 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
2771 if (rc) {
2772 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
2773 chip->weak_voltage, rc);
2774 return rc;
2775 }
2776 }
2777
2778 if (chip->trkl_current != 0) {
2779 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
2780 if (rc) {
2781 pr_err("Failed to set trkl current to %dmA rc=%d\n",
2782 chip->trkl_voltage, rc);
2783 return rc;
2784 }
2785 }
2786
2787 if (chip->weak_current != 0) {
2788 rc = pm_chg_iweak_set(chip, chip->weak_current);
2789 if (rc) {
2790 pr_err("Failed to set weak current to %dmA rc=%d\n",
2791 chip->weak_current, rc);
2792 return rc;
2793 }
2794 }
2795
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07002796 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
2797 if (rc) {
2798 pr_err("Failed to set cold config %d rc=%d\n",
2799 chip->cold_thr, rc);
2800 }
2801
2802 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
2803 if (rc) {
2804 pr_err("Failed to set hot config %d rc=%d\n",
2805 chip->hot_thr, rc);
2806 }
2807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 /* Workarounds for die 1.1 and 1.0 */
2809 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
2810 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
2812 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002813
2814 /* software workaround for correct battery_id detection */
2815 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
2816 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
2817 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
2818 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
2819 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
2820 udelay(100);
2821 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 }
2823
David Keitelb51995e2011-11-18 17:03:31 -08002824 /* Workarounds for die 3.0 */
2825 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
2826 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
2827
2828 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
2829
David Keitela3c0d822011-11-03 14:18:52 -07002830 /* Disable EOC FSM processing */
2831 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
2832
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002833 pm8921_chg_force_19p2mhz_clk(chip);
2834
2835 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
2836 VREF_BATT_THERM_FORCE_ON);
2837 if (rc)
2838 pr_err("Failed to Force Vref therm rc=%d\n", rc);
2839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002840 rc = pm_chg_charge_dis(chip, charging_disabled);
2841 if (rc) {
2842 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
2843 return rc;
2844 }
2845
2846 rc = pm_chg_auto_enable(chip, !charging_disabled);
2847 if (rc) {
2848 pr_err("Failed to enable charging rc=%d\n", rc);
2849 return rc;
2850 }
2851
2852 return 0;
2853}
2854
2855static int get_rt_status(void *data, u64 * val)
2856{
2857 int i = (int)data;
2858 int ret;
2859
2860 /* global irq number is passed in via data */
2861 ret = pm_chg_get_rt_status(the_chip, i);
2862 *val = ret;
2863 return 0;
2864}
2865DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
2866
2867static int get_fsm_status(void *data, u64 * val)
2868{
2869 u8 temp;
2870
2871 temp = pm_chg_get_fsm_state(the_chip);
2872 *val = temp;
2873 return 0;
2874}
2875DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
2876
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002877static int get_reg_loop(void *data, u64 * val)
2878{
2879 u8 temp;
2880
2881 if (!the_chip) {
2882 pr_err("%s called before init\n", __func__);
2883 return -EINVAL;
2884 }
2885 temp = pm_chg_get_regulation_loop(the_chip);
2886 *val = temp;
2887 return 0;
2888}
2889DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
2890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891static int get_reg(void *data, u64 * val)
2892{
2893 int addr = (int)data;
2894 int ret;
2895 u8 temp;
2896
2897 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
2898 if (ret) {
2899 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
2900 addr, temp, ret);
2901 return -EAGAIN;
2902 }
2903 *val = temp;
2904 return 0;
2905}
2906
2907static int set_reg(void *data, u64 val)
2908{
2909 int addr = (int)data;
2910 int ret;
2911 u8 temp;
2912
2913 temp = (u8) val;
2914 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
2915 if (ret) {
2916 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
2917 addr, temp, ret);
2918 return -EAGAIN;
2919 }
2920 return 0;
2921}
2922DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
2923
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002924enum {
2925 BAT_WARM_ZONE,
2926 BAT_COOL_ZONE,
2927};
2928static int get_warm_cool(void *data, u64 * val)
2929{
2930 if (!the_chip) {
2931 pr_err("%s called before init\n", __func__);
2932 return -EINVAL;
2933 }
2934 if ((int)data == BAT_WARM_ZONE)
2935 *val = the_chip->is_bat_warm;
2936 if ((int)data == BAT_COOL_ZONE)
2937 *val = the_chip->is_bat_cool;
2938 return 0;
2939}
2940DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
2941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942static void create_debugfs_entries(struct pm8921_chg_chip *chip)
2943{
2944 int i;
2945
2946 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
2947
2948 if (IS_ERR(chip->dent)) {
2949 pr_err("pmic charger couldnt create debugfs dir\n");
2950 return;
2951 }
2952
2953 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
2954 (void *)CHG_CNTRL, &reg_fops);
2955 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
2956 (void *)CHG_CNTRL_2, &reg_fops);
2957 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
2958 (void *)CHG_CNTRL_3, &reg_fops);
2959 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
2960 (void *)PBL_ACCESS1, &reg_fops);
2961 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
2962 (void *)PBL_ACCESS2, &reg_fops);
2963 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
2964 (void *)SYS_CONFIG_1, &reg_fops);
2965 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
2966 (void *)SYS_CONFIG_2, &reg_fops);
2967 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
2968 (void *)CHG_VDD_MAX, &reg_fops);
2969 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
2970 (void *)CHG_VDD_SAFE, &reg_fops);
2971 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
2972 (void *)CHG_VBAT_DET, &reg_fops);
2973 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
2974 (void *)CHG_IBAT_MAX, &reg_fops);
2975 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
2976 (void *)CHG_IBAT_SAFE, &reg_fops);
2977 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
2978 (void *)CHG_VIN_MIN, &reg_fops);
2979 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
2980 (void *)CHG_VTRICKLE, &reg_fops);
2981 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
2982 (void *)CHG_ITRICKLE, &reg_fops);
2983 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
2984 (void *)CHG_ITERM, &reg_fops);
2985 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
2986 (void *)CHG_TCHG_MAX, &reg_fops);
2987 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
2988 (void *)CHG_TWDOG, &reg_fops);
2989 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
2990 (void *)CHG_TEMP_THRESH, &reg_fops);
2991 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
2992 (void *)CHG_COMP_OVR, &reg_fops);
2993 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
2994 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
2995 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
2996 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
2997 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
2998 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
2999 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3000 (void *)CHG_TEST, &reg_fops);
3001
3002 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3003 &fsm_fops);
3004
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003005 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3006 &reg_loop_fops);
3007
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003008 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3009 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3010 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3011 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3014 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3015 debugfs_create_file(chg_irq_data[i].name, 0444,
3016 chip->dent,
3017 (void *)chg_irq_data[i].irq_id,
3018 &rt_fops);
3019 }
3020}
3021
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003022static int pm8921_charger_suspend_noirq(struct device *dev)
3023{
3024 int rc;
3025 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3026
3027 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3028 if (rc)
3029 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3030 pm8921_chg_set_hw_clk_switching(chip);
3031 return 0;
3032}
3033
3034static int pm8921_charger_resume_noirq(struct device *dev)
3035{
3036 int rc;
3037 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3038
3039 pm8921_chg_force_19p2mhz_clk(chip);
3040
3041 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3042 VREF_BATT_THERM_FORCE_ON);
3043 if (rc)
3044 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3045 return 0;
3046}
3047
David Keitelf2226022011-12-13 15:55:50 -08003048static int pm8921_charger_resume(struct device *dev)
3049{
3050 int rc;
3051 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3052
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003053 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003054 && !(chip->keep_btm_on_suspend)) {
3055 rc = pm8xxx_adc_btm_configure(&btm_config);
3056 if (rc)
3057 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3058
3059 rc = pm8xxx_adc_btm_start();
3060 if (rc)
3061 pr_err("couldn't restart btm rc=%d\n", rc);
3062 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003063 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3064 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3065 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3066 }
David Keitelf2226022011-12-13 15:55:50 -08003067 return 0;
3068}
3069
3070static int pm8921_charger_suspend(struct device *dev)
3071{
3072 int rc;
3073 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3074
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003075 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003076 && !(chip->keep_btm_on_suspend)) {
3077 rc = pm8xxx_adc_btm_end();
3078 if (rc)
3079 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3080 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003081
3082 if (is_usb_chg_plugged_in(chip)) {
3083 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3084 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3085 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003086
David Keitelf2226022011-12-13 15:55:50 -08003087 return 0;
3088}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3090{
3091 int rc = 0;
3092 struct pm8921_chg_chip *chip;
3093 const struct pm8921_charger_platform_data *pdata
3094 = pdev->dev.platform_data;
3095
3096 if (!pdata) {
3097 pr_err("missing platform data\n");
3098 return -EINVAL;
3099 }
3100
3101 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3102 GFP_KERNEL);
3103 if (!chip) {
3104 pr_err("Cannot allocate pm_chg_chip\n");
3105 return -ENOMEM;
3106 }
3107
3108 chip->dev = &pdev->dev;
3109 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003110 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003112 chip->max_voltage_mv = pdata->max_voltage;
3113 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003114 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 chip->term_current = pdata->term_current;
3116 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003117 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003118 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3119 chip->batt_id_min = pdata->batt_id_min;
3120 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003121 if (pdata->cool_temp != INT_MIN)
3122 chip->cool_temp_dc = pdata->cool_temp * 10;
3123 else
3124 chip->cool_temp_dc = INT_MIN;
3125
3126 if (pdata->warm_temp != INT_MIN)
3127 chip->warm_temp_dc = pdata->warm_temp * 10;
3128 else
3129 chip->warm_temp_dc = INT_MIN;
3130
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003131 chip->temp_check_period = pdata->temp_check_period;
3132 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3133 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3134 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3135 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3136 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003137 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003138 chip->trkl_voltage = pdata->trkl_voltage;
3139 chip->weak_voltage = pdata->weak_voltage;
3140 chip->trkl_current = pdata->trkl_current;
3141 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003142 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003143 chip->thermal_mitigation = pdata->thermal_mitigation;
3144 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003146 chip->cold_thr = pdata->cold_thr;
3147 chip->hot_thr = pdata->hot_thr;
3148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003149 rc = pm8921_chg_hw_init(chip);
3150 if (rc) {
3151 pr_err("couldn't init hardware rc=%d\n", rc);
3152 goto free_chip;
3153 }
3154
3155 chip->usb_psy.name = "usb",
3156 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3157 chip->usb_psy.supplied_to = pm_power_supplied_to,
3158 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3159 chip->usb_psy.properties = pm_power_props,
3160 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3161 chip->usb_psy.get_property = pm_power_get_property,
3162
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 chip->batt_psy.name = "battery",
3164 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3165 chip->batt_psy.properties = msm_batt_power_props,
3166 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3167 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003168 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169 rc = power_supply_register(chip->dev, &chip->usb_psy);
3170 if (rc < 0) {
3171 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003172 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 }
3174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 rc = power_supply_register(chip->dev, &chip->batt_psy);
3176 if (rc < 0) {
3177 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel88e1b572012-01-11 11:57:14 -08003178 goto unregister_usb;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003179 }
3180
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003181 platform_set_drvdata(pdev, chip);
3182 the_chip = chip;
3183
3184 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003185 wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
3186 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003187 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003188 INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
3189 unplug_wrkarnd_restore_worker);
3190 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 rc = request_irqs(chip, pdev);
3193 if (rc) {
3194 pr_err("couldn't register interrupts rc=%d\n", rc);
3195 goto unregister_batt;
3196 }
3197
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003198 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3199 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3200 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003201 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3202 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003203 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003204 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003205 * care for jeita compliance
3206 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003207 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003208 rc = configure_btm(chip);
3209 if (rc) {
3210 pr_err("couldn't register with btm rc=%d\n", rc);
3211 goto free_irq;
3212 }
3213 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 create_debugfs_entries(chip);
3216
3217 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003218 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 /* determine what state the charger is in */
3221 determine_initial_state(chip);
3222
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003223 if (chip->update_time) {
3224 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3225 update_heartbeat);
3226 schedule_delayed_work(&chip->update_heartbeat_work,
3227 round_jiffies_relative(msecs_to_jiffies
3228 (chip->update_time)));
3229 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230 return 0;
3231
3232free_irq:
3233 free_irqs(chip);
3234unregister_batt:
3235 power_supply_unregister(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003236unregister_usb:
3237 power_supply_unregister(&chip->usb_psy);
3238free_chip:
3239 kfree(chip);
3240 return rc;
3241}
3242
3243static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3244{
3245 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3246
3247 free_irqs(chip);
3248 platform_set_drvdata(pdev, NULL);
3249 the_chip = NULL;
3250 kfree(chip);
3251 return 0;
3252}
David Keitelf2226022011-12-13 15:55:50 -08003253static const struct dev_pm_ops pm8921_pm_ops = {
3254 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003255 .suspend_noirq = pm8921_charger_suspend_noirq,
3256 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003257 .resume = pm8921_charger_resume,
3258};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003260 .probe = pm8921_charger_probe,
3261 .remove = __devexit_p(pm8921_charger_remove),
3262 .driver = {
3263 .name = PM8921_CHARGER_DEV_NAME,
3264 .owner = THIS_MODULE,
3265 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 },
3267};
3268
3269static int __init pm8921_charger_init(void)
3270{
3271 return platform_driver_register(&pm8921_charger_driver);
3272}
3273
3274static void __exit pm8921_charger_exit(void)
3275{
3276 platform_driver_unregister(&pm8921_charger_driver);
3277}
3278
3279late_initcall(pm8921_charger_init);
3280module_exit(pm8921_charger_exit);
3281
3282MODULE_LICENSE("GPL v2");
3283MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3284MODULE_VERSION("1.0");
3285MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);