blob: e24c7000ba6ce1e06d44d05651e3fb5c38db84bd [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
80
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070081/* check EOC every 10 seconds */
82#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080083/* check for USB unplug every 200 msecs */
84#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086enum chg_fsm_state {
87 FSM_STATE_OFF_0 = 0,
88 FSM_STATE_BATFETDET_START_12 = 12,
89 FSM_STATE_BATFETDET_END_16 = 16,
90 FSM_STATE_ON_CHG_HIGHI_1 = 1,
91 FSM_STATE_ATC_2A = 2,
92 FSM_STATE_ATC_2B = 18,
93 FSM_STATE_ON_BAT_3 = 3,
94 FSM_STATE_ATC_FAIL_4 = 4 ,
95 FSM_STATE_DELAY_5 = 5,
96 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
97 FSM_STATE_FAST_CHG_7 = 7,
98 FSM_STATE_TRKL_CHG_8 = 8,
99 FSM_STATE_CHG_FAIL_9 = 9,
100 FSM_STATE_EOC_10 = 10,
101 FSM_STATE_ON_CHG_VREGOK_11 = 11,
102 FSM_STATE_ATC_PAUSE_13 = 13,
103 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
104 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
105 FSM_STATE_START_BOOT = 20,
106 FSM_STATE_FLCB_VREGOK = 21,
107 FSM_STATE_FLCB = 22,
108};
109
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700110struct fsm_state_to_batt_status {
111 enum chg_fsm_state fsm_state;
112 int batt_state;
113};
114
115static struct fsm_state_to_batt_status map[] = {
116 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
117 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
118 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
119 /*
120 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
121 * too hot/cold, charger too hot
122 */
123 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
124 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
125 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
126 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
127 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
128 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
129 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
130 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
133 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
134 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
135 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
136 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
141};
142
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700143enum chg_regulation_loop {
144 VDD_LOOP = BIT(3),
145 BAT_CURRENT_LOOP = BIT(2),
146 INPUT_CURRENT_LOOP = BIT(1),
147 INPUT_VOLTAGE_LOOP = BIT(0),
148 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
149 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
150};
151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152enum pmic_chg_interrupts {
153 USBIN_VALID_IRQ = 0,
154 USBIN_OV_IRQ,
155 BATT_INSERTED_IRQ,
156 VBATDET_LOW_IRQ,
157 USBIN_UV_IRQ,
158 VBAT_OV_IRQ,
159 CHGWDOG_IRQ,
160 VCP_IRQ,
161 ATCDONE_IRQ,
162 ATCFAIL_IRQ,
163 CHGDONE_IRQ,
164 CHGFAIL_IRQ,
165 CHGSTATE_IRQ,
166 LOOP_CHANGE_IRQ,
167 FASTCHG_IRQ,
168 TRKLCHG_IRQ,
169 BATT_REMOVED_IRQ,
170 BATTTEMP_HOT_IRQ,
171 CHGHOT_IRQ,
172 BATTTEMP_COLD_IRQ,
173 CHG_GONE_IRQ,
174 BAT_TEMP_OK_IRQ,
175 COARSE_DET_LOW_IRQ,
176 VDD_LOOP_IRQ,
177 VREG_OV_IRQ,
178 VBATDET_IRQ,
179 BATFET_IRQ,
180 PSI_IRQ,
181 DCIN_VALID_IRQ,
182 DCIN_OV_IRQ,
183 DCIN_UV_IRQ,
184 PM_CHG_MAX_INTS,
185};
186
187struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700188 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 int is_charging;
190 struct work_struct work;
191};
192
193/**
194 * struct pm8921_chg_chip -device information
195 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 * @usb_present: present status of usb
197 * @dc_present: present status of dc
198 * @usb_charger_current: usb current to charge the battery with used when
199 * the usb path is enabled or charging is resumed
200 * @safety_time: max time for which charging will happen
201 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800202 * @max_voltage_mv: the max volts the batt should be charged up to
203 * @min_voltage_mv: the min battery voltage before turning the FETon
204 * @cool_temp_dc: the cool temp threshold in deciCelcius
205 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700206 * @resume_voltage_delta: the voltage delta from vdd max at which the
207 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @term_current: The charging based term current
209 *
210 */
211struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700212 struct device *dev;
213 unsigned int usb_present;
214 unsigned int dc_present;
215 unsigned int usb_charger_current;
216 unsigned int max_bat_chg_current;
217 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
218 unsigned int safety_time;
219 unsigned int ttrkl_time;
220 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800221 unsigned int max_voltage_mv;
222 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800223 int cool_temp_dc;
224 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700225 unsigned int temp_check_period;
226 unsigned int cool_bat_chg_current;
227 unsigned int warm_bat_chg_current;
228 unsigned int cool_bat_voltage;
229 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700230 unsigned int is_bat_cool;
231 unsigned int is_bat_warm;
232 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700233 unsigned int term_current;
234 unsigned int vbat_channel;
235 unsigned int batt_temp_channel;
236 unsigned int batt_id_channel;
237 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800238 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800239 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700240 struct power_supply batt_psy;
241 struct dentry *dent;
242 struct bms_notify bms_notify;
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
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800267static int usb_max_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700269static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271static struct pm8921_chg_chip *the_chip;
272
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700273static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
276 u8 mask, u8 val)
277{
278 int rc;
279 u8 reg;
280
281 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
282 if (rc) {
283 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
284 return rc;
285 }
286 reg &= ~mask;
287 reg |= val & mask;
288 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
289 if (rc) {
290 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
291 return rc;
292 }
293 return 0;
294}
295
296#define CAPTURE_FSM_STATE_CMD 0xC2
297#define READ_BANK_7 0x70
298#define READ_BANK_4 0x40
299static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
300{
301 u8 temp;
302 int err, ret = 0;
303
304 temp = CAPTURE_FSM_STATE_CMD;
305 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
306 if (err) {
307 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
308 return err;
309 }
310
311 temp = READ_BANK_7;
312 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
313 if (err) {
314 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
315 return err;
316 }
317
318 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
319 if (err) {
320 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
321 return err;
322 }
323 /* get the lower 4 bits */
324 ret = temp & 0xF;
325
326 temp = READ_BANK_4;
327 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
328 if (err) {
329 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
330 return err;
331 }
332
333 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
334 if (err) {
335 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
336 return err;
337 }
338 /* get the upper 1 bit */
339 ret |= (temp & 0x1) << 4;
340 return ret;
341}
342
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700343#define READ_BANK_6 0x60
344static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
345{
346 u8 temp;
347 int err;
348
349 temp = READ_BANK_6;
350 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
351 if (err) {
352 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
353 return err;
354 }
355
356 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
357 if (err) {
358 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
359 return err;
360 }
361
362 /* return the lower 4 bits */
363 return temp & CHG_ALL_LOOPS;
364}
365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366#define CHG_USB_SUSPEND_BIT BIT(2)
367static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
368{
369 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
370 enable ? CHG_USB_SUSPEND_BIT : 0);
371}
372
373#define CHG_EN_BIT BIT(7)
374static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
375{
376 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
377 enable ? CHG_EN_BIT : 0);
378}
379
David Keitel753ec8d2011-11-02 10:56:37 -0700380#define CHG_FAILED_CLEAR BIT(0)
381#define ATC_FAILED_CLEAR BIT(1)
382static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
383{
384 int rc;
385
386 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
387 clear ? ATC_FAILED_CLEAR : 0);
388 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
389 clear ? CHG_FAILED_CLEAR : 0);
390 return rc;
391}
392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393#define CHG_CHARGE_DIS_BIT BIT(1)
394static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
395{
396 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
397 disable ? CHG_CHARGE_DIS_BIT : 0);
398}
399
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800400static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip)
401{
402 u8 temp = 0;
403
404 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
405 return !!(temp & CHG_CHARGE_DIS_BIT);
406}
407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408#define PM8921_CHG_V_MIN_MV 3240
409#define PM8921_CHG_V_STEP_MV 20
410#define PM8921_CHG_VDDMAX_MAX 4500
411#define PM8921_CHG_VDDMAX_MIN 3400
412#define PM8921_CHG_V_MASK 0x7F
413static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
414{
415 u8 temp;
416
417 if (voltage < PM8921_CHG_VDDMAX_MIN
418 || voltage > PM8921_CHG_VDDMAX_MAX) {
419 pr_err("bad mV=%d asked to set\n", voltage);
420 return -EINVAL;
421 }
422 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
423 pr_debug("voltage=%d setting %02x\n", voltage, temp);
424 return pm_chg_masked_write(chip, CHG_VDD_MAX, PM8921_CHG_V_MASK, temp);
425}
426
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700427static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
428{
429 u8 temp;
430 int rc;
431
432 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
433 if (rc) {
434 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700435 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700436 return rc;
437 }
438 temp &= PM8921_CHG_V_MASK;
439 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
440 return 0;
441}
442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443#define PM8921_CHG_VDDSAFE_MIN 3400
444#define PM8921_CHG_VDDSAFE_MAX 4500
445static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
446{
447 u8 temp;
448
449 if (voltage < PM8921_CHG_VDDSAFE_MIN
450 || voltage > PM8921_CHG_VDDSAFE_MAX) {
451 pr_err("bad mV=%d asked to set\n", voltage);
452 return -EINVAL;
453 }
454 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
455 pr_debug("voltage=%d setting %02x\n", voltage, temp);
456 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
457}
458
459#define PM8921_CHG_VBATDET_MIN 3240
460#define PM8921_CHG_VBATDET_MAX 5780
461static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
462{
463 u8 temp;
464
465 if (voltage < PM8921_CHG_VBATDET_MIN
466 || voltage > PM8921_CHG_VBATDET_MAX) {
467 pr_err("bad mV=%d asked to set\n", voltage);
468 return -EINVAL;
469 }
470 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
471 pr_debug("voltage=%d setting %02x\n", voltage, temp);
472 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
473}
474
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700475#define PM8921_CHG_VINMIN_MIN_MV 3800
476#define PM8921_CHG_VINMIN_STEP_MV 100
477#define PM8921_CHG_VINMIN_USABLE_MAX 6500
478#define PM8921_CHG_VINMIN_USABLE_MIN 4300
479#define PM8921_CHG_VINMIN_MASK 0x1F
480static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
481{
482 u8 temp;
483
484 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
485 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
486 pr_err("bad mV=%d asked to set\n", voltage);
487 return -EINVAL;
488 }
489 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
490 pr_debug("voltage=%d setting %02x\n", voltage, temp);
491 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
492 temp);
493}
494
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800495static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
496{
497 u8 temp;
498 int rc, voltage_mv;
499
500 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
501 temp &= PM8921_CHG_VINMIN_MASK;
502
503 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
504 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
505
506 return voltage_mv;
507}
508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509#define PM8921_CHG_IBATMAX_MIN 325
510#define PM8921_CHG_IBATMAX_MAX 2000
511#define PM8921_CHG_I_MIN_MA 225
512#define PM8921_CHG_I_STEP_MA 50
513#define PM8921_CHG_I_MASK 0x3F
514static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
515{
516 u8 temp;
517
518 if (chg_current < PM8921_CHG_IBATMAX_MIN
519 || chg_current > PM8921_CHG_IBATMAX_MAX) {
520 pr_err("bad mA=%d asked to set\n", chg_current);
521 return -EINVAL;
522 }
523 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
524 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
525}
526
527#define PM8921_CHG_IBATSAFE_MIN 225
528#define PM8921_CHG_IBATSAFE_MAX 3375
529static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
530{
531 u8 temp;
532
533 if (chg_current < PM8921_CHG_IBATSAFE_MIN
534 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
535 pr_err("bad mA=%d asked to set\n", chg_current);
536 return -EINVAL;
537 }
538 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
539 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
540 PM8921_CHG_I_MASK, temp);
541}
542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700544#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545#define PM8921_CHG_ITERM_STEP_MA 10
546#define PM8921_CHG_ITERM_MASK 0xF
547static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
548{
549 u8 temp;
550
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700551 if (chg_current < PM8921_CHG_ITERM_MIN_MA
552 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 pr_err("bad mA=%d asked to set\n", chg_current);
554 return -EINVAL;
555 }
556
557 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
558 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700559 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 temp);
561}
562
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700563static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
564{
565 u8 temp;
566 int rc;
567
568 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
569 if (rc) {
570 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700571 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700572 return rc;
573 }
574 temp &= PM8921_CHG_ITERM_MASK;
575 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
576 + PM8921_CHG_ITERM_MIN_MA;
577 return 0;
578}
579
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800580struct usb_ma_limit_entry {
581 int usb_ma;
582 u8 chg_iusb_value;
583};
584
585static struct usb_ma_limit_entry usb_ma_table[] = {
586 {100, 0},
587 {500, 1},
588 {700, 2},
589 {850, 3},
590 {900, 4},
591 {1100, 5},
592 {1300, 6},
593 {1500, 7},
594};
595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596#define PM8921_CHG_IUSB_MASK 0x1C
597#define PM8921_CHG_IUSB_MAX 7
598#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700599static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600{
601 u8 temp;
602
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700603 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
604 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 return -EINVAL;
606 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700607 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
609 temp);
610}
611
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800612static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
613{
614 u8 temp;
615 int i, rc;
616
617 *mA = 0;
618 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
619 if (rc) {
620 pr_err("err=%d reading PBL_ACCESS2\n", rc);
621 return rc;
622 }
623 temp &= PM8921_CHG_IUSB_MASK;
624 temp = temp >> 2;
625 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
626 if (usb_ma_table[i].chg_iusb_value == temp)
627 *mA = usb_ma_table[i].usb_ma;
628 }
629 return rc;
630}
631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632#define PM8921_CHG_WD_MASK 0x1F
633static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
634{
635 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700636 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
637}
638
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700639#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700640#define PM8921_CHG_TCHG_MIN 4
641#define PM8921_CHG_TCHG_MAX 512
642#define PM8921_CHG_TCHG_STEP 4
643static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
644{
645 u8 temp;
646
647 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
648 pr_err("bad max minutes =%d asked to set\n", minutes);
649 return -EINVAL;
650 }
651
652 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
653 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
654 temp);
655}
656
657#define PM8921_CHG_TTRKL_MASK 0x1F
658#define PM8921_CHG_TTRKL_MIN 1
659#define PM8921_CHG_TTRKL_MAX 64
660static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
661{
662 u8 temp;
663
664 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
665 pr_err("bad max minutes =%d asked to set\n", minutes);
666 return -EINVAL;
667 }
668
669 temp = minutes - 1;
670 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
671 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672}
673
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700674#define PM8921_CHG_VTRKL_MIN_MV 2050
675#define PM8921_CHG_VTRKL_MAX_MV 2800
676#define PM8921_CHG_VTRKL_STEP_MV 50
677#define PM8921_CHG_VTRKL_SHIFT 4
678#define PM8921_CHG_VTRKL_MASK 0xF0
679static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
680{
681 u8 temp;
682
683 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
684 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
685 pr_err("bad voltage = %dmV asked to set\n", millivolts);
686 return -EINVAL;
687 }
688
689 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
690 temp = temp << PM8921_CHG_VTRKL_SHIFT;
691 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
692 temp);
693}
694
695#define PM8921_CHG_VWEAK_MIN_MV 2100
696#define PM8921_CHG_VWEAK_MAX_MV 3600
697#define PM8921_CHG_VWEAK_STEP_MV 100
698#define PM8921_CHG_VWEAK_MASK 0x0F
699static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
700{
701 u8 temp;
702
703 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
704 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
705 pr_err("bad voltage = %dmV asked to set\n", millivolts);
706 return -EINVAL;
707 }
708
709 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
710 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
711 temp);
712}
713
714#define PM8921_CHG_ITRKL_MIN_MA 50
715#define PM8921_CHG_ITRKL_MAX_MA 200
716#define PM8921_CHG_ITRKL_MASK 0x0F
717#define PM8921_CHG_ITRKL_STEP_MA 10
718static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
719{
720 u8 temp;
721
722 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
723 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
724 pr_err("bad current = %dmA asked to set\n", milliamps);
725 return -EINVAL;
726 }
727
728 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
729
730 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
731 temp);
732}
733
734#define PM8921_CHG_IWEAK_MIN_MA 325
735#define PM8921_CHG_IWEAK_MAX_MA 525
736#define PM8921_CHG_IWEAK_SHIFT 7
737#define PM8921_CHG_IWEAK_MASK 0x80
738static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
739{
740 u8 temp;
741
742 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
743 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
744 pr_err("bad current = %dmA asked to set\n", milliamps);
745 return -EINVAL;
746 }
747
748 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
749 temp = 0;
750 else
751 temp = 1;
752
753 temp = temp << PM8921_CHG_IWEAK_SHIFT;
754 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
755 temp);
756}
757
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700758#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
759#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
760static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
761 enum pm8921_chg_cold_thr cold_thr)
762{
763 u8 temp;
764
765 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
766 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
767 return pm_chg_masked_write(chip, CHG_CNTRL_2,
768 PM8921_CHG_BATT_TEMP_THR_COLD,
769 temp);
770}
771
772#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
773#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
774static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
775 enum pm8921_chg_hot_thr hot_thr)
776{
777 u8 temp;
778
779 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
780 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
781 return pm_chg_masked_write(chip, CHG_CNTRL_2,
782 PM8921_CHG_BATT_TEMP_THR_HOT,
783 temp);
784}
785
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700786static int64_t read_battery_id(struct pm8921_chg_chip *chip)
787{
788 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700789 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700790
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700791 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700792 if (rc) {
793 pr_err("error reading batt id channel = %d, rc = %d\n",
794 chip->vbat_channel, rc);
795 return rc;
796 }
797 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
798 result.measurement);
799 return result.physical;
800}
801
802static int is_battery_valid(struct pm8921_chg_chip *chip)
803{
804 int64_t rc;
805
806 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
807 return 1;
808
809 rc = read_battery_id(chip);
810 if (rc < 0) {
811 pr_err("error reading batt id channel = %d, rc = %lld\n",
812 chip->vbat_channel, rc);
813 /* assume battery id is valid when adc error happens */
814 return 1;
815 }
816
817 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
818 pr_err("batt_id phy =%lld is not valid\n", rc);
819 return 0;
820 }
821 return 1;
822}
823
824static void check_battery_valid(struct pm8921_chg_chip *chip)
825{
826 if (is_battery_valid(chip) == 0) {
827 pr_err("batt_id not valid, disbling charging\n");
828 pm_chg_auto_enable(chip, 0);
829 } else {
830 pm_chg_auto_enable(chip, !charging_disabled);
831 }
832}
833
834static void battery_id_valid(struct work_struct *work)
835{
836 struct pm8921_chg_chip *chip = container_of(work,
837 struct pm8921_chg_chip, battery_id_valid_work);
838
839 check_battery_valid(chip);
840}
841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
843{
844 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
845 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
846 enable_irq(chip->pmic_chg_irq[interrupt]);
847 }
848}
849
850static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
851{
852 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
853 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
854 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
855 }
856}
857
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800858static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
859{
860 return test_bit(interrupt, chip->enabled_irqs);
861}
862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
864{
865 return pm8xxx_read_irq_stat(chip->dev->parent,
866 chip->pmic_chg_irq[irq_id]);
867}
868
869/* Treat OverVoltage/UnderVoltage as source missing */
870static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
871{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700872 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873}
874
875/* Treat OverVoltage/UnderVoltage as source missing */
876static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
877{
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -0700878 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879}
880
Amir Samuelovd31ef502011-10-26 14:41:36 +0200881static bool is_ext_charging(struct pm8921_chg_chip *chip)
882{
David Keitel88e1b572012-01-11 11:57:14 -0800883 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200884
David Keitel88e1b572012-01-11 11:57:14 -0800885 if (!chip->ext_psy)
886 return false;
887 if (chip->ext_psy->get_property(chip->ext_psy,
888 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
889 return false;
890 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
891 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200892
893 return false;
894}
895
896static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
897{
David Keitel88e1b572012-01-11 11:57:14 -0800898 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200899
David Keitel88e1b572012-01-11 11:57:14 -0800900 if (!chip->ext_psy)
901 return false;
902 if (chip->ext_psy->get_property(chip->ext_psy,
903 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
904 return false;
905 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +0200906 return true;
907
908 return false;
909}
910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911static int is_battery_charging(int fsm_state)
912{
Amir Samuelovd31ef502011-10-26 14:41:36 +0200913 if (is_ext_charging(the_chip))
914 return 1;
915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 switch (fsm_state) {
917 case FSM_STATE_ATC_2A:
918 case FSM_STATE_ATC_2B:
919 case FSM_STATE_ON_CHG_AND_BAT_6:
920 case FSM_STATE_FAST_CHG_7:
921 case FSM_STATE_TRKL_CHG_8:
922 return 1;
923 }
924 return 0;
925}
926
927static void bms_notify(struct work_struct *work)
928{
929 struct bms_notify *n = container_of(work, struct bms_notify, work);
930
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700931 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700933 } else {
934 pm8921_bms_charging_end(n->is_battery_full);
935 n->is_battery_full = 0;
936 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937}
938
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -0700939static void bms_notify_check(struct pm8921_chg_chip *chip)
940{
941 int fsm_state, new_is_charging;
942
943 fsm_state = pm_chg_get_fsm_state(chip);
944 new_is_charging = is_battery_charging(fsm_state);
945
946 if (chip->bms_notify.is_charging ^ new_is_charging) {
947 chip->bms_notify.is_charging = new_is_charging;
948 schedule_work(&(chip->bms_notify.work));
949 }
950}
951
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952static enum power_supply_property pm_power_props[] = {
953 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -0700954 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955};
956
957static char *pm_power_supplied_to[] = {
958 "battery",
959};
960
David Keitel6ed71a52012-01-30 12:42:18 -0800961#define USB_WALL_THRESHOLD_MA 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962static int pm_power_get_property(struct power_supply *psy,
963 enum power_supply_property psp,
964 union power_supply_propval *val)
965{
David Keitel6ed71a52012-01-30 12:42:18 -0800966 int current_max;
967
968 /* Check if called before init */
969 if (!the_chip)
970 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971
972 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -0800973 case POWER_SUPPLY_PROP_CURRENT_MAX:
974 pm_chg_iusbmax_get(the_chip, &current_max);
975 val->intval = current_max;
976 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -0700978 case POWER_SUPPLY_PROP_ONLINE:
David Keitel6ed71a52012-01-30 12:42:18 -0800979 if (pm_is_chg_charge_dis_bit_set(the_chip) ||
980 !is_usb_chg_plugged_in(the_chip))
981 val->intval = 0;
982 else if (psy->type == POWER_SUPPLY_TYPE_USB ||
983 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
984 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
985 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
986 val->intval = 1;
987 } else if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
988 pm_chg_iusbmax_get(the_chip, &current_max);
989 if (current_max > USB_WALL_THRESHOLD_MA)
990 val->intval = 1;
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800991 else
David Keitel6ed71a52012-01-30 12:42:18 -0800992 val->intval = 0;
993 } else {
994 val->intval = 0;
995 pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 }
997 break;
998 default:
999 return -EINVAL;
1000 }
1001 return 0;
1002}
1003
1004static enum power_supply_property msm_batt_power_props[] = {
1005 POWER_SUPPLY_PROP_STATUS,
1006 POWER_SUPPLY_PROP_CHARGE_TYPE,
1007 POWER_SUPPLY_PROP_HEALTH,
1008 POWER_SUPPLY_PROP_PRESENT,
1009 POWER_SUPPLY_PROP_TECHNOLOGY,
1010 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1011 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1012 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1013 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001014 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001015 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001016 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017};
1018
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001019static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020{
1021 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001022 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001024 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 if (rc) {
1026 pr_err("error reading adc channel = %d, rc = %d\n",
1027 chip->vbat_channel, rc);
1028 return rc;
1029 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001030 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 result.measurement);
1032 return (int)result.physical;
1033}
1034
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001035static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1036{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001037 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1038 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1039 unsigned int low_voltage = chip->min_voltage_mv;
1040 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001041
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001042 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001043 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001044 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001045 return 100;
1046 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001047 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001048 / (high_voltage - low_voltage);
1049}
1050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1052{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001053 int percent_soc = pm8921_bms_get_percent_charge();
1054
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001055 if (percent_soc == -ENXIO)
1056 percent_soc = voltage_based_capacity(chip);
1057
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001058 if (percent_soc <= 10)
1059 pr_warn("low battery charge = %d%%\n", percent_soc);
1060
1061 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062}
1063
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001064static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1065{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001066 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001067
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001068 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001069 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001070 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001071 }
1072
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001073 if (rc) {
1074 pr_err("unable to get batt current rc = %d\n", rc);
1075 return rc;
1076 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001077 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001078 }
1079}
1080
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001081static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1082{
1083 int rc;
1084
1085 rc = pm8921_bms_get_fcc();
1086 if (rc < 0)
1087 pr_err("unable to get batt fcc rc = %d\n", rc);
1088 return rc;
1089}
1090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1092{
1093 int temp;
1094
1095 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1096 if (temp)
1097 return POWER_SUPPLY_HEALTH_OVERHEAT;
1098
1099 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1100 if (temp)
1101 return POWER_SUPPLY_HEALTH_COLD;
1102
1103 return POWER_SUPPLY_HEALTH_GOOD;
1104}
1105
1106static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1107{
1108 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1109}
1110
1111static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1112{
1113 int temp;
1114
Amir Samuelovd31ef502011-10-26 14:41:36 +02001115 if (!get_prop_batt_present(chip))
1116 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1117
1118 if (is_ext_trickle_charging(chip))
1119 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1120
1121 if (is_ext_charging(chip))
1122 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001124 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1125 if (temp)
1126 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1127
1128 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1129 if (temp)
1130 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1131
1132 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1133}
1134
1135static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1136{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001137 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1138 int fsm_state = pm_chg_get_fsm_state(chip);
1139 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140
David Keitel88e1b572012-01-11 11:57:14 -08001141 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001142 if (chip->ext_charge_done)
1143 return POWER_SUPPLY_STATUS_FULL;
1144 if (chip->ext_charging)
1145 return POWER_SUPPLY_STATUS_CHARGING;
1146 }
1147
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001148 for (i = 0; i < ARRAY_SIZE(map); i++)
1149 if (map[i].fsm_state == fsm_state)
1150 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001151
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001152 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1153 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1154 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001155 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1156 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001157
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001158 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001159 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001160 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161}
1162
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001163#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001164static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1165{
1166 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001167 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001168
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001169 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001170 if (rc) {
1171 pr_err("error reading adc channel = %d, rc = %d\n",
1172 chip->vbat_channel, rc);
1173 return rc;
1174 }
1175 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1176 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001177 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1178 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1179 (int) result.physical);
1180
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001181 return (int)result.physical;
1182}
1183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184static int pm_batt_power_get_property(struct power_supply *psy,
1185 enum power_supply_property psp,
1186 union power_supply_propval *val)
1187{
1188 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1189 batt_psy);
1190
1191 switch (psp) {
1192 case POWER_SUPPLY_PROP_STATUS:
1193 val->intval = get_prop_batt_status(chip);
1194 break;
1195 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1196 val->intval = get_prop_charge_type(chip);
1197 break;
1198 case POWER_SUPPLY_PROP_HEALTH:
1199 val->intval = get_prop_batt_health(chip);
1200 break;
1201 case POWER_SUPPLY_PROP_PRESENT:
1202 val->intval = get_prop_batt_present(chip);
1203 break;
1204 case POWER_SUPPLY_PROP_TECHNOLOGY:
1205 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1206 break;
1207 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001208 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 break;
1210 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001211 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 break;
1213 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001214 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 break;
1216 case POWER_SUPPLY_PROP_CAPACITY:
1217 val->intval = get_prop_batt_capacity(chip);
1218 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001219 case POWER_SUPPLY_PROP_CURRENT_NOW:
1220 val->intval = get_prop_batt_current(chip);
1221 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001222 case POWER_SUPPLY_PROP_TEMP:
1223 val->intval = get_prop_batt_temp(chip);
1224 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001225 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001226 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001227 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001228 default:
1229 return -EINVAL;
1230 }
1231
1232 return 0;
1233}
1234
1235static void (*notify_vbus_state_func_ptr)(int);
1236static int usb_chg_current;
1237static DEFINE_SPINLOCK(vbus_lock);
1238
1239int pm8921_charger_register_vbus_sn(void (*callback)(int))
1240{
1241 pr_debug("%p\n", callback);
1242 notify_vbus_state_func_ptr = callback;
1243 return 0;
1244}
1245EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1246
1247/* this is passed to the hsusb via platform_data msm_otg_pdata */
1248void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1249{
1250 pr_debug("%p\n", callback);
1251 notify_vbus_state_func_ptr = NULL;
1252}
1253EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1254
1255static void notify_usb_of_the_plugin_event(int plugin)
1256{
1257 plugin = !!plugin;
1258 if (notify_vbus_state_func_ptr) {
1259 pr_debug("notifying plugin\n");
1260 (*notify_vbus_state_func_ptr) (plugin);
1261 } else {
1262 pr_debug("unable to notify plugin\n");
1263 }
1264}
1265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266/* assumes vbus_lock is held */
1267static void __pm8921_charger_vbus_draw(unsigned int mA)
1268{
1269 int i, rc;
1270
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001271 if (usb_max_current && mA > usb_max_current) {
1272 pr_warn("restricting usb current to %d instead of %d\n",
1273 usb_max_current, mA);
1274 mA = usb_max_current;
1275 }
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 if (mA > 0 && mA <= 2) {
1278 usb_chg_current = 0;
1279 rc = pm_chg_iusbmax_set(the_chip,
1280 usb_ma_table[0].chg_iusb_value);
1281 if (rc) {
1282 pr_err("unable to set iusb to %d rc = %d\n",
1283 usb_ma_table[0].chg_iusb_value, rc);
1284 }
1285 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1286 if (rc)
1287 pr_err("fail to set suspend bit rc=%d\n", rc);
1288 } else {
1289 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1290 if (rc)
1291 pr_err("fail to reset suspend bit rc=%d\n", rc);
1292 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1293 if (usb_ma_table[i].usb_ma <= mA)
1294 break;
1295 }
1296 if (i < 0)
1297 i = 0;
1298 rc = pm_chg_iusbmax_set(the_chip,
1299 usb_ma_table[i].chg_iusb_value);
1300 if (rc) {
1301 pr_err("unable to set iusb to %d rc = %d\n",
1302 usb_ma_table[i].chg_iusb_value, rc);
1303 }
1304 }
1305}
1306
1307/* USB calls these to tell us how much max usb current the system can draw */
1308void pm8921_charger_vbus_draw(unsigned int mA)
1309{
1310 unsigned long flags;
1311
1312 pr_debug("Enter charge=%d\n", mA);
1313 spin_lock_irqsave(&vbus_lock, flags);
1314 if (the_chip) {
1315 __pm8921_charger_vbus_draw(mA);
1316 } else {
1317 /*
1318 * called before pmic initialized,
1319 * save this value and use it at probe
1320 */
1321 usb_chg_current = mA;
1322 }
1323 spin_unlock_irqrestore(&vbus_lock, flags);
1324}
1325EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1326
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001327int pm8921_charger_enable(bool enable)
1328{
1329 int rc;
1330
1331 if (!the_chip) {
1332 pr_err("called before init\n");
1333 return -EINVAL;
1334 }
1335 enable = !!enable;
1336 rc = pm_chg_auto_enable(the_chip, enable);
1337 if (rc)
1338 pr_err("Failed rc=%d\n", rc);
1339 return rc;
1340}
1341EXPORT_SYMBOL(pm8921_charger_enable);
1342
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001343int pm8921_is_usb_chg_plugged_in(void)
1344{
1345 if (!the_chip) {
1346 pr_err("called before init\n");
1347 return -EINVAL;
1348 }
1349 return is_usb_chg_plugged_in(the_chip);
1350}
1351EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1352
1353int pm8921_is_dc_chg_plugged_in(void)
1354{
1355 if (!the_chip) {
1356 pr_err("called before init\n");
1357 return -EINVAL;
1358 }
1359 return is_dc_chg_plugged_in(the_chip);
1360}
1361EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1362
1363int pm8921_is_battery_present(void)
1364{
1365 if (!the_chip) {
1366 pr_err("called before init\n");
1367 return -EINVAL;
1368 }
1369 return get_prop_batt_present(the_chip);
1370}
1371EXPORT_SYMBOL(pm8921_is_battery_present);
1372
David Keitel012deef2011-12-02 11:49:33 -08001373/*
1374 * Disabling the charge current limit causes current
1375 * current limits to have no monitoring. An adequate charger
1376 * capable of supplying high current while sustaining VIN_MIN
1377 * is required if the limiting is disabled.
1378 */
1379int pm8921_disable_input_current_limit(bool disable)
1380{
1381 if (!the_chip) {
1382 pr_err("called before init\n");
1383 return -EINVAL;
1384 }
1385 if (disable) {
1386 pr_warn("Disabling input current limit!\n");
1387
1388 return pm8xxx_writeb(the_chip->dev->parent,
1389 CHG_BUCK_CTRL_TEST3, 0xF2);
1390 }
1391 return 0;
1392}
1393EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1394
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001395int pm8921_set_max_battery_charge_current(int ma)
1396{
1397 if (!the_chip) {
1398 pr_err("called before init\n");
1399 return -EINVAL;
1400 }
1401 return pm_chg_ibatmax_set(the_chip, ma);
1402}
1403EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1404
1405int pm8921_disable_source_current(bool disable)
1406{
1407 if (!the_chip) {
1408 pr_err("called before init\n");
1409 return -EINVAL;
1410 }
1411 if (disable)
1412 pr_warn("current drawn from chg=0, battery provides current\n");
1413 return pm_chg_charge_dis(the_chip, disable);
1414}
1415EXPORT_SYMBOL(pm8921_disable_source_current);
1416
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001417int pm8921_regulate_input_voltage(int voltage)
1418{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001419 int rc;
1420
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001421 if (!the_chip) {
1422 pr_err("called before init\n");
1423 return -EINVAL;
1424 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001425 rc = pm_chg_vinmin_set(the_chip, voltage);
1426
1427 if (rc == 0)
1428 the_chip->vin_min = voltage;
1429
1430 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001431}
1432
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001433#define USB_OV_THRESHOLD_MASK 0x60
1434#define USB_OV_THRESHOLD_SHIFT 5
1435int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1436{
1437 u8 temp;
1438
1439 if (!the_chip) {
1440 pr_err("called before init\n");
1441 return -EINVAL;
1442 }
1443
1444 if (ov > PM_USB_OV_7V) {
1445 pr_err("limiting to over voltage threshold to 7volts\n");
1446 ov = PM_USB_OV_7V;
1447 }
1448
1449 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1450
1451 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1452 USB_OV_THRESHOLD_MASK, temp);
1453}
1454EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1455
1456#define USB_DEBOUNCE_TIME_MASK 0x06
1457#define USB_DEBOUNCE_TIME_SHIFT 1
1458int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1459{
1460 u8 temp;
1461
1462 if (!the_chip) {
1463 pr_err("called before init\n");
1464 return -EINVAL;
1465 }
1466
1467 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1468 pr_err("limiting debounce to 80.5ms\n");
1469 ms = PM_USB_DEBOUNCE_80P5MS;
1470 }
1471
1472 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1473
1474 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1475 USB_DEBOUNCE_TIME_MASK, temp);
1476}
1477EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1478
1479#define USB_OVP_DISABLE_MASK 0x80
1480int pm8921_usb_ovp_disable(int disable)
1481{
1482 u8 temp = 0;
1483
1484 if (!the_chip) {
1485 pr_err("called before init\n");
1486 return -EINVAL;
1487 }
1488
1489 if (disable)
1490 temp = USB_OVP_DISABLE_MASK;
1491
1492 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1493 USB_OVP_DISABLE_MASK, temp);
1494}
1495
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001496bool pm8921_is_battery_charging(int *source)
1497{
1498 int fsm_state, is_charging, dc_present, usb_present;
1499
1500 if (!the_chip) {
1501 pr_err("called before init\n");
1502 return -EINVAL;
1503 }
1504 fsm_state = pm_chg_get_fsm_state(the_chip);
1505 is_charging = is_battery_charging(fsm_state);
1506 if (is_charging == 0) {
1507 *source = PM8921_CHG_SRC_NONE;
1508 return is_charging;
1509 }
1510
1511 if (source == NULL)
1512 return is_charging;
1513
1514 /* the battery is charging, the source is requested, find it */
1515 dc_present = is_dc_chg_plugged_in(the_chip);
1516 usb_present = is_usb_chg_plugged_in(the_chip);
1517
1518 if (dc_present && !usb_present)
1519 *source = PM8921_CHG_SRC_DC;
1520
1521 if (usb_present && !dc_present)
1522 *source = PM8921_CHG_SRC_USB;
1523
1524 if (usb_present && dc_present)
1525 /*
1526 * The system always chooses dc for charging since it has
1527 * higher priority.
1528 */
1529 *source = PM8921_CHG_SRC_DC;
1530
1531 return is_charging;
1532}
1533EXPORT_SYMBOL(pm8921_is_battery_charging);
1534
David Keitel6df9cea2011-12-21 12:36:45 -08001535int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1536{
1537 if (!the_chip) {
1538 pr_err("called before init\n");
1539 return -EINVAL;
1540 }
1541
1542 if (type < POWER_SUPPLY_TYPE_USB)
1543 return -EINVAL;
1544
1545 the_chip->usb_psy.type = type;
1546 power_supply_changed(&the_chip->usb_psy);
1547 return 0;
1548}
1549EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1550
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001551int pm8921_batt_temperature(void)
1552{
1553 if (!the_chip) {
1554 pr_err("called before init\n");
1555 return -EINVAL;
1556 }
1557 return get_prop_batt_temp(the_chip);
1558}
1559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1561{
1562 int usb_present;
1563
1564 usb_present = is_usb_chg_plugged_in(chip);
1565 if (chip->usb_present ^ usb_present) {
1566 notify_usb_of_the_plugin_event(usb_present);
1567 chip->usb_present = usb_present;
1568 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001569 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001571 if (usb_present) {
1572 schedule_delayed_work(&chip->unplug_check_work,
1573 round_jiffies_relative(msecs_to_jiffies
1574 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1575 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001576 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577}
1578
Amir Samuelovd31ef502011-10-26 14:41:36 +02001579static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1580{
David Keitel88e1b572012-01-11 11:57:14 -08001581 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001582 pr_debug("external charger not registered.\n");
1583 return;
1584 }
1585
1586 if (!chip->ext_charging) {
1587 pr_debug("already not charging.\n");
1588 return;
1589 }
1590
David Keitel88e1b572012-01-11 11:57:14 -08001591 power_supply_set_charge_type(chip->ext_psy,
1592 POWER_SUPPLY_CHARGE_TYPE_NONE);
1593 pm8921_disable_source_current(false); /* release BATFET */
Amir Samuelovd31ef502011-10-26 14:41:36 +02001594 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001595 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001596 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001597}
1598
1599static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1600{
1601 int dc_present;
1602 int batt_present;
1603 int batt_temp_ok;
1604 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001605 unsigned long delay =
1606 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1607
David Keitel88e1b572012-01-11 11:57:14 -08001608 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001609 pr_debug("external charger not registered.\n");
1610 return;
1611 }
1612
1613 if (chip->ext_charging) {
1614 pr_debug("already charging.\n");
1615 return;
1616 }
1617
David Keitel88e1b572012-01-11 11:57:14 -08001618 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001619 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1620 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001621
1622 if (!dc_present) {
1623 pr_warn("%s. dc not present.\n", __func__);
1624 return;
1625 }
1626 if (!batt_present) {
1627 pr_warn("%s. battery not present.\n", __func__);
1628 return;
1629 }
1630 if (!batt_temp_ok) {
1631 pr_warn("%s. battery temperature not ok.\n", __func__);
1632 return;
1633 }
David Keitel88e1b572012-01-11 11:57:14 -08001634 pm8921_disable_source_current(true); /* Force BATFET=ON */
1635 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001636 if (vbat_ov) {
1637 pr_warn("%s. battery over voltage.\n", __func__);
1638 return;
1639 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001640
David Keitel88e1b572012-01-11 11:57:14 -08001641 power_supply_set_charge_type(chip->ext_psy,
1642 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001643 chip->ext_charging = true;
1644 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001645 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001646 /* Start BMS */
1647 schedule_delayed_work(&chip->eoc_work, delay);
1648 wake_lock(&chip->eoc_wake_lock);
1649}
1650
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001651#define WRITE_BANK_4 0xC0
1652static void unplug_wrkarnd_restore_worker(struct work_struct *work)
1653{
1654 u8 temp;
1655 int rc;
1656 struct delayed_work *dwork = to_delayed_work(work);
1657 struct pm8921_chg_chip *chip = container_of(dwork,
1658 struct pm8921_chg_chip,
1659 unplug_wrkarnd_restore_work);
1660
1661 pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
1662 rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
1663
1664 temp = WRITE_BANK_4 | 0xA;
1665 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1666 if (rc) {
1667 pr_err("Error %d writing %d to addr %d\n", rc,
1668 temp, CHG_BUCK_CTRL_TEST3);
1669 }
1670 wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
1671}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1673{
1674 handle_usb_insertion_removal(data);
1675 return IRQ_HANDLED;
1676}
1677
1678static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1679{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001680 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 return IRQ_HANDLED;
1682}
1683
1684static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1685{
1686 struct pm8921_chg_chip *chip = data;
1687 int status;
1688
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001689 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1690 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001691 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 pr_debug("battery present=%d", status);
1693 power_supply_changed(&chip->batt_psy);
1694 return IRQ_HANDLED;
1695}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001696
1697/*
1698 * this interrupt used to restart charging a battery.
1699 *
1700 * Note: When DC-inserted the VBAT can't go low.
1701 * VPH_PWR is provided by the ext-charger.
1702 * After End-Of-Charging from DC, charging can be resumed only
1703 * if DC is removed and then inserted after the battery was in use.
1704 * Therefore the handle_start_ext_chg() is not called.
1705 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1707{
1708 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001709 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001710
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001711 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001712
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001713 if (high_transition) {
1714 /* enable auto charging */
1715 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001716 pr_info("batt fell below resume voltage %s\n",
1717 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001718 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001720
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 power_supply_changed(&chip->batt_psy);
1722 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 return IRQ_HANDLED;
1725}
1726
1727static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1728{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001729 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 return IRQ_HANDLED;
1731}
1732
1733static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1734{
1735 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1736 return IRQ_HANDLED;
1737}
1738
1739static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1740{
1741 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1742 return IRQ_HANDLED;
1743}
1744
1745static irqreturn_t vcp_irq_handler(int irq, void *data)
1746{
1747 pr_warning("VCP triggered BATDET forced on\n");
1748 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1749 return IRQ_HANDLED;
1750}
1751
1752static irqreturn_t atcdone_irq_handler(int irq, void *data)
1753{
1754 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1755 return IRQ_HANDLED;
1756}
1757
1758static irqreturn_t atcfail_irq_handler(int irq, void *data)
1759{
1760 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1761 return IRQ_HANDLED;
1762}
1763
1764static irqreturn_t chgdone_irq_handler(int irq, void *data)
1765{
1766 struct pm8921_chg_chip *chip = data;
1767
1768 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001769
1770 handle_stop_ext_chg(chip);
1771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 power_supply_changed(&chip->batt_psy);
1773 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001774
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001775 bms_notify_check(chip);
1776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 return IRQ_HANDLED;
1778}
1779
1780static irqreturn_t chgfail_irq_handler(int irq, void *data)
1781{
1782 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001783 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001784
David Keitel753ec8d2011-11-02 10:56:37 -07001785 ret = pm_chg_failed_clear(chip, 1);
1786 if (ret)
1787 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1788
1789 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1790 get_prop_batt_present(chip),
1791 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1792 pm_chg_get_fsm_state(data));
1793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 power_supply_changed(&chip->batt_psy);
1795 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 return IRQ_HANDLED;
1797}
1798
1799static irqreturn_t chgstate_irq_handler(int irq, void *data)
1800{
1801 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802
1803 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1804 power_supply_changed(&chip->batt_psy);
1805 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001807 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 return IRQ_HANDLED;
1810}
1811
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001812#define VIN_ACTIVE_BIT BIT(0)
1813#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
1814#define VIN_MIN_INCREASE_MV 100
1815static void unplug_check_worker(struct work_struct *work)
1816{
1817 struct delayed_work *dwork = to_delayed_work(work);
1818 struct pm8921_chg_chip *chip = container_of(dwork,
1819 struct pm8921_chg_chip, unplug_check_work);
1820 u8 reg_loop;
1821 int ibat, usb_chg_plugged_in;
1822
1823 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1824 if (!usb_chg_plugged_in) {
1825 pr_debug("Stopping Unplug Check Worker since USB is removed"
1826 "reg_loop = %d, fsm = %d ibat = %d\n",
1827 pm_chg_get_regulation_loop(chip),
1828 pm_chg_get_fsm_state(chip),
1829 get_prop_batt_current(chip)
1830 );
1831 return;
1832 }
1833 reg_loop = pm_chg_get_regulation_loop(chip);
1834 pr_debug("reg_loop=0x%x\n", reg_loop);
1835
1836 if (reg_loop & VIN_ACTIVE_BIT) {
1837 ibat = get_prop_batt_current(chip);
1838
1839 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
1840 ibat, pm_chg_get_fsm_state(chip), reg_loop);
1841 if (ibat > 0) {
1842 int err;
1843 u8 temp;
1844
1845 temp = WRITE_BANK_4 | 0xE;
1846 err = pm8xxx_writeb(chip->dev->parent,
1847 CHG_BUCK_CTRL_TEST3, temp);
1848 if (err) {
1849 pr_err("Error %d writing %d to addr %d\n", err,
1850 temp, CHG_BUCK_CTRL_TEST3);
1851 }
1852
1853 pm_chg_vinmin_set(chip,
1854 chip->vin_min + VIN_MIN_INCREASE_MV);
1855
1856 wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
1857 schedule_delayed_work(
1858 &chip->unplug_wrkarnd_restore_work,
1859 round_jiffies_relative(usecs_to_jiffies
1860 (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
1861 }
1862 }
1863
1864 schedule_delayed_work(&chip->unplug_check_work,
1865 round_jiffies_relative(msecs_to_jiffies
1866 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1867}
1868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869static irqreturn_t loop_change_irq_handler(int irq, void *data)
1870{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001871 struct pm8921_chg_chip *chip = data;
1872
1873 pr_debug("fsm_state=%d reg_loop=0x%x\n",
1874 pm_chg_get_fsm_state(data),
1875 pm_chg_get_regulation_loop(data));
1876 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877 return IRQ_HANDLED;
1878}
1879
1880static irqreturn_t fastchg_irq_handler(int irq, void *data)
1881{
1882 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001883 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001885 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1886 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
1887 wake_lock(&chip->eoc_wake_lock);
1888 schedule_delayed_work(&chip->eoc_work,
1889 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001890 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001891 }
1892 power_supply_changed(&chip->batt_psy);
1893 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894 return IRQ_HANDLED;
1895}
1896
1897static irqreturn_t trklchg_irq_handler(int irq, void *data)
1898{
1899 struct pm8921_chg_chip *chip = data;
1900
1901 power_supply_changed(&chip->batt_psy);
1902 return IRQ_HANDLED;
1903}
1904
1905static irqreturn_t batt_removed_irq_handler(int irq, void *data)
1906{
1907 struct pm8921_chg_chip *chip = data;
1908 int status;
1909
1910 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
1911 pr_debug("battery present=%d state=%d", !status,
1912 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001913 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914 power_supply_changed(&chip->batt_psy);
1915 return IRQ_HANDLED;
1916}
1917
1918static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
1919{
1920 struct pm8921_chg_chip *chip = data;
1921
Amir Samuelovd31ef502011-10-26 14:41:36 +02001922 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923 power_supply_changed(&chip->batt_psy);
1924 return IRQ_HANDLED;
1925}
1926
1927static irqreturn_t chghot_irq_handler(int irq, void *data)
1928{
1929 struct pm8921_chg_chip *chip = data;
1930
1931 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
1932 power_supply_changed(&chip->batt_psy);
1933 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08001934 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 return IRQ_HANDLED;
1936}
1937
1938static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
1939{
1940 struct pm8921_chg_chip *chip = data;
1941
1942 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001943 handle_stop_ext_chg(chip);
1944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 power_supply_changed(&chip->batt_psy);
1946 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001947 return IRQ_HANDLED;
1948}
1949
1950static irqreturn_t chg_gone_irq_handler(int irq, void *data)
1951{
1952 struct pm8921_chg_chip *chip = data;
1953
1954 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
1955 power_supply_changed(&chip->batt_psy);
1956 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 return IRQ_HANDLED;
1958}
David Keitel52fda532011-11-10 10:43:44 -08001959/*
1960 *
1961 * bat_temp_ok_irq_handler - is edge triggered, hence it will
1962 * fire for two cases:
1963 *
1964 * If the interrupt line switches to high temperature is okay
1965 * and thus charging begins.
1966 * If bat_temp_ok is low this means the temperature is now
1967 * too hot or cold, so charging is stopped.
1968 *
1969 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
1971{
David Keitel52fda532011-11-10 10:43:44 -08001972 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 struct pm8921_chg_chip *chip = data;
1974
David Keitel52fda532011-11-10 10:43:44 -08001975 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
1976
1977 pr_debug("batt_temp_ok = %d fsm_state%d\n",
1978 bat_temp_ok, pm_chg_get_fsm_state(data));
1979
1980 if (bat_temp_ok)
1981 handle_start_ext_chg(chip);
1982 else
1983 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 power_supply_changed(&chip->batt_psy);
1986 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001987 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 return IRQ_HANDLED;
1989}
1990
1991static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
1992{
1993 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1994 return IRQ_HANDLED;
1995}
1996
1997static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
1998{
1999 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2000 return IRQ_HANDLED;
2001}
2002
2003static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2004{
2005 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2006 return IRQ_HANDLED;
2007}
2008
2009static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2010{
2011 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2012 return IRQ_HANDLED;
2013}
2014
2015static irqreturn_t batfet_irq_handler(int irq, void *data)
2016{
2017 struct pm8921_chg_chip *chip = data;
2018
2019 pr_debug("vreg ov\n");
2020 power_supply_changed(&chip->batt_psy);
2021 return IRQ_HANDLED;
2022}
2023
2024static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2025{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002026 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002027 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002028
David Keitel88e1b572012-01-11 11:57:14 -08002029 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2030 if (chip->ext_psy)
2031 power_supply_set_online(chip->ext_psy, dc_present);
2032 chip->dc_present = dc_present;
2033 if (dc_present)
2034 handle_start_ext_chg(chip);
2035 else
2036 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 return IRQ_HANDLED;
2038}
2039
2040static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2041{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002042 struct pm8921_chg_chip *chip = data;
2043
Amir Samuelovd31ef502011-10-26 14:41:36 +02002044 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045 return IRQ_HANDLED;
2046}
2047
2048static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2049{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002050 struct pm8921_chg_chip *chip = data;
2051
Amir Samuelovd31ef502011-10-26 14:41:36 +02002052 handle_stop_ext_chg(chip);
2053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 return IRQ_HANDLED;
2055}
2056
David Keitel88e1b572012-01-11 11:57:14 -08002057static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2058{
2059 struct power_supply *psy = &the_chip->batt_psy;
2060 struct power_supply *epsy = dev_get_drvdata(dev);
2061 int i, dcin_irq;
2062
2063 /* Only search for external supply if none is registered */
2064 if (!the_chip->ext_psy) {
2065 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2066 for (i = 0; i < epsy->num_supplicants; i++) {
2067 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2068 if (!strncmp(epsy->name, "dc", 2)) {
2069 the_chip->ext_psy = epsy;
2070 dcin_valid_irq_handler(dcin_irq,
2071 the_chip);
2072 }
2073 }
2074 }
2075 }
2076 return 0;
2077}
2078
2079static void pm_batt_external_power_changed(struct power_supply *psy)
2080{
2081 /* Only look for an external supply if it hasn't been registered */
2082 if (!the_chip->ext_psy)
2083 class_for_each_device(power_supply_class, NULL, psy,
2084 __pm_batt_external_power_changed_work);
2085}
2086
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002087/**
2088 * update_heartbeat - internal function to update userspace
2089 * per update_time minutes
2090 *
2091 */
2092static void update_heartbeat(struct work_struct *work)
2093{
2094 struct delayed_work *dwork = to_delayed_work(work);
2095 struct pm8921_chg_chip *chip = container_of(dwork,
2096 struct pm8921_chg_chip, update_heartbeat_work);
2097
2098 power_supply_changed(&chip->batt_psy);
2099 schedule_delayed_work(&chip->update_heartbeat_work,
2100 round_jiffies_relative(msecs_to_jiffies
2101 (chip->update_time)));
2102}
2103
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002104enum {
2105 CHG_IN_PROGRESS,
2106 CHG_NOT_IN_PROGRESS,
2107 CHG_FINISHED,
2108};
2109
2110#define VBAT_TOLERANCE_MV 70
2111#define CHG_DISABLE_MSLEEP 100
2112static int is_charging_finished(struct pm8921_chg_chip *chip)
2113{
2114 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2115 int ichg_meas_ma, iterm_programmed;
2116 int regulation_loop, fast_chg, vcp;
2117 int rc;
2118 static int last_vbat_programmed = -EINVAL;
2119
2120 if (!is_ext_charging(chip)) {
2121 /* return if the battery is not being fastcharged */
2122 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2123 pr_debug("fast_chg = %d\n", fast_chg);
2124 if (fast_chg == 0)
2125 return CHG_NOT_IN_PROGRESS;
2126
2127 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2128 pr_debug("vcp = %d\n", vcp);
2129 if (vcp == 1)
2130 return CHG_IN_PROGRESS;
2131
2132 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2133 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2134 if (vbatdet_low == 1)
2135 return CHG_IN_PROGRESS;
2136
2137 /* reset count if battery is hot/cold */
2138 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2139 pr_debug("batt_temp_ok = %d\n", rc);
2140 if (rc == 0)
2141 return CHG_IN_PROGRESS;
2142
2143 /* reset count if battery voltage is less than vddmax */
2144 vbat_meas_uv = get_prop_battery_uvolts(chip);
2145 if (vbat_meas_uv < 0)
2146 return CHG_IN_PROGRESS;
2147 vbat_meas_mv = vbat_meas_uv / 1000;
2148
2149 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2150 if (rc) {
2151 pr_err("couldnt read vddmax rc = %d\n", rc);
2152 return CHG_IN_PROGRESS;
2153 }
2154 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2155 vbat_programmed, vbat_meas_mv);
2156 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2157 return CHG_IN_PROGRESS;
2158
2159 if (last_vbat_programmed == -EINVAL)
2160 last_vbat_programmed = vbat_programmed;
2161 if (last_vbat_programmed != vbat_programmed) {
2162 /* vddmax changed, reset and check again */
2163 pr_debug("vddmax = %d last_vdd_max=%d\n",
2164 vbat_programmed, last_vbat_programmed);
2165 last_vbat_programmed = vbat_programmed;
2166 return CHG_IN_PROGRESS;
2167 }
2168
2169 /*
2170 * TODO if charging from an external charger
2171 * check SOC instead of regulation loop
2172 */
2173 regulation_loop = pm_chg_get_regulation_loop(chip);
2174 if (regulation_loop < 0) {
2175 pr_err("couldnt read the regulation loop err=%d\n",
2176 regulation_loop);
2177 return CHG_IN_PROGRESS;
2178 }
2179 pr_debug("regulation_loop=%d\n", regulation_loop);
2180
2181 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2182 return CHG_IN_PROGRESS;
2183 } /* !is_ext_charging */
2184
2185 /* reset count if battery chg current is more than iterm */
2186 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2187 if (rc) {
2188 pr_err("couldnt read iterm rc = %d\n", rc);
2189 return CHG_IN_PROGRESS;
2190 }
2191
2192 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2193 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2194 iterm_programmed, ichg_meas_ma);
2195 /*
2196 * ichg_meas_ma < 0 means battery is drawing current
2197 * ichg_meas_ma > 0 means battery is providing current
2198 */
2199 if (ichg_meas_ma > 0)
2200 return CHG_IN_PROGRESS;
2201
2202 if (ichg_meas_ma * -1 > iterm_programmed)
2203 return CHG_IN_PROGRESS;
2204
2205 return CHG_FINISHED;
2206}
2207
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002208/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002209 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002210 * has happened
2211 *
2212 * If all conditions favouring, if the charge current is
2213 * less than the term current for three consecutive times
2214 * an EOC has happened.
2215 * The wakelock is released if there is no need to reshedule
2216 * - this happens when the battery is removed or EOC has
2217 * happened
2218 */
2219#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002220static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002221{
2222 struct delayed_work *dwork = to_delayed_work(work);
2223 struct pm8921_chg_chip *chip = container_of(dwork,
2224 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002225 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002226 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002227
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002228 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002229 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002230 count = 0;
2231 wake_unlock(&chip->eoc_wake_lock);
2232 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002233 }
2234
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002235 if (end == CHG_FINISHED) {
2236 count++;
2237 } else {
2238 count = 0;
2239 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002240
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002241 if (count == CONSECUTIVE_COUNT) {
2242 count = 0;
2243 pr_info("End of Charging\n");
2244
2245 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002246
Amir Samuelovd31ef502011-10-26 14:41:36 +02002247 if (is_ext_charging(chip))
2248 chip->ext_charge_done = true;
2249
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002250 if (chip->is_bat_warm || chip->is_bat_cool)
2251 chip->bms_notify.is_battery_full = 0;
2252 else
2253 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002254 /* declare end of charging by invoking chgdone interrupt */
2255 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2256 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002257 } else {
2258 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002259 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002260 round_jiffies_relative(msecs_to_jiffies
2261 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002262 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002263}
2264
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002265static void btm_configure_work(struct work_struct *work)
2266{
2267 int rc;
2268
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002269 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002270 if (rc)
2271 pr_err("failed to configure btm rc=%d", rc);
2272}
2273
2274DECLARE_WORK(btm_config_work, btm_configure_work);
2275
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002276static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2277{
2278 unsigned int chg_current = chip->max_bat_chg_current;
2279
2280 if (chip->is_bat_cool)
2281 chg_current = min(chg_current, chip->cool_bat_chg_current);
2282
2283 if (chip->is_bat_warm)
2284 chg_current = min(chg_current, chip->warm_bat_chg_current);
2285
David Keitelfdef3a42011-12-14 19:02:54 -08002286 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002287 chg_current = min(chg_current,
2288 chip->thermal_mitigation[thermal_mitigation]);
2289
2290 pm_chg_ibatmax_set(the_chip, chg_current);
2291}
2292
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002293#define TEMP_HYSTERISIS_DEGC 2
2294static void battery_cool(bool enter)
2295{
2296 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002297 if (enter == the_chip->is_bat_cool)
2298 return;
2299 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002300 if (enter) {
2301 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002302 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002303 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002304 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002305 pm_chg_vbatdet_set(the_chip,
2306 the_chip->cool_bat_voltage
2307 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002308 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002309 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002310 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002311 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002312 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002313 the_chip->max_voltage_mv
2314 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002315 }
2316 schedule_work(&btm_config_work);
2317}
2318
2319static void battery_warm(bool enter)
2320{
2321 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002322 if (enter == the_chip->is_bat_warm)
2323 return;
2324 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002325 if (enter) {
2326 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002327 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002328 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002329 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002330 pm_chg_vbatdet_set(the_chip,
2331 the_chip->warm_bat_voltage
2332 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002333 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002334 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002335 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002336 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002337 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002338 the_chip->max_voltage_mv
2339 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002340 }
2341 schedule_work(&btm_config_work);
2342}
2343
2344static int configure_btm(struct pm8921_chg_chip *chip)
2345{
2346 int rc;
2347
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002348 if (chip->warm_temp_dc != INT_MIN)
2349 btm_config.btm_warm_fn = battery_warm;
2350 else
2351 btm_config.btm_warm_fn = NULL;
2352
2353 if (chip->cool_temp_dc != INT_MIN)
2354 btm_config.btm_cool_fn = battery_cool;
2355 else
2356 btm_config.btm_cool_fn = NULL;
2357
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002358 btm_config.low_thr_temp = chip->cool_temp_dc;
2359 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002360 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002361 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002362 if (rc)
2363 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002364 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002365 if (rc)
2366 pr_err("failed to start btm rc = %d\n", rc);
2367
2368 return rc;
2369}
2370
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002371/**
2372 * set_disable_status_param -
2373 *
2374 * Internal function to disable battery charging and also disable drawing
2375 * any current from the source. The device is forced to run on a battery
2376 * after this.
2377 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378static int set_disable_status_param(const char *val, struct kernel_param *kp)
2379{
2380 int ret;
2381 struct pm8921_chg_chip *chip = the_chip;
2382
2383 ret = param_set_int(val, kp);
2384 if (ret) {
2385 pr_err("error setting value %d\n", ret);
2386 return ret;
2387 }
2388 pr_info("factory set disable param to %d\n", charging_disabled);
2389 if (chip) {
2390 pm_chg_auto_enable(chip, !charging_disabled);
2391 pm_chg_charge_dis(chip, charging_disabled);
2392 }
2393 return 0;
2394}
2395module_param_call(disabled, set_disable_status_param, param_get_uint,
2396 &charging_disabled, 0644);
2397
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002398/**
2399 * set_thermal_mitigation_level -
2400 *
2401 * Internal function to control battery charging current to reduce
2402 * temperature
2403 */
2404static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2405{
2406 int ret;
2407 struct pm8921_chg_chip *chip = the_chip;
2408
2409 ret = param_set_int(val, kp);
2410 if (ret) {
2411 pr_err("error setting value %d\n", ret);
2412 return ret;
2413 }
2414
2415 if (!chip) {
2416 pr_err("called before init\n");
2417 return -EINVAL;
2418 }
2419
2420 if (!chip->thermal_mitigation) {
2421 pr_err("no thermal mitigation\n");
2422 return -EINVAL;
2423 }
2424
2425 if (thermal_mitigation < 0
2426 || thermal_mitigation >= chip->thermal_levels) {
2427 pr_err("out of bound level selected\n");
2428 return -EINVAL;
2429 }
2430
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002431 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002432 return ret;
2433}
2434module_param_call(thermal_mitigation, set_therm_mitigation_level,
2435 param_get_uint,
2436 &thermal_mitigation, 0644);
2437
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002438static int set_usb_max_current(const char *val, struct kernel_param *kp)
2439{
2440 int ret, mA;
2441 struct pm8921_chg_chip *chip = the_chip;
2442
2443 ret = param_set_int(val, kp);
2444 if (ret) {
2445 pr_err("error setting value %d\n", ret);
2446 return ret;
2447 }
2448 if (chip) {
2449 pr_warn("setting current max to %d\n", usb_max_current);
2450 pm_chg_iusbmax_get(chip, &mA);
2451 if (mA > usb_max_current)
2452 pm8921_charger_vbus_draw(usb_max_current);
2453 return 0;
2454 }
2455 return -EINVAL;
2456}
2457module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2458 &usb_max_current, 0644);
2459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460static void free_irqs(struct pm8921_chg_chip *chip)
2461{
2462 int i;
2463
2464 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2465 if (chip->pmic_chg_irq[i]) {
2466 free_irq(chip->pmic_chg_irq[i], chip);
2467 chip->pmic_chg_irq[i] = 0;
2468 }
2469}
2470
David Keitel88e1b572012-01-11 11:57:14 -08002471/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2473{
2474 unsigned long flags;
2475 int fsm_state;
2476
2477 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2478 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2479
2480 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002481 if (chip->usb_present) {
2482 schedule_delayed_work(&chip->unplug_check_work,
2483 round_jiffies_relative(msecs_to_jiffies
2484 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486
2487 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2488 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2489 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002490 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2491 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2492 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2493 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2494 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002495 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002496 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2497 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002498 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499
2500 spin_lock_irqsave(&vbus_lock, flags);
2501 if (usb_chg_current) {
2502 /* reissue a vbus draw call */
2503 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002504 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 }
2506 spin_unlock_irqrestore(&vbus_lock, flags);
2507
2508 fsm_state = pm_chg_get_fsm_state(chip);
2509 if (is_battery_charging(fsm_state)) {
2510 chip->bms_notify.is_charging = 1;
2511 pm8921_bms_charging_began();
2512 }
2513
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002514 check_battery_valid(chip);
2515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002516 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2517 chip->usb_present,
2518 chip->dc_present,
2519 get_prop_batt_present(chip),
2520 fsm_state);
2521}
2522
2523struct pm_chg_irq_init_data {
2524 unsigned int irq_id;
2525 char *name;
2526 unsigned long flags;
2527 irqreturn_t (*handler)(int, void *);
2528};
2529
2530#define CHG_IRQ(_id, _flags, _handler) \
2531{ \
2532 .irq_id = _id, \
2533 .name = #_id, \
2534 .flags = _flags, \
2535 .handler = _handler, \
2536}
2537struct pm_chg_irq_init_data chg_irq_data[] = {
2538 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2539 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002540 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2542 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002543 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2544 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2546 usbin_uv_irq_handler),
2547 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2548 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2549 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2550 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2551 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2552 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2553 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2554 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2555 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002556 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2557 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2559 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2560 batt_removed_irq_handler),
2561 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2562 batttemp_hot_irq_handler),
2563 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2564 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2565 batttemp_cold_irq_handler),
2566 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002567 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2568 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2570 coarse_det_low_irq_handler),
2571 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2572 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2573 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2574 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2575 batfet_irq_handler),
2576 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2577 dcin_valid_irq_handler),
2578 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2579 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002580 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581};
2582
2583static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2584 struct platform_device *pdev)
2585{
2586 struct resource *res;
2587 int ret, i;
2588
2589 ret = 0;
2590 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2591
2592 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2593 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2594 chg_irq_data[i].name);
2595 if (res == NULL) {
2596 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2597 goto err_out;
2598 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002599 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600 ret = request_irq(res->start, chg_irq_data[i].handler,
2601 chg_irq_data[i].flags,
2602 chg_irq_data[i].name, chip);
2603 if (ret < 0) {
2604 pr_err("couldn't request %d (%s) %d\n", res->start,
2605 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002606 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 goto err_out;
2608 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2610 }
2611 return 0;
2612
2613err_out:
2614 free_irqs(chip);
2615 return -EINVAL;
2616}
2617
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002618static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2619{
2620 int err;
2621 u8 temp;
2622
2623 temp = 0xD1;
2624 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2625 if (err) {
2626 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2627 return;
2628 }
2629
2630 temp = 0xD3;
2631 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2632 if (err) {
2633 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2634 return;
2635 }
2636
2637 temp = 0xD1;
2638 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2639 if (err) {
2640 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2641 return;
2642 }
2643
2644 temp = 0xD5;
2645 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2646 if (err) {
2647 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2648 return;
2649 }
2650
2651 udelay(183);
2652
2653 temp = 0xD1;
2654 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2655 if (err) {
2656 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2657 return;
2658 }
2659
2660 temp = 0xD0;
2661 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2662 if (err) {
2663 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2664 return;
2665 }
2666 udelay(32);
2667
2668 temp = 0xD1;
2669 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2670 if (err) {
2671 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2672 return;
2673 }
2674
2675 temp = 0xD3;
2676 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2677 if (err) {
2678 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2679 return;
2680 }
2681}
2682
2683static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2684{
2685 int err;
2686 u8 temp;
2687
2688 temp = 0xD1;
2689 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2690 if (err) {
2691 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2692 return;
2693 }
2694
2695 temp = 0xD0;
2696 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2697 if (err) {
2698 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2699 return;
2700 }
2701}
2702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002703#define ENUM_TIMER_STOP_BIT BIT(1)
2704#define BOOT_DONE_BIT BIT(6)
2705#define CHG_BATFET_ON_BIT BIT(3)
2706#define CHG_VCP_EN BIT(0)
2707#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2708#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002709#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2711{
2712 int rc;
2713
2714 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2715 BOOT_DONE_BIT, BOOT_DONE_BIT);
2716 if (rc) {
2717 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2718 return rc;
2719 }
2720
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002721 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 if (rc) {
2723 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002724 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725 return rc;
2726 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002727 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002728 chip->max_voltage_mv
2729 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002730 if (rc) {
2731 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002732 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733 return rc;
2734 }
2735
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002736 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 if (rc) {
2738 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002739 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002740 return rc;
2741 }
2742 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2743 if (rc) {
2744 pr_err("Failed to set max voltage to %d rc=%d\n",
2745 SAFE_CURRENT_MA, rc);
2746 return rc;
2747 }
2748
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002749 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750 if (rc) {
2751 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2752 return rc;
2753 }
2754
2755 rc = pm_chg_iterm_set(chip, chip->term_current);
2756 if (rc) {
2757 pr_err("Failed to set term current to %d rc=%d\n",
2758 chip->term_current, rc);
2759 return rc;
2760 }
2761
2762 /* Disable the ENUM TIMER */
2763 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2764 ENUM_TIMER_STOP_BIT);
2765 if (rc) {
2766 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2767 return rc;
2768 }
2769
2770 /* init with the lowest USB current */
2771 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
2772 if (rc) {
2773 pr_err("Failed to set usb max to %d rc=%d\n",
2774 usb_ma_table[0].chg_iusb_value, rc);
2775 return rc;
2776 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002777
2778 if (chip->safety_time != 0) {
2779 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
2780 if (rc) {
2781 pr_err("Failed to set max time to %d minutes rc=%d\n",
2782 chip->safety_time, rc);
2783 return rc;
2784 }
2785 }
2786
2787 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07002788 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002789 if (rc) {
2790 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
2791 chip->safety_time, rc);
2792 return rc;
2793 }
2794 }
2795
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002796 if (chip->vin_min != 0) {
2797 rc = pm_chg_vinmin_set(chip, chip->vin_min);
2798 if (rc) {
2799 pr_err("Failed to set vin min to %d mV rc=%d\n",
2800 chip->vin_min, rc);
2801 return rc;
2802 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002803 } else {
2804 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002805 }
2806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807 rc = pm_chg_disable_wd(chip);
2808 if (rc) {
2809 pr_err("Failed to disable wd rc=%d\n", rc);
2810 return rc;
2811 }
2812
2813 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
2814 CHG_BAT_TEMP_DIS_BIT, 0);
2815 if (rc) {
2816 pr_err("Failed to enable temp control chg rc=%d\n", rc);
2817 return rc;
2818 }
2819 /* switch to a 3.2Mhz for the buck */
2820 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
2821 if (rc) {
2822 pr_err("Failed to switch buck clk rc=%d\n", rc);
2823 return rc;
2824 }
2825
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07002826 if (chip->trkl_voltage != 0) {
2827 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
2828 if (rc) {
2829 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
2830 chip->trkl_voltage, rc);
2831 return rc;
2832 }
2833 }
2834
2835 if (chip->weak_voltage != 0) {
2836 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
2837 if (rc) {
2838 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
2839 chip->weak_voltage, rc);
2840 return rc;
2841 }
2842 }
2843
2844 if (chip->trkl_current != 0) {
2845 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
2846 if (rc) {
2847 pr_err("Failed to set trkl current to %dmA rc=%d\n",
2848 chip->trkl_voltage, rc);
2849 return rc;
2850 }
2851 }
2852
2853 if (chip->weak_current != 0) {
2854 rc = pm_chg_iweak_set(chip, chip->weak_current);
2855 if (rc) {
2856 pr_err("Failed to set weak current to %dmA rc=%d\n",
2857 chip->weak_current, rc);
2858 return rc;
2859 }
2860 }
2861
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07002862 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
2863 if (rc) {
2864 pr_err("Failed to set cold config %d rc=%d\n",
2865 chip->cold_thr, rc);
2866 }
2867
2868 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
2869 if (rc) {
2870 pr_err("Failed to set hot config %d rc=%d\n",
2871 chip->hot_thr, rc);
2872 }
2873
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002874 /* Workarounds for die 1.1 and 1.0 */
2875 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
2876 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
2878 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002879
2880 /* software workaround for correct battery_id detection */
2881 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
2882 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
2883 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
2884 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
2885 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
2886 udelay(100);
2887 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 }
2889
David Keitelb51995e2011-11-18 17:03:31 -08002890 /* Workarounds for die 3.0 */
2891 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
2892 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
2893
2894 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
2895
David Keitela3c0d822011-11-03 14:18:52 -07002896 /* Disable EOC FSM processing */
2897 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
2898
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002899 pm8921_chg_force_19p2mhz_clk(chip);
2900
2901 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
2902 VREF_BATT_THERM_FORCE_ON);
2903 if (rc)
2904 pr_err("Failed to Force Vref therm rc=%d\n", rc);
2905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002906 rc = pm_chg_charge_dis(chip, charging_disabled);
2907 if (rc) {
2908 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
2909 return rc;
2910 }
2911
2912 rc = pm_chg_auto_enable(chip, !charging_disabled);
2913 if (rc) {
2914 pr_err("Failed to enable charging rc=%d\n", rc);
2915 return rc;
2916 }
2917
2918 return 0;
2919}
2920
2921static int get_rt_status(void *data, u64 * val)
2922{
2923 int i = (int)data;
2924 int ret;
2925
2926 /* global irq number is passed in via data */
2927 ret = pm_chg_get_rt_status(the_chip, i);
2928 *val = ret;
2929 return 0;
2930}
2931DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
2932
2933static int get_fsm_status(void *data, u64 * val)
2934{
2935 u8 temp;
2936
2937 temp = pm_chg_get_fsm_state(the_chip);
2938 *val = temp;
2939 return 0;
2940}
2941DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
2942
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002943static int get_reg_loop(void *data, u64 * val)
2944{
2945 u8 temp;
2946
2947 if (!the_chip) {
2948 pr_err("%s called before init\n", __func__);
2949 return -EINVAL;
2950 }
2951 temp = pm_chg_get_regulation_loop(the_chip);
2952 *val = temp;
2953 return 0;
2954}
2955DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
2956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957static int get_reg(void *data, u64 * val)
2958{
2959 int addr = (int)data;
2960 int ret;
2961 u8 temp;
2962
2963 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
2964 if (ret) {
2965 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
2966 addr, temp, ret);
2967 return -EAGAIN;
2968 }
2969 *val = temp;
2970 return 0;
2971}
2972
2973static int set_reg(void *data, u64 val)
2974{
2975 int addr = (int)data;
2976 int ret;
2977 u8 temp;
2978
2979 temp = (u8) val;
2980 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
2981 if (ret) {
2982 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
2983 addr, temp, ret);
2984 return -EAGAIN;
2985 }
2986 return 0;
2987}
2988DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
2989
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002990enum {
2991 BAT_WARM_ZONE,
2992 BAT_COOL_ZONE,
2993};
2994static int get_warm_cool(void *data, u64 * val)
2995{
2996 if (!the_chip) {
2997 pr_err("%s called before init\n", __func__);
2998 return -EINVAL;
2999 }
3000 if ((int)data == BAT_WARM_ZONE)
3001 *val = the_chip->is_bat_warm;
3002 if ((int)data == BAT_COOL_ZONE)
3003 *val = the_chip->is_bat_cool;
3004 return 0;
3005}
3006DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003008static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3009{
3010 int i;
3011
3012 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3013
3014 if (IS_ERR(chip->dent)) {
3015 pr_err("pmic charger couldnt create debugfs dir\n");
3016 return;
3017 }
3018
3019 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3020 (void *)CHG_CNTRL, &reg_fops);
3021 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3022 (void *)CHG_CNTRL_2, &reg_fops);
3023 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3024 (void *)CHG_CNTRL_3, &reg_fops);
3025 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3026 (void *)PBL_ACCESS1, &reg_fops);
3027 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3028 (void *)PBL_ACCESS2, &reg_fops);
3029 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3030 (void *)SYS_CONFIG_1, &reg_fops);
3031 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3032 (void *)SYS_CONFIG_2, &reg_fops);
3033 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3034 (void *)CHG_VDD_MAX, &reg_fops);
3035 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3036 (void *)CHG_VDD_SAFE, &reg_fops);
3037 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3038 (void *)CHG_VBAT_DET, &reg_fops);
3039 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3040 (void *)CHG_IBAT_MAX, &reg_fops);
3041 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3042 (void *)CHG_IBAT_SAFE, &reg_fops);
3043 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3044 (void *)CHG_VIN_MIN, &reg_fops);
3045 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3046 (void *)CHG_VTRICKLE, &reg_fops);
3047 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3048 (void *)CHG_ITRICKLE, &reg_fops);
3049 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3050 (void *)CHG_ITERM, &reg_fops);
3051 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3052 (void *)CHG_TCHG_MAX, &reg_fops);
3053 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3054 (void *)CHG_TWDOG, &reg_fops);
3055 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3056 (void *)CHG_TEMP_THRESH, &reg_fops);
3057 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3058 (void *)CHG_COMP_OVR, &reg_fops);
3059 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3060 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3061 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3062 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3063 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3064 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3065 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3066 (void *)CHG_TEST, &reg_fops);
3067
3068 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3069 &fsm_fops);
3070
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003071 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3072 &reg_loop_fops);
3073
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003074 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3075 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3076 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3077 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3080 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3081 debugfs_create_file(chg_irq_data[i].name, 0444,
3082 chip->dent,
3083 (void *)chg_irq_data[i].irq_id,
3084 &rt_fops);
3085 }
3086}
3087
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003088static int pm8921_charger_suspend_noirq(struct device *dev)
3089{
3090 int rc;
3091 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3092
3093 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3094 if (rc)
3095 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3096 pm8921_chg_set_hw_clk_switching(chip);
3097 return 0;
3098}
3099
3100static int pm8921_charger_resume_noirq(struct device *dev)
3101{
3102 int rc;
3103 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3104
3105 pm8921_chg_force_19p2mhz_clk(chip);
3106
3107 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3108 VREF_BATT_THERM_FORCE_ON);
3109 if (rc)
3110 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3111 return 0;
3112}
3113
David Keitelf2226022011-12-13 15:55:50 -08003114static int pm8921_charger_resume(struct device *dev)
3115{
3116 int rc;
3117 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3118
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003119 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003120 && !(chip->keep_btm_on_suspend)) {
3121 rc = pm8xxx_adc_btm_configure(&btm_config);
3122 if (rc)
3123 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3124
3125 rc = pm8xxx_adc_btm_start();
3126 if (rc)
3127 pr_err("couldn't restart btm rc=%d\n", rc);
3128 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003129 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3130 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3131 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3132 }
David Keitelf2226022011-12-13 15:55:50 -08003133 return 0;
3134}
3135
3136static int pm8921_charger_suspend(struct device *dev)
3137{
3138 int rc;
3139 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3140
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003141 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003142 && !(chip->keep_btm_on_suspend)) {
3143 rc = pm8xxx_adc_btm_end();
3144 if (rc)
3145 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3146 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003147
3148 if (is_usb_chg_plugged_in(chip)) {
3149 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3150 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3151 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003152
David Keitelf2226022011-12-13 15:55:50 -08003153 return 0;
3154}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003155static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3156{
3157 int rc = 0;
3158 struct pm8921_chg_chip *chip;
3159 const struct pm8921_charger_platform_data *pdata
3160 = pdev->dev.platform_data;
3161
3162 if (!pdata) {
3163 pr_err("missing platform data\n");
3164 return -EINVAL;
3165 }
3166
3167 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3168 GFP_KERNEL);
3169 if (!chip) {
3170 pr_err("Cannot allocate pm_chg_chip\n");
3171 return -ENOMEM;
3172 }
3173
3174 chip->dev = &pdev->dev;
3175 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003176 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003178 chip->max_voltage_mv = pdata->max_voltage;
3179 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003180 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 chip->term_current = pdata->term_current;
3182 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003183 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003184 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3185 chip->batt_id_min = pdata->batt_id_min;
3186 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003187 if (pdata->cool_temp != INT_MIN)
3188 chip->cool_temp_dc = pdata->cool_temp * 10;
3189 else
3190 chip->cool_temp_dc = INT_MIN;
3191
3192 if (pdata->warm_temp != INT_MIN)
3193 chip->warm_temp_dc = pdata->warm_temp * 10;
3194 else
3195 chip->warm_temp_dc = INT_MIN;
3196
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003197 chip->temp_check_period = pdata->temp_check_period;
3198 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3199 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3200 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3201 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3202 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003203 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003204 chip->trkl_voltage = pdata->trkl_voltage;
3205 chip->weak_voltage = pdata->weak_voltage;
3206 chip->trkl_current = pdata->trkl_current;
3207 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003208 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003209 chip->thermal_mitigation = pdata->thermal_mitigation;
3210 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003212 chip->cold_thr = pdata->cold_thr;
3213 chip->hot_thr = pdata->hot_thr;
3214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 rc = pm8921_chg_hw_init(chip);
3216 if (rc) {
3217 pr_err("couldn't init hardware rc=%d\n", rc);
3218 goto free_chip;
3219 }
3220
3221 chip->usb_psy.name = "usb",
3222 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3223 chip->usb_psy.supplied_to = pm_power_supplied_to,
3224 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3225 chip->usb_psy.properties = pm_power_props,
3226 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3227 chip->usb_psy.get_property = pm_power_get_property,
3228
David Keitel6ed71a52012-01-30 12:42:18 -08003229 chip->dc_psy.name = "pm8921-dc",
3230 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3231 chip->dc_psy.supplied_to = pm_power_supplied_to,
3232 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3233 chip->dc_psy.properties = pm_power_props,
3234 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
3235 chip->dc_psy.get_property = pm_power_get_property,
3236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003237 chip->batt_psy.name = "battery",
3238 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3239 chip->batt_psy.properties = msm_batt_power_props,
3240 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3241 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003242 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003243 rc = power_supply_register(chip->dev, &chip->usb_psy);
3244 if (rc < 0) {
3245 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003246 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247 }
3248
David Keitel6ed71a52012-01-30 12:42:18 -08003249 rc = power_supply_register(chip->dev, &chip->dc_psy);
3250 if (rc < 0) {
3251 pr_err("power_supply_register usb failed rc = %d\n", rc);
3252 goto unregister_usb;
3253 }
3254
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 rc = power_supply_register(chip->dev, &chip->batt_psy);
3256 if (rc < 0) {
3257 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003258 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 }
3260
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003261 platform_set_drvdata(pdev, chip);
3262 the_chip = chip;
3263
3264 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003265 wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
3266 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003267 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003268 INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
3269 unplug_wrkarnd_restore_worker);
3270 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003271
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 rc = request_irqs(chip, pdev);
3273 if (rc) {
3274 pr_err("couldn't register interrupts rc=%d\n", rc);
3275 goto unregister_batt;
3276 }
3277
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003278 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3279 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3280 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003281 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3282 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003283 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003284 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003285 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003286 * care for jeita compliance
3287 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003288 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003289 rc = configure_btm(chip);
3290 if (rc) {
3291 pr_err("couldn't register with btm rc=%d\n", rc);
3292 goto free_irq;
3293 }
3294 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 create_debugfs_entries(chip);
3297
3298 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003299 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 /* determine what state the charger is in */
3302 determine_initial_state(chip);
3303
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003304 if (chip->update_time) {
3305 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3306 update_heartbeat);
3307 schedule_delayed_work(&chip->update_heartbeat_work,
3308 round_jiffies_relative(msecs_to_jiffies
3309 (chip->update_time)));
3310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 return 0;
3312
3313free_irq:
3314 free_irqs(chip);
3315unregister_batt:
3316 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003317unregister_dc:
3318 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003319unregister_usb:
3320 power_supply_unregister(&chip->usb_psy);
3321free_chip:
3322 kfree(chip);
3323 return rc;
3324}
3325
3326static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3327{
3328 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3329
3330 free_irqs(chip);
3331 platform_set_drvdata(pdev, NULL);
3332 the_chip = NULL;
3333 kfree(chip);
3334 return 0;
3335}
David Keitelf2226022011-12-13 15:55:50 -08003336static const struct dev_pm_ops pm8921_pm_ops = {
3337 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003338 .suspend_noirq = pm8921_charger_suspend_noirq,
3339 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003340 .resume = pm8921_charger_resume,
3341};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003342static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003343 .probe = pm8921_charger_probe,
3344 .remove = __devexit_p(pm8921_charger_remove),
3345 .driver = {
3346 .name = PM8921_CHARGER_DEV_NAME,
3347 .owner = THIS_MODULE,
3348 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 },
3350};
3351
3352static int __init pm8921_charger_init(void)
3353{
3354 return platform_driver_register(&pm8921_charger_driver);
3355}
3356
3357static void __exit pm8921_charger_exit(void)
3358{
3359 platform_driver_unregister(&pm8921_charger_driver);
3360}
3361
3362late_initcall(pm8921_charger_init);
3363module_exit(pm8921_charger_exit);
3364
3365MODULE_LICENSE("GPL v2");
3366MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3367MODULE_VERSION("1.0");
3368MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);