blob: 77e7b8911c25286fb64af1598916f2be73bbae18 [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;
223 unsigned int cool_temp_dc;
224 unsigned 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;
238 struct power_supply dc_psy;
239 struct power_supply batt_psy;
240 struct dentry *dent;
241 struct bms_notify bms_notify;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200242 struct ext_chg_pm8921 *ext;
David Keitelf2226022011-12-13 15:55:50 -0800243 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200244 bool ext_charging;
245 bool ext_charge_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 struct work_struct battery_id_valid_work;
248 int64_t batt_id_min;
249 int64_t batt_id_max;
250 int trkl_voltage;
251 int weak_voltage;
252 int trkl_current;
253 int weak_current;
254 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800255 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700256 int thermal_levels;
257 struct delayed_work update_heartbeat_work;
258 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800259 struct delayed_work unplug_wrkarnd_restore_work;
260 struct delayed_work unplug_check_work;
261 struct wake_lock unplug_wrkarnd_restore_wake_lock;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct wake_lock eoc_wake_lock;
263 enum pm8921_chg_cold_thr cold_thr;
264 enum pm8921_chg_hot_thr hot_thr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265};
266
267static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700268static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269
270static struct pm8921_chg_chip *the_chip;
271
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700272static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
275 u8 mask, u8 val)
276{
277 int rc;
278 u8 reg;
279
280 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
281 if (rc) {
282 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
283 return rc;
284 }
285 reg &= ~mask;
286 reg |= val & mask;
287 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
288 if (rc) {
289 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
290 return rc;
291 }
292 return 0;
293}
294
295#define CAPTURE_FSM_STATE_CMD 0xC2
296#define READ_BANK_7 0x70
297#define READ_BANK_4 0x40
298static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
299{
300 u8 temp;
301 int err, ret = 0;
302
303 temp = CAPTURE_FSM_STATE_CMD;
304 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
305 if (err) {
306 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
307 return err;
308 }
309
310 temp = READ_BANK_7;
311 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
312 if (err) {
313 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
314 return err;
315 }
316
317 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
318 if (err) {
319 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
320 return err;
321 }
322 /* get the lower 4 bits */
323 ret = temp & 0xF;
324
325 temp = READ_BANK_4;
326 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
327 if (err) {
328 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
329 return err;
330 }
331
332 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
333 if (err) {
334 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
335 return err;
336 }
337 /* get the upper 1 bit */
338 ret |= (temp & 0x1) << 4;
339 return ret;
340}
341
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700342#define READ_BANK_6 0x60
343static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
344{
345 u8 temp;
346 int err;
347
348 temp = READ_BANK_6;
349 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
350 if (err) {
351 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
352 return err;
353 }
354
355 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
356 if (err) {
357 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
358 return err;
359 }
360
361 /* return the lower 4 bits */
362 return temp & CHG_ALL_LOOPS;
363}
364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365#define CHG_USB_SUSPEND_BIT BIT(2)
366static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
367{
368 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
369 enable ? CHG_USB_SUSPEND_BIT : 0);
370}
371
372#define CHG_EN_BIT BIT(7)
373static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
374{
375 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
376 enable ? CHG_EN_BIT : 0);
377}
378
David Keitel753ec8d2011-11-02 10:56:37 -0700379#define CHG_FAILED_CLEAR BIT(0)
380#define ATC_FAILED_CLEAR BIT(1)
381static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
382{
383 int rc;
384
385 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
386 clear ? ATC_FAILED_CLEAR : 0);
387 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
388 clear ? CHG_FAILED_CLEAR : 0);
389 return rc;
390}
391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392#define CHG_CHARGE_DIS_BIT BIT(1)
393static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
394{
395 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
396 disable ? CHG_CHARGE_DIS_BIT : 0);
397}
398
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800399static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip)
400{
401 u8 temp = 0;
402
403 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
404 return !!(temp & CHG_CHARGE_DIS_BIT);
405}
406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407#define PM8921_CHG_V_MIN_MV 3240
408#define PM8921_CHG_V_STEP_MV 20
409#define PM8921_CHG_VDDMAX_MAX 4500
410#define PM8921_CHG_VDDMAX_MIN 3400
411#define PM8921_CHG_V_MASK 0x7F
412static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
413{
414 u8 temp;
415
416 if (voltage < PM8921_CHG_VDDMAX_MIN
417 || voltage > PM8921_CHG_VDDMAX_MAX) {
418 pr_err("bad mV=%d asked to set\n", voltage);
419 return -EINVAL;
420 }
421 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
422 pr_debug("voltage=%d setting %02x\n", voltage, temp);
423 return pm_chg_masked_write(chip, CHG_VDD_MAX, PM8921_CHG_V_MASK, temp);
424}
425
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700426static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
427{
428 u8 temp;
429 int rc;
430
431 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
432 if (rc) {
433 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700434 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700435 return rc;
436 }
437 temp &= PM8921_CHG_V_MASK;
438 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
439 return 0;
440}
441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442#define PM8921_CHG_VDDSAFE_MIN 3400
443#define PM8921_CHG_VDDSAFE_MAX 4500
444static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
445{
446 u8 temp;
447
448 if (voltage < PM8921_CHG_VDDSAFE_MIN
449 || voltage > PM8921_CHG_VDDSAFE_MAX) {
450 pr_err("bad mV=%d asked to set\n", voltage);
451 return -EINVAL;
452 }
453 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
454 pr_debug("voltage=%d setting %02x\n", voltage, temp);
455 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
456}
457
458#define PM8921_CHG_VBATDET_MIN 3240
459#define PM8921_CHG_VBATDET_MAX 5780
460static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
461{
462 u8 temp;
463
464 if (voltage < PM8921_CHG_VBATDET_MIN
465 || voltage > PM8921_CHG_VBATDET_MAX) {
466 pr_err("bad mV=%d asked to set\n", voltage);
467 return -EINVAL;
468 }
469 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
470 pr_debug("voltage=%d setting %02x\n", voltage, temp);
471 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
472}
473
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700474#define PM8921_CHG_VINMIN_MIN_MV 3800
475#define PM8921_CHG_VINMIN_STEP_MV 100
476#define PM8921_CHG_VINMIN_USABLE_MAX 6500
477#define PM8921_CHG_VINMIN_USABLE_MIN 4300
478#define PM8921_CHG_VINMIN_MASK 0x1F
479static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
480{
481 u8 temp;
482
483 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
484 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
485 pr_err("bad mV=%d asked to set\n", voltage);
486 return -EINVAL;
487 }
488 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
489 pr_debug("voltage=%d setting %02x\n", voltage, temp);
490 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
491 temp);
492}
493
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800494static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
495{
496 u8 temp;
497 int rc, voltage_mv;
498
499 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
500 temp &= PM8921_CHG_VINMIN_MASK;
501
502 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
503 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
504
505 return voltage_mv;
506}
507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508#define PM8921_CHG_IBATMAX_MIN 325
509#define PM8921_CHG_IBATMAX_MAX 2000
510#define PM8921_CHG_I_MIN_MA 225
511#define PM8921_CHG_I_STEP_MA 50
512#define PM8921_CHG_I_MASK 0x3F
513static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
514{
515 u8 temp;
516
517 if (chg_current < PM8921_CHG_IBATMAX_MIN
518 || chg_current > PM8921_CHG_IBATMAX_MAX) {
519 pr_err("bad mA=%d asked to set\n", chg_current);
520 return -EINVAL;
521 }
522 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
523 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
524}
525
526#define PM8921_CHG_IBATSAFE_MIN 225
527#define PM8921_CHG_IBATSAFE_MAX 3375
528static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
529{
530 u8 temp;
531
532 if (chg_current < PM8921_CHG_IBATSAFE_MIN
533 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
534 pr_err("bad mA=%d asked to set\n", chg_current);
535 return -EINVAL;
536 }
537 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
538 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
539 PM8921_CHG_I_MASK, temp);
540}
541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700543#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544#define PM8921_CHG_ITERM_STEP_MA 10
545#define PM8921_CHG_ITERM_MASK 0xF
546static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
547{
548 u8 temp;
549
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700550 if (chg_current < PM8921_CHG_ITERM_MIN_MA
551 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552 pr_err("bad mA=%d asked to set\n", chg_current);
553 return -EINVAL;
554 }
555
556 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
557 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700558 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559 temp);
560}
561
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700562static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
563{
564 u8 temp;
565 int rc;
566
567 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
568 if (rc) {
569 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700570 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700571 return rc;
572 }
573 temp &= PM8921_CHG_ITERM_MASK;
574 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
575 + PM8921_CHG_ITERM_MIN_MA;
576 return 0;
577}
578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579#define PM8921_CHG_IUSB_MASK 0x1C
580#define PM8921_CHG_IUSB_MAX 7
581#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700582static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583{
584 u8 temp;
585
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700586 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
587 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 return -EINVAL;
589 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700590 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
592 temp);
593}
594
595#define PM8921_CHG_WD_MASK 0x1F
596static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
597{
598 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700599 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
600}
601
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700602#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700603#define PM8921_CHG_TCHG_MIN 4
604#define PM8921_CHG_TCHG_MAX 512
605#define PM8921_CHG_TCHG_STEP 4
606static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
607{
608 u8 temp;
609
610 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
611 pr_err("bad max minutes =%d asked to set\n", minutes);
612 return -EINVAL;
613 }
614
615 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
616 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
617 temp);
618}
619
620#define PM8921_CHG_TTRKL_MASK 0x1F
621#define PM8921_CHG_TTRKL_MIN 1
622#define PM8921_CHG_TTRKL_MAX 64
623static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
624{
625 u8 temp;
626
627 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
628 pr_err("bad max minutes =%d asked to set\n", minutes);
629 return -EINVAL;
630 }
631
632 temp = minutes - 1;
633 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
634 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635}
636
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700637#define PM8921_CHG_VTRKL_MIN_MV 2050
638#define PM8921_CHG_VTRKL_MAX_MV 2800
639#define PM8921_CHG_VTRKL_STEP_MV 50
640#define PM8921_CHG_VTRKL_SHIFT 4
641#define PM8921_CHG_VTRKL_MASK 0xF0
642static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
643{
644 u8 temp;
645
646 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
647 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
648 pr_err("bad voltage = %dmV asked to set\n", millivolts);
649 return -EINVAL;
650 }
651
652 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
653 temp = temp << PM8921_CHG_VTRKL_SHIFT;
654 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
655 temp);
656}
657
658#define PM8921_CHG_VWEAK_MIN_MV 2100
659#define PM8921_CHG_VWEAK_MAX_MV 3600
660#define PM8921_CHG_VWEAK_STEP_MV 100
661#define PM8921_CHG_VWEAK_MASK 0x0F
662static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
663{
664 u8 temp;
665
666 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
667 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
668 pr_err("bad voltage = %dmV asked to set\n", millivolts);
669 return -EINVAL;
670 }
671
672 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
673 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
674 temp);
675}
676
677#define PM8921_CHG_ITRKL_MIN_MA 50
678#define PM8921_CHG_ITRKL_MAX_MA 200
679#define PM8921_CHG_ITRKL_MASK 0x0F
680#define PM8921_CHG_ITRKL_STEP_MA 10
681static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
682{
683 u8 temp;
684
685 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
686 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
687 pr_err("bad current = %dmA asked to set\n", milliamps);
688 return -EINVAL;
689 }
690
691 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
692
693 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
694 temp);
695}
696
697#define PM8921_CHG_IWEAK_MIN_MA 325
698#define PM8921_CHG_IWEAK_MAX_MA 525
699#define PM8921_CHG_IWEAK_SHIFT 7
700#define PM8921_CHG_IWEAK_MASK 0x80
701static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
702{
703 u8 temp;
704
705 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
706 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
707 pr_err("bad current = %dmA asked to set\n", milliamps);
708 return -EINVAL;
709 }
710
711 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
712 temp = 0;
713 else
714 temp = 1;
715
716 temp = temp << PM8921_CHG_IWEAK_SHIFT;
717 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
718 temp);
719}
720
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700721#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
722#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
723static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
724 enum pm8921_chg_cold_thr cold_thr)
725{
726 u8 temp;
727
728 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
729 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
730 return pm_chg_masked_write(chip, CHG_CNTRL_2,
731 PM8921_CHG_BATT_TEMP_THR_COLD,
732 temp);
733}
734
735#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
736#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
737static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
738 enum pm8921_chg_hot_thr hot_thr)
739{
740 u8 temp;
741
742 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
743 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
744 return pm_chg_masked_write(chip, CHG_CNTRL_2,
745 PM8921_CHG_BATT_TEMP_THR_HOT,
746 temp);
747}
748
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700749static int64_t read_battery_id(struct pm8921_chg_chip *chip)
750{
751 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700752 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700753
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700754 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700755 if (rc) {
756 pr_err("error reading batt id channel = %d, rc = %d\n",
757 chip->vbat_channel, rc);
758 return rc;
759 }
760 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
761 result.measurement);
762 return result.physical;
763}
764
765static int is_battery_valid(struct pm8921_chg_chip *chip)
766{
767 int64_t rc;
768
769 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
770 return 1;
771
772 rc = read_battery_id(chip);
773 if (rc < 0) {
774 pr_err("error reading batt id channel = %d, rc = %lld\n",
775 chip->vbat_channel, rc);
776 /* assume battery id is valid when adc error happens */
777 return 1;
778 }
779
780 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
781 pr_err("batt_id phy =%lld is not valid\n", rc);
782 return 0;
783 }
784 return 1;
785}
786
787static void check_battery_valid(struct pm8921_chg_chip *chip)
788{
789 if (is_battery_valid(chip) == 0) {
790 pr_err("batt_id not valid, disbling charging\n");
791 pm_chg_auto_enable(chip, 0);
792 } else {
793 pm_chg_auto_enable(chip, !charging_disabled);
794 }
795}
796
797static void battery_id_valid(struct work_struct *work)
798{
799 struct pm8921_chg_chip *chip = container_of(work,
800 struct pm8921_chg_chip, battery_id_valid_work);
801
802 check_battery_valid(chip);
803}
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
806{
807 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
808 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
809 enable_irq(chip->pmic_chg_irq[interrupt]);
810 }
811}
812
813static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
814{
815 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
816 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
817 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
818 }
819}
820
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800821static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
822{
823 return test_bit(interrupt, chip->enabled_irqs);
824}
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
827{
828 return pm8xxx_read_irq_stat(chip->dev->parent,
829 chip->pmic_chg_irq[irq_id]);
830}
831
832/* Treat OverVoltage/UnderVoltage as source missing */
833static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
834{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700835 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836}
837
838/* Treat OverVoltage/UnderVoltage as source missing */
839static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
840{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700841 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842}
843
Amir Samuelovd31ef502011-10-26 14:41:36 +0200844static bool is_ext_charging(struct pm8921_chg_chip *chip)
845{
846 if (chip->ext == NULL)
847 return false;
848
849 if (chip->ext_charging)
850 return true;
851
852 return false;
853}
854
855static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
856{
857 if (chip->ext == NULL)
858 return false;
859
860 if (chip->ext->is_trickle(chip->ext->ctx))
861 return true;
862
863 return false;
864}
865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866static int is_battery_charging(int fsm_state)
867{
Amir Samuelovd31ef502011-10-26 14:41:36 +0200868 if (is_ext_charging(the_chip))
869 return 1;
870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871 switch (fsm_state) {
872 case FSM_STATE_ATC_2A:
873 case FSM_STATE_ATC_2B:
874 case FSM_STATE_ON_CHG_AND_BAT_6:
875 case FSM_STATE_FAST_CHG_7:
876 case FSM_STATE_TRKL_CHG_8:
877 return 1;
878 }
879 return 0;
880}
881
882static void bms_notify(struct work_struct *work)
883{
884 struct bms_notify *n = container_of(work, struct bms_notify, work);
885
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700886 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700888 } else {
889 pm8921_bms_charging_end(n->is_battery_full);
890 n->is_battery_full = 0;
891 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892}
893
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -0700894static void bms_notify_check(struct pm8921_chg_chip *chip)
895{
896 int fsm_state, new_is_charging;
897
898 fsm_state = pm_chg_get_fsm_state(chip);
899 new_is_charging = is_battery_charging(fsm_state);
900
901 if (chip->bms_notify.is_charging ^ new_is_charging) {
902 chip->bms_notify.is_charging = new_is_charging;
903 schedule_work(&(chip->bms_notify.work));
904 }
905}
906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907static enum power_supply_property pm_power_props[] = {
908 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -0700909 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910};
911
912static char *pm_power_supplied_to[] = {
913 "battery",
914};
915
916static int pm_power_get_property(struct power_supply *psy,
917 enum power_supply_property psp,
918 union power_supply_propval *val)
919{
920 struct pm8921_chg_chip *chip;
921
922 switch (psp) {
923 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -0700924 case POWER_SUPPLY_PROP_ONLINE:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
926 chip = container_of(psy, struct pm8921_chg_chip,
927 dc_psy);
928 val->intval = is_dc_chg_plugged_in(chip);
929 }
David Keitel6df9cea2011-12-21 12:36:45 -0800930 if (psy->type == POWER_SUPPLY_TYPE_USB ||
931 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
932 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
933 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 chip = container_of(psy, struct pm8921_chg_chip,
935 usb_psy);
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800936 if (pm_is_chg_charge_dis_bit_set(chip))
937 val->intval = 0;
938 else
939 val->intval = is_usb_chg_plugged_in(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940 }
941 break;
942 default:
943 return -EINVAL;
944 }
945 return 0;
946}
947
948static enum power_supply_property msm_batt_power_props[] = {
949 POWER_SUPPLY_PROP_STATUS,
950 POWER_SUPPLY_PROP_CHARGE_TYPE,
951 POWER_SUPPLY_PROP_HEALTH,
952 POWER_SUPPLY_PROP_PRESENT,
953 POWER_SUPPLY_PROP_TECHNOLOGY,
954 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
955 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
956 POWER_SUPPLY_PROP_VOLTAGE_NOW,
957 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -0700958 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700959 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -0700960 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961};
962
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800963static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964{
965 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700966 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700968 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969 if (rc) {
970 pr_err("error reading adc channel = %d, rc = %d\n",
971 chip->vbat_channel, rc);
972 return rc;
973 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700974 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975 result.measurement);
976 return (int)result.physical;
977}
978
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800979static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
980{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800981 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
982 unsigned int current_voltage_mv = current_voltage_uv / 1000;
983 unsigned int low_voltage = chip->min_voltage_mv;
984 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800985
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800986 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800987 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800988 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800989 return 100;
990 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800991 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800992 / (high_voltage - low_voltage);
993}
994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
996{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -0700997 int percent_soc = pm8921_bms_get_percent_charge();
998
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -0800999 if (percent_soc == -ENXIO)
1000 percent_soc = voltage_based_capacity(chip);
1001
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001002 if (percent_soc <= 10)
1003 pr_warn("low battery charge = %d%%\n", percent_soc);
1004
1005 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006}
1007
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001008static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1009{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001010 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001011
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001012 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001013 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001014 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001015 }
1016
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001017 if (rc) {
1018 pr_err("unable to get batt current rc = %d\n", rc);
1019 return rc;
1020 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001021 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001022 }
1023}
1024
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001025static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1026{
1027 int rc;
1028
1029 rc = pm8921_bms_get_fcc();
1030 if (rc < 0)
1031 pr_err("unable to get batt fcc rc = %d\n", rc);
1032 return rc;
1033}
1034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1036{
1037 int temp;
1038
1039 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1040 if (temp)
1041 return POWER_SUPPLY_HEALTH_OVERHEAT;
1042
1043 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1044 if (temp)
1045 return POWER_SUPPLY_HEALTH_COLD;
1046
1047 return POWER_SUPPLY_HEALTH_GOOD;
1048}
1049
1050static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1051{
1052 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1053}
1054
1055static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1056{
1057 int temp;
1058
Amir Samuelovd31ef502011-10-26 14:41:36 +02001059 if (!get_prop_batt_present(chip))
1060 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1061
1062 if (is_ext_trickle_charging(chip))
1063 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1064
1065 if (is_ext_charging(chip))
1066 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1069 if (temp)
1070 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1071
1072 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1073 if (temp)
1074 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1075
1076 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1077}
1078
1079static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1080{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001081 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1082 int fsm_state = pm_chg_get_fsm_state(chip);
1083 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084
David Keiteld4e59ef2011-11-09 17:38:31 -08001085 if (chip->ext) {
1086 if (chip->ext_charge_done)
1087 return POWER_SUPPLY_STATUS_FULL;
1088 if (chip->ext_charging)
1089 return POWER_SUPPLY_STATUS_CHARGING;
1090 }
1091
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001092 for (i = 0; i < ARRAY_SIZE(map); i++)
1093 if (map[i].fsm_state == fsm_state)
1094 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001095
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001096 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1097 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1098 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001099 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1100 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001101
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001102 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001103 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001104 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105}
1106
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001107#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001108static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1109{
1110 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001111 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001112
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001113 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001114 if (rc) {
1115 pr_err("error reading adc channel = %d, rc = %d\n",
1116 chip->vbat_channel, rc);
1117 return rc;
1118 }
1119 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1120 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001121 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1122 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1123 (int) result.physical);
1124
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001125 return (int)result.physical;
1126}
1127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128static int pm_batt_power_get_property(struct power_supply *psy,
1129 enum power_supply_property psp,
1130 union power_supply_propval *val)
1131{
1132 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1133 batt_psy);
1134
1135 switch (psp) {
1136 case POWER_SUPPLY_PROP_STATUS:
1137 val->intval = get_prop_batt_status(chip);
1138 break;
1139 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1140 val->intval = get_prop_charge_type(chip);
1141 break;
1142 case POWER_SUPPLY_PROP_HEALTH:
1143 val->intval = get_prop_batt_health(chip);
1144 break;
1145 case POWER_SUPPLY_PROP_PRESENT:
1146 val->intval = get_prop_batt_present(chip);
1147 break;
1148 case POWER_SUPPLY_PROP_TECHNOLOGY:
1149 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1150 break;
1151 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001152 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 break;
1154 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001155 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 break;
1157 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001158 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 break;
1160 case POWER_SUPPLY_PROP_CAPACITY:
1161 val->intval = get_prop_batt_capacity(chip);
1162 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001163 case POWER_SUPPLY_PROP_CURRENT_NOW:
1164 val->intval = get_prop_batt_current(chip);
1165 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001166 case POWER_SUPPLY_PROP_TEMP:
1167 val->intval = get_prop_batt_temp(chip);
1168 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001169 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001170 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001171 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 default:
1173 return -EINVAL;
1174 }
1175
1176 return 0;
1177}
1178
1179static void (*notify_vbus_state_func_ptr)(int);
1180static int usb_chg_current;
1181static DEFINE_SPINLOCK(vbus_lock);
1182
1183int pm8921_charger_register_vbus_sn(void (*callback)(int))
1184{
1185 pr_debug("%p\n", callback);
1186 notify_vbus_state_func_ptr = callback;
1187 return 0;
1188}
1189EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1190
1191/* this is passed to the hsusb via platform_data msm_otg_pdata */
1192void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1193{
1194 pr_debug("%p\n", callback);
1195 notify_vbus_state_func_ptr = NULL;
1196}
1197EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1198
1199static void notify_usb_of_the_plugin_event(int plugin)
1200{
1201 plugin = !!plugin;
1202 if (notify_vbus_state_func_ptr) {
1203 pr_debug("notifying plugin\n");
1204 (*notify_vbus_state_func_ptr) (plugin);
1205 } else {
1206 pr_debug("unable to notify plugin\n");
1207 }
1208}
1209
1210struct usb_ma_limit_entry {
1211 int usb_ma;
1212 u8 chg_iusb_value;
1213};
1214
1215static struct usb_ma_limit_entry usb_ma_table[] = {
1216 {100, 0},
1217 {500, 1},
1218 {700, 2},
1219 {850, 3},
1220 {900, 4},
1221 {1100, 5},
1222 {1300, 6},
1223 {1500, 7},
1224};
1225
1226/* assumes vbus_lock is held */
1227static void __pm8921_charger_vbus_draw(unsigned int mA)
1228{
1229 int i, rc;
1230
1231 if (mA > 0 && mA <= 2) {
1232 usb_chg_current = 0;
1233 rc = pm_chg_iusbmax_set(the_chip,
1234 usb_ma_table[0].chg_iusb_value);
1235 if (rc) {
1236 pr_err("unable to set iusb to %d rc = %d\n",
1237 usb_ma_table[0].chg_iusb_value, rc);
1238 }
1239 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1240 if (rc)
1241 pr_err("fail to set suspend bit rc=%d\n", rc);
1242 } else {
1243 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1244 if (rc)
1245 pr_err("fail to reset suspend bit rc=%d\n", rc);
1246 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1247 if (usb_ma_table[i].usb_ma <= mA)
1248 break;
1249 }
1250 if (i < 0)
1251 i = 0;
1252 rc = pm_chg_iusbmax_set(the_chip,
1253 usb_ma_table[i].chg_iusb_value);
1254 if (rc) {
1255 pr_err("unable to set iusb to %d rc = %d\n",
1256 usb_ma_table[i].chg_iusb_value, rc);
1257 }
1258 }
1259}
1260
1261/* USB calls these to tell us how much max usb current the system can draw */
1262void pm8921_charger_vbus_draw(unsigned int mA)
1263{
1264 unsigned long flags;
1265
1266 pr_debug("Enter charge=%d\n", mA);
1267 spin_lock_irqsave(&vbus_lock, flags);
1268 if (the_chip) {
1269 __pm8921_charger_vbus_draw(mA);
1270 } else {
1271 /*
1272 * called before pmic initialized,
1273 * save this value and use it at probe
1274 */
1275 usb_chg_current = mA;
1276 }
1277 spin_unlock_irqrestore(&vbus_lock, flags);
1278}
1279EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1280
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001281int pm8921_charger_enable(bool enable)
1282{
1283 int rc;
1284
1285 if (!the_chip) {
1286 pr_err("called before init\n");
1287 return -EINVAL;
1288 }
1289 enable = !!enable;
1290 rc = pm_chg_auto_enable(the_chip, enable);
1291 if (rc)
1292 pr_err("Failed rc=%d\n", rc);
1293 return rc;
1294}
1295EXPORT_SYMBOL(pm8921_charger_enable);
1296
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001297int pm8921_is_usb_chg_plugged_in(void)
1298{
1299 if (!the_chip) {
1300 pr_err("called before init\n");
1301 return -EINVAL;
1302 }
1303 return is_usb_chg_plugged_in(the_chip);
1304}
1305EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1306
1307int pm8921_is_dc_chg_plugged_in(void)
1308{
1309 if (!the_chip) {
1310 pr_err("called before init\n");
1311 return -EINVAL;
1312 }
1313 return is_dc_chg_plugged_in(the_chip);
1314}
1315EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1316
1317int pm8921_is_battery_present(void)
1318{
1319 if (!the_chip) {
1320 pr_err("called before init\n");
1321 return -EINVAL;
1322 }
1323 return get_prop_batt_present(the_chip);
1324}
1325EXPORT_SYMBOL(pm8921_is_battery_present);
1326
David Keitel012deef2011-12-02 11:49:33 -08001327/*
1328 * Disabling the charge current limit causes current
1329 * current limits to have no monitoring. An adequate charger
1330 * capable of supplying high current while sustaining VIN_MIN
1331 * is required if the limiting is disabled.
1332 */
1333int pm8921_disable_input_current_limit(bool disable)
1334{
1335 if (!the_chip) {
1336 pr_err("called before init\n");
1337 return -EINVAL;
1338 }
1339 if (disable) {
1340 pr_warn("Disabling input current limit!\n");
1341
1342 return pm8xxx_writeb(the_chip->dev->parent,
1343 CHG_BUCK_CTRL_TEST3, 0xF2);
1344 }
1345 return 0;
1346}
1347EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1348
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001349int pm8921_set_max_battery_charge_current(int ma)
1350{
1351 if (!the_chip) {
1352 pr_err("called before init\n");
1353 return -EINVAL;
1354 }
1355 return pm_chg_ibatmax_set(the_chip, ma);
1356}
1357EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1358
1359int pm8921_disable_source_current(bool disable)
1360{
1361 if (!the_chip) {
1362 pr_err("called before init\n");
1363 return -EINVAL;
1364 }
1365 if (disable)
1366 pr_warn("current drawn from chg=0, battery provides current\n");
1367 return pm_chg_charge_dis(the_chip, disable);
1368}
1369EXPORT_SYMBOL(pm8921_disable_source_current);
1370
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001371int pm8921_regulate_input_voltage(int voltage)
1372{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001373 int rc;
1374
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001375 if (!the_chip) {
1376 pr_err("called before init\n");
1377 return -EINVAL;
1378 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001379 rc = pm_chg_vinmin_set(the_chip, voltage);
1380
1381 if (rc == 0)
1382 the_chip->vin_min = voltage;
1383
1384 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001385}
1386
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001387#define USB_OV_THRESHOLD_MASK 0x60
1388#define USB_OV_THRESHOLD_SHIFT 5
1389int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1390{
1391 u8 temp;
1392
1393 if (!the_chip) {
1394 pr_err("called before init\n");
1395 return -EINVAL;
1396 }
1397
1398 if (ov > PM_USB_OV_7V) {
1399 pr_err("limiting to over voltage threshold to 7volts\n");
1400 ov = PM_USB_OV_7V;
1401 }
1402
1403 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1404
1405 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1406 USB_OV_THRESHOLD_MASK, temp);
1407}
1408EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1409
1410#define USB_DEBOUNCE_TIME_MASK 0x06
1411#define USB_DEBOUNCE_TIME_SHIFT 1
1412int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1413{
1414 u8 temp;
1415
1416 if (!the_chip) {
1417 pr_err("called before init\n");
1418 return -EINVAL;
1419 }
1420
1421 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1422 pr_err("limiting debounce to 80.5ms\n");
1423 ms = PM_USB_DEBOUNCE_80P5MS;
1424 }
1425
1426 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1427
1428 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1429 USB_DEBOUNCE_TIME_MASK, temp);
1430}
1431EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1432
1433#define USB_OVP_DISABLE_MASK 0x80
1434int pm8921_usb_ovp_disable(int disable)
1435{
1436 u8 temp = 0;
1437
1438 if (!the_chip) {
1439 pr_err("called before init\n");
1440 return -EINVAL;
1441 }
1442
1443 if (disable)
1444 temp = USB_OVP_DISABLE_MASK;
1445
1446 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1447 USB_OVP_DISABLE_MASK, temp);
1448}
1449
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001450bool pm8921_is_battery_charging(int *source)
1451{
1452 int fsm_state, is_charging, dc_present, usb_present;
1453
1454 if (!the_chip) {
1455 pr_err("called before init\n");
1456 return -EINVAL;
1457 }
1458 fsm_state = pm_chg_get_fsm_state(the_chip);
1459 is_charging = is_battery_charging(fsm_state);
1460 if (is_charging == 0) {
1461 *source = PM8921_CHG_SRC_NONE;
1462 return is_charging;
1463 }
1464
1465 if (source == NULL)
1466 return is_charging;
1467
1468 /* the battery is charging, the source is requested, find it */
1469 dc_present = is_dc_chg_plugged_in(the_chip);
1470 usb_present = is_usb_chg_plugged_in(the_chip);
1471
1472 if (dc_present && !usb_present)
1473 *source = PM8921_CHG_SRC_DC;
1474
1475 if (usb_present && !dc_present)
1476 *source = PM8921_CHG_SRC_USB;
1477
1478 if (usb_present && dc_present)
1479 /*
1480 * The system always chooses dc for charging since it has
1481 * higher priority.
1482 */
1483 *source = PM8921_CHG_SRC_DC;
1484
1485 return is_charging;
1486}
1487EXPORT_SYMBOL(pm8921_is_battery_charging);
1488
David Keitel6df9cea2011-12-21 12:36:45 -08001489int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1490{
1491 if (!the_chip) {
1492 pr_err("called before init\n");
1493 return -EINVAL;
1494 }
1495
1496 if (type < POWER_SUPPLY_TYPE_USB)
1497 return -EINVAL;
1498
1499 the_chip->usb_psy.type = type;
1500 power_supply_changed(&the_chip->usb_psy);
1501 return 0;
1502}
1503EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1504
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001505int pm8921_batt_temperature(void)
1506{
1507 if (!the_chip) {
1508 pr_err("called before init\n");
1509 return -EINVAL;
1510 }
1511 return get_prop_batt_temp(the_chip);
1512}
1513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1515{
1516 int usb_present;
1517
1518 usb_present = is_usb_chg_plugged_in(chip);
1519 if (chip->usb_present ^ usb_present) {
1520 notify_usb_of_the_plugin_event(usb_present);
1521 chip->usb_present = usb_present;
1522 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001523 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001525 if (usb_present) {
1526 schedule_delayed_work(&chip->unplug_check_work,
1527 round_jiffies_relative(msecs_to_jiffies
1528 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1529 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001530 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531}
1532
Amir Samuelovd31ef502011-10-26 14:41:36 +02001533static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1534{
1535 if (chip->ext == NULL) {
1536 pr_debug("external charger not registered.\n");
1537 return;
1538 }
1539
1540 if (!chip->ext_charging) {
1541 pr_debug("already not charging.\n");
1542 return;
1543 }
1544
1545 chip->ext->stop_charging(chip->ext->ctx);
1546 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001547 chip->ext_charge_done = false;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001548}
1549
1550static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1551{
1552 int dc_present;
1553 int batt_present;
1554 int batt_temp_ok;
1555 int vbat_ov;
1556 int batfet;
1557 unsigned long delay =
1558 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1559
1560 if (chip->ext == NULL) {
1561 pr_debug("external charger not registered.\n");
1562 return;
1563 }
1564
1565 if (chip->ext_charging) {
1566 pr_debug("already charging.\n");
1567 return;
1568 }
1569
1570 dc_present = is_dc_chg_plugged_in(chip);
1571 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1572 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
1573 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
1574 batfet = pm_chg_get_rt_status(chip, BATFET_IRQ);
1575
1576 if (!dc_present) {
1577 pr_warn("%s. dc not present.\n", __func__);
1578 return;
1579 }
1580 if (!batt_present) {
1581 pr_warn("%s. battery not present.\n", __func__);
1582 return;
1583 }
1584 if (!batt_temp_ok) {
1585 pr_warn("%s. battery temperature not ok.\n", __func__);
1586 return;
1587 }
1588 if (vbat_ov) {
1589 pr_warn("%s. battery over voltage.\n", __func__);
1590 return;
1591 }
1592 if (!batfet) {
1593 pr_warn("%s. battery FET not closed.\n", __func__);
1594 return;
1595 }
1596
1597 chip->ext->start_charging(chip->ext->ctx);
1598 chip->ext_charging = true;
1599 chip->ext_charge_done = false;
1600 /* Start BMS */
1601 schedule_delayed_work(&chip->eoc_work, delay);
1602 wake_lock(&chip->eoc_wake_lock);
1603}
1604
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605static void handle_dc_removal_insertion(struct pm8921_chg_chip *chip)
1606{
1607 int dc_present;
1608
1609 dc_present = is_dc_chg_plugged_in(chip);
1610 if (chip->dc_present ^ dc_present) {
1611 chip->dc_present = dc_present;
1612 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001613 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001615 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616}
1617
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001618#define WRITE_BANK_4 0xC0
1619static void unplug_wrkarnd_restore_worker(struct work_struct *work)
1620{
1621 u8 temp;
1622 int rc;
1623 struct delayed_work *dwork = to_delayed_work(work);
1624 struct pm8921_chg_chip *chip = container_of(dwork,
1625 struct pm8921_chg_chip,
1626 unplug_wrkarnd_restore_work);
1627
1628 pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
1629 rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
1630
1631 temp = WRITE_BANK_4 | 0xA;
1632 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1633 if (rc) {
1634 pr_err("Error %d writing %d to addr %d\n", rc,
1635 temp, CHG_BUCK_CTRL_TEST3);
1636 }
1637 wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
1638}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1640{
1641 handle_usb_insertion_removal(data);
1642 return IRQ_HANDLED;
1643}
1644
1645static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1646{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001647 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 return IRQ_HANDLED;
1649}
1650
1651static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1652{
1653 struct pm8921_chg_chip *chip = data;
1654 int status;
1655
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001656 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1657 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001658 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 pr_debug("battery present=%d", status);
1660 power_supply_changed(&chip->batt_psy);
1661 return IRQ_HANDLED;
1662}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001663
1664/*
1665 * this interrupt used to restart charging a battery.
1666 *
1667 * Note: When DC-inserted the VBAT can't go low.
1668 * VPH_PWR is provided by the ext-charger.
1669 * After End-Of-Charging from DC, charging can be resumed only
1670 * if DC is removed and then inserted after the battery was in use.
1671 * Therefore the handle_start_ext_chg() is not called.
1672 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1674{
1675 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001676 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001678 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001679
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001680 if (high_transition) {
1681 /* enable auto charging */
1682 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001683 pr_info("batt fell below resume voltage %s\n",
1684 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001685 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 power_supply_changed(&chip->batt_psy);
1689 power_supply_changed(&chip->usb_psy);
1690 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 return IRQ_HANDLED;
1693}
1694
1695static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1696{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001697 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 return IRQ_HANDLED;
1699}
1700
1701static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1702{
1703 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1704 return IRQ_HANDLED;
1705}
1706
1707static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1708{
1709 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1710 return IRQ_HANDLED;
1711}
1712
1713static irqreturn_t vcp_irq_handler(int irq, void *data)
1714{
1715 pr_warning("VCP triggered BATDET forced on\n");
1716 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1717 return IRQ_HANDLED;
1718}
1719
1720static irqreturn_t atcdone_irq_handler(int irq, void *data)
1721{
1722 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1723 return IRQ_HANDLED;
1724}
1725
1726static irqreturn_t atcfail_irq_handler(int irq, void *data)
1727{
1728 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1729 return IRQ_HANDLED;
1730}
1731
1732static irqreturn_t chgdone_irq_handler(int irq, void *data)
1733{
1734 struct pm8921_chg_chip *chip = data;
1735
1736 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001737
1738 handle_stop_ext_chg(chip);
1739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 power_supply_changed(&chip->batt_psy);
1741 power_supply_changed(&chip->usb_psy);
1742 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001743
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001744 bms_notify_check(chip);
1745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 return IRQ_HANDLED;
1747}
1748
1749static irqreturn_t chgfail_irq_handler(int irq, void *data)
1750{
1751 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001752 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753
David Keitel753ec8d2011-11-02 10:56:37 -07001754 ret = pm_chg_failed_clear(chip, 1);
1755 if (ret)
1756 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1757
1758 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1759 get_prop_batt_present(chip),
1760 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1761 pm_chg_get_fsm_state(data));
1762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763 power_supply_changed(&chip->batt_psy);
1764 power_supply_changed(&chip->usb_psy);
1765 power_supply_changed(&chip->dc_psy);
1766 return IRQ_HANDLED;
1767}
1768
1769static irqreturn_t chgstate_irq_handler(int irq, void *data)
1770{
1771 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772
1773 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1774 power_supply_changed(&chip->batt_psy);
1775 power_supply_changed(&chip->usb_psy);
1776 power_supply_changed(&chip->dc_psy);
1777
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001778 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 return IRQ_HANDLED;
1781}
1782
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001783#define VIN_ACTIVE_BIT BIT(0)
1784#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
1785#define VIN_MIN_INCREASE_MV 100
1786static void unplug_check_worker(struct work_struct *work)
1787{
1788 struct delayed_work *dwork = to_delayed_work(work);
1789 struct pm8921_chg_chip *chip = container_of(dwork,
1790 struct pm8921_chg_chip, unplug_check_work);
1791 u8 reg_loop;
1792 int ibat, usb_chg_plugged_in;
1793
1794 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1795 if (!usb_chg_plugged_in) {
1796 pr_debug("Stopping Unplug Check Worker since USB is removed"
1797 "reg_loop = %d, fsm = %d ibat = %d\n",
1798 pm_chg_get_regulation_loop(chip),
1799 pm_chg_get_fsm_state(chip),
1800 get_prop_batt_current(chip)
1801 );
1802 return;
1803 }
1804 reg_loop = pm_chg_get_regulation_loop(chip);
1805 pr_debug("reg_loop=0x%x\n", reg_loop);
1806
1807 if (reg_loop & VIN_ACTIVE_BIT) {
1808 ibat = get_prop_batt_current(chip);
1809
1810 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
1811 ibat, pm_chg_get_fsm_state(chip), reg_loop);
1812 if (ibat > 0) {
1813 int err;
1814 u8 temp;
1815
1816 temp = WRITE_BANK_4 | 0xE;
1817 err = pm8xxx_writeb(chip->dev->parent,
1818 CHG_BUCK_CTRL_TEST3, temp);
1819 if (err) {
1820 pr_err("Error %d writing %d to addr %d\n", err,
1821 temp, CHG_BUCK_CTRL_TEST3);
1822 }
1823
1824 pm_chg_vinmin_set(chip,
1825 chip->vin_min + VIN_MIN_INCREASE_MV);
1826
1827 wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
1828 schedule_delayed_work(
1829 &chip->unplug_wrkarnd_restore_work,
1830 round_jiffies_relative(usecs_to_jiffies
1831 (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
1832 }
1833 }
1834
1835 schedule_delayed_work(&chip->unplug_check_work,
1836 round_jiffies_relative(msecs_to_jiffies
1837 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1838}
1839
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840static irqreturn_t loop_change_irq_handler(int irq, void *data)
1841{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001842 struct pm8921_chg_chip *chip = data;
1843
1844 pr_debug("fsm_state=%d reg_loop=0x%x\n",
1845 pm_chg_get_fsm_state(data),
1846 pm_chg_get_regulation_loop(data));
1847 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 return IRQ_HANDLED;
1849}
1850
1851static irqreturn_t fastchg_irq_handler(int irq, void *data)
1852{
1853 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001854 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001856 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1857 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
1858 wake_lock(&chip->eoc_wake_lock);
1859 schedule_delayed_work(&chip->eoc_work,
1860 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001861 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001862 }
1863 power_supply_changed(&chip->batt_psy);
1864 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 return IRQ_HANDLED;
1866}
1867
1868static irqreturn_t trklchg_irq_handler(int irq, void *data)
1869{
1870 struct pm8921_chg_chip *chip = data;
1871
1872 power_supply_changed(&chip->batt_psy);
1873 return IRQ_HANDLED;
1874}
1875
1876static irqreturn_t batt_removed_irq_handler(int irq, void *data)
1877{
1878 struct pm8921_chg_chip *chip = data;
1879 int status;
1880
1881 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
1882 pr_debug("battery present=%d state=%d", !status,
1883 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001884 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 power_supply_changed(&chip->batt_psy);
1886 return IRQ_HANDLED;
1887}
1888
1889static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
1890{
1891 struct pm8921_chg_chip *chip = data;
1892
Amir Samuelovd31ef502011-10-26 14:41:36 +02001893 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894 power_supply_changed(&chip->batt_psy);
1895 return IRQ_HANDLED;
1896}
1897
1898static irqreturn_t chghot_irq_handler(int irq, void *data)
1899{
1900 struct pm8921_chg_chip *chip = data;
1901
1902 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
1903 power_supply_changed(&chip->batt_psy);
1904 power_supply_changed(&chip->usb_psy);
1905 power_supply_changed(&chip->dc_psy);
1906 return IRQ_HANDLED;
1907}
1908
1909static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
1910{
1911 struct pm8921_chg_chip *chip = data;
1912
1913 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001914 handle_stop_ext_chg(chip);
1915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 power_supply_changed(&chip->batt_psy);
1917 power_supply_changed(&chip->usb_psy);
1918 power_supply_changed(&chip->dc_psy);
1919 return IRQ_HANDLED;
1920}
1921
1922static irqreturn_t chg_gone_irq_handler(int irq, void *data)
1923{
1924 struct pm8921_chg_chip *chip = data;
1925
1926 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
1927 power_supply_changed(&chip->batt_psy);
1928 power_supply_changed(&chip->usb_psy);
1929 power_supply_changed(&chip->dc_psy);
1930 return IRQ_HANDLED;
1931}
David Keitel52fda532011-11-10 10:43:44 -08001932/*
1933 *
1934 * bat_temp_ok_irq_handler - is edge triggered, hence it will
1935 * fire for two cases:
1936 *
1937 * If the interrupt line switches to high temperature is okay
1938 * and thus charging begins.
1939 * If bat_temp_ok is low this means the temperature is now
1940 * too hot or cold, so charging is stopped.
1941 *
1942 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
1944{
David Keitel52fda532011-11-10 10:43:44 -08001945 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 struct pm8921_chg_chip *chip = data;
1947
David Keitel52fda532011-11-10 10:43:44 -08001948 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
1949
1950 pr_debug("batt_temp_ok = %d fsm_state%d\n",
1951 bat_temp_ok, pm_chg_get_fsm_state(data));
1952
1953 if (bat_temp_ok)
1954 handle_start_ext_chg(chip);
1955 else
1956 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 power_supply_changed(&chip->batt_psy);
1959 power_supply_changed(&chip->usb_psy);
1960 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001961 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 return IRQ_HANDLED;
1963}
1964
1965static irqreturn_t coarse_det_low_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 vdd_loop_irq_handler(int irq, void *data)
1972{
1973 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1974 return IRQ_HANDLED;
1975}
1976
1977static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
1978{
1979 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1980 return IRQ_HANDLED;
1981}
1982
1983static irqreturn_t vbatdet_irq_handler(int irq, void *data)
1984{
1985 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1986 return IRQ_HANDLED;
1987}
1988
1989static irqreturn_t batfet_irq_handler(int irq, void *data)
1990{
1991 struct pm8921_chg_chip *chip = data;
1992
1993 pr_debug("vreg ov\n");
1994 power_supply_changed(&chip->batt_psy);
1995 return IRQ_HANDLED;
1996}
1997
1998static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
1999{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002000 struct pm8921_chg_chip *chip = data;
2001
2002 pm8921_disable_source_current(true); /* Force BATFET=ON */
2003
2004 handle_dc_removal_insertion(chip);
2005 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 return IRQ_HANDLED;
2007}
2008
2009static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2010{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002011 struct pm8921_chg_chip *chip = data;
2012
2013 pm8921_disable_source_current(false); /* release BATFET */
2014
2015 handle_dc_removal_insertion(chip);
2016 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 return IRQ_HANDLED;
2018}
2019
2020static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2021{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002022 struct pm8921_chg_chip *chip = data;
2023
2024 pm8921_disable_source_current(false); /* release BATFET */
2025 handle_stop_ext_chg(chip);
2026
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 return IRQ_HANDLED;
2028}
2029
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002030/**
2031 * update_heartbeat - internal function to update userspace
2032 * per update_time minutes
2033 *
2034 */
2035static void update_heartbeat(struct work_struct *work)
2036{
2037 struct delayed_work *dwork = to_delayed_work(work);
2038 struct pm8921_chg_chip *chip = container_of(dwork,
2039 struct pm8921_chg_chip, update_heartbeat_work);
2040
2041 power_supply_changed(&chip->batt_psy);
2042 schedule_delayed_work(&chip->update_heartbeat_work,
2043 round_jiffies_relative(msecs_to_jiffies
2044 (chip->update_time)));
2045}
2046
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002047enum {
2048 CHG_IN_PROGRESS,
2049 CHG_NOT_IN_PROGRESS,
2050 CHG_FINISHED,
2051};
2052
2053#define VBAT_TOLERANCE_MV 70
2054#define CHG_DISABLE_MSLEEP 100
2055static int is_charging_finished(struct pm8921_chg_chip *chip)
2056{
2057 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2058 int ichg_meas_ma, iterm_programmed;
2059 int regulation_loop, fast_chg, vcp;
2060 int rc;
2061 static int last_vbat_programmed = -EINVAL;
2062
2063 if (!is_ext_charging(chip)) {
2064 /* return if the battery is not being fastcharged */
2065 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2066 pr_debug("fast_chg = %d\n", fast_chg);
2067 if (fast_chg == 0)
2068 return CHG_NOT_IN_PROGRESS;
2069
2070 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2071 pr_debug("vcp = %d\n", vcp);
2072 if (vcp == 1)
2073 return CHG_IN_PROGRESS;
2074
2075 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2076 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2077 if (vbatdet_low == 1)
2078 return CHG_IN_PROGRESS;
2079
2080 /* reset count if battery is hot/cold */
2081 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2082 pr_debug("batt_temp_ok = %d\n", rc);
2083 if (rc == 0)
2084 return CHG_IN_PROGRESS;
2085
2086 /* reset count if battery voltage is less than vddmax */
2087 vbat_meas_uv = get_prop_battery_uvolts(chip);
2088 if (vbat_meas_uv < 0)
2089 return CHG_IN_PROGRESS;
2090 vbat_meas_mv = vbat_meas_uv / 1000;
2091
2092 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2093 if (rc) {
2094 pr_err("couldnt read vddmax rc = %d\n", rc);
2095 return CHG_IN_PROGRESS;
2096 }
2097 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2098 vbat_programmed, vbat_meas_mv);
2099 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2100 return CHG_IN_PROGRESS;
2101
2102 if (last_vbat_programmed == -EINVAL)
2103 last_vbat_programmed = vbat_programmed;
2104 if (last_vbat_programmed != vbat_programmed) {
2105 /* vddmax changed, reset and check again */
2106 pr_debug("vddmax = %d last_vdd_max=%d\n",
2107 vbat_programmed, last_vbat_programmed);
2108 last_vbat_programmed = vbat_programmed;
2109 return CHG_IN_PROGRESS;
2110 }
2111
2112 /*
2113 * TODO if charging from an external charger
2114 * check SOC instead of regulation loop
2115 */
2116 regulation_loop = pm_chg_get_regulation_loop(chip);
2117 if (regulation_loop < 0) {
2118 pr_err("couldnt read the regulation loop err=%d\n",
2119 regulation_loop);
2120 return CHG_IN_PROGRESS;
2121 }
2122 pr_debug("regulation_loop=%d\n", regulation_loop);
2123
2124 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2125 return CHG_IN_PROGRESS;
2126 } /* !is_ext_charging */
2127
2128 /* reset count if battery chg current is more than iterm */
2129 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2130 if (rc) {
2131 pr_err("couldnt read iterm rc = %d\n", rc);
2132 return CHG_IN_PROGRESS;
2133 }
2134
2135 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2136 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2137 iterm_programmed, ichg_meas_ma);
2138 /*
2139 * ichg_meas_ma < 0 means battery is drawing current
2140 * ichg_meas_ma > 0 means battery is providing current
2141 */
2142 if (ichg_meas_ma > 0)
2143 return CHG_IN_PROGRESS;
2144
2145 if (ichg_meas_ma * -1 > iterm_programmed)
2146 return CHG_IN_PROGRESS;
2147
2148 return CHG_FINISHED;
2149}
2150
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002151/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002152 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002153 * has happened
2154 *
2155 * If all conditions favouring, if the charge current is
2156 * less than the term current for three consecutive times
2157 * an EOC has happened.
2158 * The wakelock is released if there is no need to reshedule
2159 * - this happens when the battery is removed or EOC has
2160 * happened
2161 */
2162#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002163static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002164{
2165 struct delayed_work *dwork = to_delayed_work(work);
2166 struct pm8921_chg_chip *chip = container_of(dwork,
2167 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002168 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002169 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002170
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002171 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002172 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002173 count = 0;
2174 wake_unlock(&chip->eoc_wake_lock);
2175 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002176 }
2177
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002178 if (end == CHG_FINISHED) {
2179 count++;
2180 } else {
2181 count = 0;
2182 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002183
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002184 if (count == CONSECUTIVE_COUNT) {
2185 count = 0;
2186 pr_info("End of Charging\n");
2187
2188 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002189
Amir Samuelovd31ef502011-10-26 14:41:36 +02002190 if (is_ext_charging(chip))
2191 chip->ext_charge_done = true;
2192
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002193 if (chip->is_bat_warm || chip->is_bat_cool)
2194 chip->bms_notify.is_battery_full = 0;
2195 else
2196 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002197 /* declare end of charging by invoking chgdone interrupt */
2198 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2199 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002200 } else {
2201 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002202 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002203 round_jiffies_relative(msecs_to_jiffies
2204 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002205 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002206}
2207
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002208static void btm_configure_work(struct work_struct *work)
2209{
2210 int rc;
2211
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002212 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002213 if (rc)
2214 pr_err("failed to configure btm rc=%d", rc);
2215}
2216
2217DECLARE_WORK(btm_config_work, btm_configure_work);
2218
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002219static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2220{
2221 unsigned int chg_current = chip->max_bat_chg_current;
2222
2223 if (chip->is_bat_cool)
2224 chg_current = min(chg_current, chip->cool_bat_chg_current);
2225
2226 if (chip->is_bat_warm)
2227 chg_current = min(chg_current, chip->warm_bat_chg_current);
2228
David Keitelfdef3a42011-12-14 19:02:54 -08002229 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002230 chg_current = min(chg_current,
2231 chip->thermal_mitigation[thermal_mitigation]);
2232
2233 pm_chg_ibatmax_set(the_chip, chg_current);
2234}
2235
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002236#define TEMP_HYSTERISIS_DEGC 2
2237static void battery_cool(bool enter)
2238{
2239 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002240 if (enter == the_chip->is_bat_cool)
2241 return;
2242 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002243 if (enter) {
2244 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002245 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002246 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002247 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002248 pm_chg_vbatdet_set(the_chip,
2249 the_chip->cool_bat_voltage
2250 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002251 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002252 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002253 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002254 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002255 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002256 the_chip->max_voltage_mv
2257 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002258 }
2259 schedule_work(&btm_config_work);
2260}
2261
2262static void battery_warm(bool enter)
2263{
2264 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002265 if (enter == the_chip->is_bat_warm)
2266 return;
2267 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002268 if (enter) {
2269 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002270 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002271 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002272 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002273 pm_chg_vbatdet_set(the_chip,
2274 the_chip->warm_bat_voltage
2275 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002276 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002277 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002278 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002279 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002280 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002281 the_chip->max_voltage_mv
2282 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002283 }
2284 schedule_work(&btm_config_work);
2285}
2286
2287static int configure_btm(struct pm8921_chg_chip *chip)
2288{
2289 int rc;
2290
2291 btm_config.btm_warm_fn = battery_warm;
2292 btm_config.btm_cool_fn = battery_cool;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002293 btm_config.low_thr_temp = chip->cool_temp_dc;
2294 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002295 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002296 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002297 if (rc)
2298 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002299 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002300 if (rc)
2301 pr_err("failed to start btm rc = %d\n", rc);
2302
2303 return rc;
2304}
2305
Amir Samuelovd31ef502011-10-26 14:41:36 +02002306int register_external_dc_charger(struct ext_chg_pm8921 *ext)
2307{
2308 if (the_chip == NULL) {
2309 pr_err("called too early\n");
2310 return -EINVAL;
2311 }
2312 /* TODO check function pointers */
2313 the_chip->ext = ext;
2314 the_chip->ext_charging = false;
2315
2316 if (is_dc_chg_plugged_in(the_chip))
2317 pm8921_disable_source_current(true); /* Force BATFET=ON */
2318
2319 handle_start_ext_chg(the_chip);
2320
2321 return 0;
2322}
2323EXPORT_SYMBOL(register_external_dc_charger);
2324
2325void unregister_external_dc_charger(struct ext_chg_pm8921 *ext)
2326{
2327 if (the_chip == NULL) {
2328 pr_err("called too early\n");
2329 return;
2330 }
2331 handle_stop_ext_chg(the_chip);
2332 the_chip->ext = NULL;
2333}
2334EXPORT_SYMBOL(unregister_external_dc_charger);
2335
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002336/**
2337 * set_disable_status_param -
2338 *
2339 * Internal function to disable battery charging and also disable drawing
2340 * any current from the source. The device is forced to run on a battery
2341 * after this.
2342 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343static int set_disable_status_param(const char *val, struct kernel_param *kp)
2344{
2345 int ret;
2346 struct pm8921_chg_chip *chip = the_chip;
2347
2348 ret = param_set_int(val, kp);
2349 if (ret) {
2350 pr_err("error setting value %d\n", ret);
2351 return ret;
2352 }
2353 pr_info("factory set disable param to %d\n", charging_disabled);
2354 if (chip) {
2355 pm_chg_auto_enable(chip, !charging_disabled);
2356 pm_chg_charge_dis(chip, charging_disabled);
2357 }
2358 return 0;
2359}
2360module_param_call(disabled, set_disable_status_param, param_get_uint,
2361 &charging_disabled, 0644);
2362
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002363/**
2364 * set_thermal_mitigation_level -
2365 *
2366 * Internal function to control battery charging current to reduce
2367 * temperature
2368 */
2369static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2370{
2371 int ret;
2372 struct pm8921_chg_chip *chip = the_chip;
2373
2374 ret = param_set_int(val, kp);
2375 if (ret) {
2376 pr_err("error setting value %d\n", ret);
2377 return ret;
2378 }
2379
2380 if (!chip) {
2381 pr_err("called before init\n");
2382 return -EINVAL;
2383 }
2384
2385 if (!chip->thermal_mitigation) {
2386 pr_err("no thermal mitigation\n");
2387 return -EINVAL;
2388 }
2389
2390 if (thermal_mitigation < 0
2391 || thermal_mitigation >= chip->thermal_levels) {
2392 pr_err("out of bound level selected\n");
2393 return -EINVAL;
2394 }
2395
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002396 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002397 return ret;
2398}
2399module_param_call(thermal_mitigation, set_therm_mitigation_level,
2400 param_get_uint,
2401 &thermal_mitigation, 0644);
2402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002403static void free_irqs(struct pm8921_chg_chip *chip)
2404{
2405 int i;
2406
2407 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2408 if (chip->pmic_chg_irq[i]) {
2409 free_irq(chip->pmic_chg_irq[i], chip);
2410 chip->pmic_chg_irq[i] = 0;
2411 }
2412}
2413
2414/* determines the initial present states and notifies msm_charger */
2415static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2416{
2417 unsigned long flags;
2418 int fsm_state;
2419
2420 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2421 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2422
2423 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002424 if (chip->usb_present) {
2425 schedule_delayed_work(&chip->unplug_check_work,
2426 round_jiffies_relative(msecs_to_jiffies
2427 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2428 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429
2430 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2431 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2432 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002433 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2434 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2435 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2436 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2437 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002438 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002439 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2440 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002441 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442
2443 spin_lock_irqsave(&vbus_lock, flags);
2444 if (usb_chg_current) {
2445 /* reissue a vbus draw call */
2446 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002447 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448 }
2449 spin_unlock_irqrestore(&vbus_lock, flags);
2450
2451 fsm_state = pm_chg_get_fsm_state(chip);
2452 if (is_battery_charging(fsm_state)) {
2453 chip->bms_notify.is_charging = 1;
2454 pm8921_bms_charging_began();
2455 }
2456
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002457 check_battery_valid(chip);
2458
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2460 chip->usb_present,
2461 chip->dc_present,
2462 get_prop_batt_present(chip),
2463 fsm_state);
2464}
2465
2466struct pm_chg_irq_init_data {
2467 unsigned int irq_id;
2468 char *name;
2469 unsigned long flags;
2470 irqreturn_t (*handler)(int, void *);
2471};
2472
2473#define CHG_IRQ(_id, _flags, _handler) \
2474{ \
2475 .irq_id = _id, \
2476 .name = #_id, \
2477 .flags = _flags, \
2478 .handler = _handler, \
2479}
2480struct pm_chg_irq_init_data chg_irq_data[] = {
2481 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2482 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002483 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2485 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002486 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2487 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2489 usbin_uv_irq_handler),
2490 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2491 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2492 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2493 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2494 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2495 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2496 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2497 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2498 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002499 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2500 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2502 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2503 batt_removed_irq_handler),
2504 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2505 batttemp_hot_irq_handler),
2506 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2507 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2508 batttemp_cold_irq_handler),
2509 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002510 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2511 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2513 coarse_det_low_irq_handler),
2514 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2515 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2516 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2517 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2518 batfet_irq_handler),
2519 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2520 dcin_valid_irq_handler),
2521 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2522 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002523 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524};
2525
2526static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2527 struct platform_device *pdev)
2528{
2529 struct resource *res;
2530 int ret, i;
2531
2532 ret = 0;
2533 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2534
2535 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2536 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2537 chg_irq_data[i].name);
2538 if (res == NULL) {
2539 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2540 goto err_out;
2541 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002542 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543 ret = request_irq(res->start, chg_irq_data[i].handler,
2544 chg_irq_data[i].flags,
2545 chg_irq_data[i].name, chip);
2546 if (ret < 0) {
2547 pr_err("couldn't request %d (%s) %d\n", res->start,
2548 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002549 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 goto err_out;
2551 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2553 }
2554 return 0;
2555
2556err_out:
2557 free_irqs(chip);
2558 return -EINVAL;
2559}
2560
2561#define ENUM_TIMER_STOP_BIT BIT(1)
2562#define BOOT_DONE_BIT BIT(6)
2563#define CHG_BATFET_ON_BIT BIT(3)
2564#define CHG_VCP_EN BIT(0)
2565#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2566#define SAFE_CURRENT_MA 1500
2567static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2568{
2569 int rc;
2570
2571 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2572 BOOT_DONE_BIT, BOOT_DONE_BIT);
2573 if (rc) {
2574 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2575 return rc;
2576 }
2577
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002578 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 if (rc) {
2580 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002581 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582 return rc;
2583 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002584 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002585 chip->max_voltage_mv
2586 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587 if (rc) {
2588 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002589 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 return rc;
2591 }
2592
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002593 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594 if (rc) {
2595 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002596 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597 return rc;
2598 }
2599 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2600 if (rc) {
2601 pr_err("Failed to set max voltage to %d rc=%d\n",
2602 SAFE_CURRENT_MA, rc);
2603 return rc;
2604 }
2605
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002606 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 if (rc) {
2608 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2609 return rc;
2610 }
2611
2612 rc = pm_chg_iterm_set(chip, chip->term_current);
2613 if (rc) {
2614 pr_err("Failed to set term current to %d rc=%d\n",
2615 chip->term_current, rc);
2616 return rc;
2617 }
2618
2619 /* Disable the ENUM TIMER */
2620 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2621 ENUM_TIMER_STOP_BIT);
2622 if (rc) {
2623 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2624 return rc;
2625 }
2626
2627 /* init with the lowest USB current */
2628 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
2629 if (rc) {
2630 pr_err("Failed to set usb max to %d rc=%d\n",
2631 usb_ma_table[0].chg_iusb_value, rc);
2632 return rc;
2633 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002634
2635 if (chip->safety_time != 0) {
2636 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
2637 if (rc) {
2638 pr_err("Failed to set max time to %d minutes rc=%d\n",
2639 chip->safety_time, rc);
2640 return rc;
2641 }
2642 }
2643
2644 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07002645 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002646 if (rc) {
2647 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
2648 chip->safety_time, rc);
2649 return rc;
2650 }
2651 }
2652
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002653 if (chip->vin_min != 0) {
2654 rc = pm_chg_vinmin_set(chip, chip->vin_min);
2655 if (rc) {
2656 pr_err("Failed to set vin min to %d mV rc=%d\n",
2657 chip->vin_min, rc);
2658 return rc;
2659 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002660 } else {
2661 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002662 }
2663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664 rc = pm_chg_disable_wd(chip);
2665 if (rc) {
2666 pr_err("Failed to disable wd rc=%d\n", rc);
2667 return rc;
2668 }
2669
2670 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
2671 CHG_BAT_TEMP_DIS_BIT, 0);
2672 if (rc) {
2673 pr_err("Failed to enable temp control chg rc=%d\n", rc);
2674 return rc;
2675 }
2676 /* switch to a 3.2Mhz for the buck */
2677 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
2678 if (rc) {
2679 pr_err("Failed to switch buck clk rc=%d\n", rc);
2680 return rc;
2681 }
2682
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07002683 if (chip->trkl_voltage != 0) {
2684 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
2685 if (rc) {
2686 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
2687 chip->trkl_voltage, rc);
2688 return rc;
2689 }
2690 }
2691
2692 if (chip->weak_voltage != 0) {
2693 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
2694 if (rc) {
2695 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
2696 chip->weak_voltage, rc);
2697 return rc;
2698 }
2699 }
2700
2701 if (chip->trkl_current != 0) {
2702 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
2703 if (rc) {
2704 pr_err("Failed to set trkl current to %dmA rc=%d\n",
2705 chip->trkl_voltage, rc);
2706 return rc;
2707 }
2708 }
2709
2710 if (chip->weak_current != 0) {
2711 rc = pm_chg_iweak_set(chip, chip->weak_current);
2712 if (rc) {
2713 pr_err("Failed to set weak current to %dmA rc=%d\n",
2714 chip->weak_current, rc);
2715 return rc;
2716 }
2717 }
2718
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07002719 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
2720 if (rc) {
2721 pr_err("Failed to set cold config %d rc=%d\n",
2722 chip->cold_thr, rc);
2723 }
2724
2725 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
2726 if (rc) {
2727 pr_err("Failed to set hot config %d rc=%d\n",
2728 chip->hot_thr, rc);
2729 }
2730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002731 /* Workarounds for die 1.1 and 1.0 */
2732 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
2733 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
2735 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002736
2737 /* software workaround for correct battery_id detection */
2738 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
2739 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
2740 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
2741 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
2742 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
2743 udelay(100);
2744 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 }
2746
David Keitelb51995e2011-11-18 17:03:31 -08002747 /* Workarounds for die 3.0 */
2748 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
2749 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
2750
2751 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
2752
David Keitela3c0d822011-11-03 14:18:52 -07002753 /* Disable EOC FSM processing */
2754 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
2755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002756 rc = pm_chg_charge_dis(chip, charging_disabled);
2757 if (rc) {
2758 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
2759 return rc;
2760 }
2761
2762 rc = pm_chg_auto_enable(chip, !charging_disabled);
2763 if (rc) {
2764 pr_err("Failed to enable charging rc=%d\n", rc);
2765 return rc;
2766 }
2767
2768 return 0;
2769}
2770
2771static int get_rt_status(void *data, u64 * val)
2772{
2773 int i = (int)data;
2774 int ret;
2775
2776 /* global irq number is passed in via data */
2777 ret = pm_chg_get_rt_status(the_chip, i);
2778 *val = ret;
2779 return 0;
2780}
2781DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
2782
2783static int get_fsm_status(void *data, u64 * val)
2784{
2785 u8 temp;
2786
2787 temp = pm_chg_get_fsm_state(the_chip);
2788 *val = temp;
2789 return 0;
2790}
2791DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
2792
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002793static int get_reg_loop(void *data, u64 * val)
2794{
2795 u8 temp;
2796
2797 if (!the_chip) {
2798 pr_err("%s called before init\n", __func__);
2799 return -EINVAL;
2800 }
2801 temp = pm_chg_get_regulation_loop(the_chip);
2802 *val = temp;
2803 return 0;
2804}
2805DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
2806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807static int get_reg(void *data, u64 * val)
2808{
2809 int addr = (int)data;
2810 int ret;
2811 u8 temp;
2812
2813 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
2814 if (ret) {
2815 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
2816 addr, temp, ret);
2817 return -EAGAIN;
2818 }
2819 *val = temp;
2820 return 0;
2821}
2822
2823static int set_reg(void *data, u64 val)
2824{
2825 int addr = (int)data;
2826 int ret;
2827 u8 temp;
2828
2829 temp = (u8) val;
2830 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
2831 if (ret) {
2832 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
2833 addr, temp, ret);
2834 return -EAGAIN;
2835 }
2836 return 0;
2837}
2838DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
2839
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002840enum {
2841 BAT_WARM_ZONE,
2842 BAT_COOL_ZONE,
2843};
2844static int get_warm_cool(void *data, u64 * val)
2845{
2846 if (!the_chip) {
2847 pr_err("%s called before init\n", __func__);
2848 return -EINVAL;
2849 }
2850 if ((int)data == BAT_WARM_ZONE)
2851 *val = the_chip->is_bat_warm;
2852 if ((int)data == BAT_COOL_ZONE)
2853 *val = the_chip->is_bat_cool;
2854 return 0;
2855}
2856DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
2857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858static void create_debugfs_entries(struct pm8921_chg_chip *chip)
2859{
2860 int i;
2861
2862 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
2863
2864 if (IS_ERR(chip->dent)) {
2865 pr_err("pmic charger couldnt create debugfs dir\n");
2866 return;
2867 }
2868
2869 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
2870 (void *)CHG_CNTRL, &reg_fops);
2871 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
2872 (void *)CHG_CNTRL_2, &reg_fops);
2873 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
2874 (void *)CHG_CNTRL_3, &reg_fops);
2875 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
2876 (void *)PBL_ACCESS1, &reg_fops);
2877 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
2878 (void *)PBL_ACCESS2, &reg_fops);
2879 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
2880 (void *)SYS_CONFIG_1, &reg_fops);
2881 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
2882 (void *)SYS_CONFIG_2, &reg_fops);
2883 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
2884 (void *)CHG_VDD_MAX, &reg_fops);
2885 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
2886 (void *)CHG_VDD_SAFE, &reg_fops);
2887 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
2888 (void *)CHG_VBAT_DET, &reg_fops);
2889 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
2890 (void *)CHG_IBAT_MAX, &reg_fops);
2891 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
2892 (void *)CHG_IBAT_SAFE, &reg_fops);
2893 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
2894 (void *)CHG_VIN_MIN, &reg_fops);
2895 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
2896 (void *)CHG_VTRICKLE, &reg_fops);
2897 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
2898 (void *)CHG_ITRICKLE, &reg_fops);
2899 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
2900 (void *)CHG_ITERM, &reg_fops);
2901 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
2902 (void *)CHG_TCHG_MAX, &reg_fops);
2903 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
2904 (void *)CHG_TWDOG, &reg_fops);
2905 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
2906 (void *)CHG_TEMP_THRESH, &reg_fops);
2907 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
2908 (void *)CHG_COMP_OVR, &reg_fops);
2909 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
2910 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
2911 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
2912 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
2913 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
2914 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
2915 debugfs_create_file("CHG_TEST", 0644, chip->dent,
2916 (void *)CHG_TEST, &reg_fops);
2917
2918 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
2919 &fsm_fops);
2920
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002921 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
2922 &reg_loop_fops);
2923
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002924 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
2925 (void *)BAT_WARM_ZONE, &warm_cool_fops);
2926 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
2927 (void *)BAT_COOL_ZONE, &warm_cool_fops);
2928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2930 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
2931 debugfs_create_file(chg_irq_data[i].name, 0444,
2932 chip->dent,
2933 (void *)chg_irq_data[i].irq_id,
2934 &rt_fops);
2935 }
2936}
2937
David Keitelf2226022011-12-13 15:55:50 -08002938static int pm8921_charger_resume(struct device *dev)
2939{
2940 int rc;
2941 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
2942
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002943 if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
David Keitelf2226022011-12-13 15:55:50 -08002944 && !(chip->keep_btm_on_suspend)) {
2945 rc = pm8xxx_adc_btm_configure(&btm_config);
2946 if (rc)
2947 pr_err("couldn't reconfigure btm rc=%d\n", rc);
2948
2949 rc = pm8xxx_adc_btm_start();
2950 if (rc)
2951 pr_err("couldn't restart btm rc=%d\n", rc);
2952 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002953 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
2954 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
2955 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
2956 }
David Keitelf2226022011-12-13 15:55:50 -08002957 return 0;
2958}
2959
2960static int pm8921_charger_suspend(struct device *dev)
2961{
2962 int rc;
2963 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
2964
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002965 if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
David Keitelf2226022011-12-13 15:55:50 -08002966 && !(chip->keep_btm_on_suspend)) {
2967 rc = pm8xxx_adc_btm_end();
2968 if (rc)
2969 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
2970 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002971
2972 if (is_usb_chg_plugged_in(chip)) {
2973 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
2974 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
2975 }
David Keitelf2226022011-12-13 15:55:50 -08002976 return 0;
2977}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978static int __devinit pm8921_charger_probe(struct platform_device *pdev)
2979{
2980 int rc = 0;
2981 struct pm8921_chg_chip *chip;
2982 const struct pm8921_charger_platform_data *pdata
2983 = pdev->dev.platform_data;
2984
2985 if (!pdata) {
2986 pr_err("missing platform data\n");
2987 return -EINVAL;
2988 }
2989
2990 chip = kzalloc(sizeof(struct pm8921_chg_chip),
2991 GFP_KERNEL);
2992 if (!chip) {
2993 pr_err("Cannot allocate pm_chg_chip\n");
2994 return -ENOMEM;
2995 }
2996
2997 chip->dev = &pdev->dev;
2998 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002999 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003001 chip->max_voltage_mv = pdata->max_voltage;
3002 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003003 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004 chip->term_current = pdata->term_current;
3005 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003006 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003007 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3008 chip->batt_id_min = pdata->batt_id_min;
3009 chip->batt_id_max = pdata->batt_id_max;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003010 chip->cool_temp_dc = pdata->cool_temp * 10;
3011 chip->warm_temp_dc = pdata->warm_temp * 10;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003012 chip->temp_check_period = pdata->temp_check_period;
3013 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3014 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3015 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3016 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3017 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003018 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003019 chip->trkl_voltage = pdata->trkl_voltage;
3020 chip->weak_voltage = pdata->weak_voltage;
3021 chip->trkl_current = pdata->trkl_current;
3022 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003023 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003024 chip->thermal_mitigation = pdata->thermal_mitigation;
3025 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003027 chip->cold_thr = pdata->cold_thr;
3028 chip->hot_thr = pdata->hot_thr;
3029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 rc = pm8921_chg_hw_init(chip);
3031 if (rc) {
3032 pr_err("couldn't init hardware rc=%d\n", rc);
3033 goto free_chip;
3034 }
3035
3036 chip->usb_psy.name = "usb",
3037 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3038 chip->usb_psy.supplied_to = pm_power_supplied_to,
3039 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3040 chip->usb_psy.properties = pm_power_props,
3041 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3042 chip->usb_psy.get_property = pm_power_get_property,
3043
3044 chip->dc_psy.name = "ac",
3045 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3046 chip->dc_psy.supplied_to = pm_power_supplied_to,
3047 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3048 chip->dc_psy.properties = pm_power_props,
3049 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
3050 chip->dc_psy.get_property = pm_power_get_property,
3051
3052 chip->batt_psy.name = "battery",
3053 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3054 chip->batt_psy.properties = msm_batt_power_props,
3055 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3056 chip->batt_psy.get_property = pm_batt_power_get_property,
3057
3058 rc = power_supply_register(chip->dev, &chip->usb_psy);
3059 if (rc < 0) {
3060 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003061 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 }
3063
3064 rc = power_supply_register(chip->dev, &chip->dc_psy);
3065 if (rc < 0) {
3066 pr_err("power_supply_register dc failed rc = %d\n", rc);
3067 goto unregister_usb;
3068 }
3069
3070 rc = power_supply_register(chip->dev, &chip->batt_psy);
3071 if (rc < 0) {
3072 pr_err("power_supply_register batt failed rc = %d\n", rc);
3073 goto unregister_dc;
3074 }
3075
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003076 platform_set_drvdata(pdev, chip);
3077 the_chip = chip;
3078
3079 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003080 wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
3081 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003082 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003083 INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
3084 unplug_wrkarnd_restore_worker);
3085 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003087 rc = request_irqs(chip, pdev);
3088 if (rc) {
3089 pr_err("couldn't register interrupts rc=%d\n", rc);
3090 goto unregister_batt;
3091 }
3092
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003093 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3094 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3095 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003096 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3097 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003098 /*
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003099 * if both the cool_temp_dc and warm_temp_dc are zero the device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003100 * care for jeita compliance
3101 */
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003102 if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003103 rc = configure_btm(chip);
3104 if (rc) {
3105 pr_err("couldn't register with btm rc=%d\n", rc);
3106 goto free_irq;
3107 }
3108 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110 create_debugfs_entries(chip);
3111
3112 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003113 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 /* determine what state the charger is in */
3116 determine_initial_state(chip);
3117
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003118 if (chip->update_time) {
3119 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3120 update_heartbeat);
3121 schedule_delayed_work(&chip->update_heartbeat_work,
3122 round_jiffies_relative(msecs_to_jiffies
3123 (chip->update_time)));
3124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 return 0;
3126
3127free_irq:
3128 free_irqs(chip);
3129unregister_batt:
3130 power_supply_unregister(&chip->batt_psy);
3131unregister_dc:
3132 power_supply_unregister(&chip->dc_psy);
3133unregister_usb:
3134 power_supply_unregister(&chip->usb_psy);
3135free_chip:
3136 kfree(chip);
3137 return rc;
3138}
3139
3140static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3141{
3142 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3143
3144 free_irqs(chip);
3145 platform_set_drvdata(pdev, NULL);
3146 the_chip = NULL;
3147 kfree(chip);
3148 return 0;
3149}
David Keitelf2226022011-12-13 15:55:50 -08003150static const struct dev_pm_ops pm8921_pm_ops = {
3151 .suspend = pm8921_charger_suspend,
3152 .resume = pm8921_charger_resume,
3153};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003155 .probe = pm8921_charger_probe,
3156 .remove = __devexit_p(pm8921_charger_remove),
3157 .driver = {
3158 .name = PM8921_CHARGER_DEV_NAME,
3159 .owner = THIS_MODULE,
3160 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 },
3162};
3163
3164static int __init pm8921_charger_init(void)
3165{
3166 return platform_driver_register(&pm8921_charger_driver);
3167}
3168
3169static void __exit pm8921_charger_exit(void)
3170{
3171 platform_driver_unregister(&pm8921_charger_driver);
3172}
3173
3174late_initcall(pm8921_charger_init);
3175module_exit(pm8921_charger_exit);
3176
3177MODULE_LICENSE("GPL v2");
3178MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3179MODULE_VERSION("1.0");
3180MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);