blob: 0d1589064834ad06ea9a02243c738f3449c29e66 [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;
David Keitel8c5201a2012-02-24 16:08:54 -0800259 struct work_struct unplug_ovp_fet_open_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800260 struct delayed_work unplug_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700261 struct wake_lock eoc_wake_lock;
262 enum pm8921_chg_cold_thr cold_thr;
263 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800264 int rconn_mohm;
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
David Keitelcf867232012-01-27 18:40:12 -0800296static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
297{
298 return pm8xxx_read_irq_stat(chip->dev->parent,
299 chip->pmic_chg_irq[irq_id]);
300}
301
302/* Treat OverVoltage/UnderVoltage as source missing */
303static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
304{
305 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
306}
307
308/* Treat OverVoltage/UnderVoltage as source missing */
309static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
310{
311 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
312}
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314#define CAPTURE_FSM_STATE_CMD 0xC2
315#define READ_BANK_7 0x70
316#define READ_BANK_4 0x40
317static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
318{
319 u8 temp;
320 int err, ret = 0;
321
322 temp = CAPTURE_FSM_STATE_CMD;
323 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
324 if (err) {
325 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
326 return err;
327 }
328
329 temp = READ_BANK_7;
330 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
331 if (err) {
332 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
333 return err;
334 }
335
336 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
337 if (err) {
338 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
339 return err;
340 }
341 /* get the lower 4 bits */
342 ret = temp & 0xF;
343
344 temp = READ_BANK_4;
345 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
346 if (err) {
347 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
348 return err;
349 }
350
351 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
352 if (err) {
353 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
354 return err;
355 }
356 /* get the upper 1 bit */
357 ret |= (temp & 0x1) << 4;
358 return ret;
359}
360
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700361#define READ_BANK_6 0x60
362static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
363{
364 u8 temp;
365 int err;
366
367 temp = READ_BANK_6;
368 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
369 if (err) {
370 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
371 return err;
372 }
373
374 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
375 if (err) {
376 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
377 return err;
378 }
379
380 /* return the lower 4 bits */
381 return temp & CHG_ALL_LOOPS;
382}
383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384#define CHG_USB_SUSPEND_BIT BIT(2)
385static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
386{
387 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
388 enable ? CHG_USB_SUSPEND_BIT : 0);
389}
390
391#define CHG_EN_BIT BIT(7)
392static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
393{
394 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
395 enable ? CHG_EN_BIT : 0);
396}
397
David Keitel753ec8d2011-11-02 10:56:37 -0700398#define CHG_FAILED_CLEAR BIT(0)
399#define ATC_FAILED_CLEAR BIT(1)
400static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
401{
402 int rc;
403
404 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
405 clear ? ATC_FAILED_CLEAR : 0);
406 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
407 clear ? CHG_FAILED_CLEAR : 0);
408 return rc;
409}
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411#define CHG_CHARGE_DIS_BIT BIT(1)
412static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
413{
414 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
415 disable ? CHG_CHARGE_DIS_BIT : 0);
416}
417
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800418static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
419{
420 u8 temp;
421
422 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
423 return temp & CHG_CHARGE_DIS_BIT;
424}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425#define PM8921_CHG_V_MIN_MV 3240
426#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800427#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428#define PM8921_CHG_VDDMAX_MAX 4500
429#define PM8921_CHG_VDDMAX_MIN 3400
430#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800431static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800433 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800434 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800436 if (voltage < PM8921_CHG_VDDMAX_MIN
437 || voltage > PM8921_CHG_VDDMAX_MAX) {
438 pr_err("bad mV=%d asked to set\n", voltage);
439 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 }
David Keitelcf867232012-01-27 18:40:12 -0800441
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800442 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
443
444 remainder = voltage % 20;
445 if (remainder >= 10) {
446 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
447 }
448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800450 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451}
452
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700453static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
454{
455 u8 temp;
456 int rc;
457
458 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
459 if (rc) {
460 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700461 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700462 return rc;
463 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800464 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
465 + PM8921_CHG_V_MIN_MV;
466 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
467 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700468 return 0;
469}
470
David Keitelcf867232012-01-27 18:40:12 -0800471static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
472{
473 int current_mv, ret, steps, i;
474 bool increase;
475
476 ret = 0;
477
478 if (voltage < PM8921_CHG_VDDMAX_MIN
479 || voltage > PM8921_CHG_VDDMAX_MAX) {
480 pr_err("bad mV=%d asked to set\n", voltage);
481 return -EINVAL;
482 }
483
484 ret = pm_chg_vddmax_get(chip, &current_mv);
485 if (ret) {
486 pr_err("Failed to read vddmax rc=%d\n", ret);
487 return -EINVAL;
488 }
489 if (current_mv == voltage)
490 return 0;
491
492 /* Only change in increments when USB is present */
493 if (is_usb_chg_plugged_in(chip)) {
494 if (current_mv < voltage) {
495 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
496 increase = true;
497 } else {
498 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
499 increase = false;
500 }
501 for (i = 0; i < steps; i++) {
502 if (increase)
503 current_mv += PM8921_CHG_V_STEP_MV;
504 else
505 current_mv -= PM8921_CHG_V_STEP_MV;
506 ret |= __pm_chg_vddmax_set(chip, current_mv);
507 }
508 }
509 ret |= __pm_chg_vddmax_set(chip, voltage);
510 return ret;
511}
512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513#define PM8921_CHG_VDDSAFE_MIN 3400
514#define PM8921_CHG_VDDSAFE_MAX 4500
515static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
516{
517 u8 temp;
518
519 if (voltage < PM8921_CHG_VDDSAFE_MIN
520 || voltage > PM8921_CHG_VDDSAFE_MAX) {
521 pr_err("bad mV=%d asked to set\n", voltage);
522 return -EINVAL;
523 }
524 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
525 pr_debug("voltage=%d setting %02x\n", voltage, temp);
526 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
527}
528
529#define PM8921_CHG_VBATDET_MIN 3240
530#define PM8921_CHG_VBATDET_MAX 5780
531static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
532{
533 u8 temp;
534
535 if (voltage < PM8921_CHG_VBATDET_MIN
536 || voltage > PM8921_CHG_VBATDET_MAX) {
537 pr_err("bad mV=%d asked to set\n", voltage);
538 return -EINVAL;
539 }
540 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
541 pr_debug("voltage=%d setting %02x\n", voltage, temp);
542 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
543}
544
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700545#define PM8921_CHG_VINMIN_MIN_MV 3800
546#define PM8921_CHG_VINMIN_STEP_MV 100
547#define PM8921_CHG_VINMIN_USABLE_MAX 6500
548#define PM8921_CHG_VINMIN_USABLE_MIN 4300
549#define PM8921_CHG_VINMIN_MASK 0x1F
550static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
551{
552 u8 temp;
553
554 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
555 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
556 pr_err("bad mV=%d asked to set\n", voltage);
557 return -EINVAL;
558 }
559 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
560 pr_debug("voltage=%d setting %02x\n", voltage, temp);
561 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
562 temp);
563}
564
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800565static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
566{
567 u8 temp;
568 int rc, voltage_mv;
569
570 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
571 temp &= PM8921_CHG_VINMIN_MASK;
572
573 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
574 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
575
576 return voltage_mv;
577}
578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579#define PM8921_CHG_IBATMAX_MIN 325
580#define PM8921_CHG_IBATMAX_MAX 2000
581#define PM8921_CHG_I_MIN_MA 225
582#define PM8921_CHG_I_STEP_MA 50
583#define PM8921_CHG_I_MASK 0x3F
584static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
585{
586 u8 temp;
587
588 if (chg_current < PM8921_CHG_IBATMAX_MIN
589 || chg_current > PM8921_CHG_IBATMAX_MAX) {
590 pr_err("bad mA=%d asked to set\n", chg_current);
591 return -EINVAL;
592 }
593 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
594 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
595}
596
597#define PM8921_CHG_IBATSAFE_MIN 225
598#define PM8921_CHG_IBATSAFE_MAX 3375
599static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
600{
601 u8 temp;
602
603 if (chg_current < PM8921_CHG_IBATSAFE_MIN
604 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
605 pr_err("bad mA=%d asked to set\n", chg_current);
606 return -EINVAL;
607 }
608 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
609 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
610 PM8921_CHG_I_MASK, temp);
611}
612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700614#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615#define PM8921_CHG_ITERM_STEP_MA 10
616#define PM8921_CHG_ITERM_MASK 0xF
617static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
618{
619 u8 temp;
620
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700621 if (chg_current < PM8921_CHG_ITERM_MIN_MA
622 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 pr_err("bad mA=%d asked to set\n", chg_current);
624 return -EINVAL;
625 }
626
627 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
628 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700629 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 temp);
631}
632
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700633static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
634{
635 u8 temp;
636 int rc;
637
638 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
639 if (rc) {
640 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700641 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700642 return rc;
643 }
644 temp &= PM8921_CHG_ITERM_MASK;
645 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
646 + PM8921_CHG_ITERM_MIN_MA;
647 return 0;
648}
649
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800650struct usb_ma_limit_entry {
651 int usb_ma;
652 u8 chg_iusb_value;
653};
654
655static struct usb_ma_limit_entry usb_ma_table[] = {
656 {100, 0},
657 {500, 1},
658 {700, 2},
659 {850, 3},
660 {900, 4},
661 {1100, 5},
662 {1300, 6},
663 {1500, 7},
664};
665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666#define PM8921_CHG_IUSB_MASK 0x1C
667#define PM8921_CHG_IUSB_MAX 7
668#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700669static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670{
671 u8 temp;
672
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700673 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
674 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 return -EINVAL;
676 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700677 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
679 temp);
680}
681
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800682static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
683{
684 u8 temp;
685 int i, rc;
686
687 *mA = 0;
688 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
689 if (rc) {
690 pr_err("err=%d reading PBL_ACCESS2\n", rc);
691 return rc;
692 }
693 temp &= PM8921_CHG_IUSB_MASK;
694 temp = temp >> 2;
695 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
696 if (usb_ma_table[i].chg_iusb_value == temp)
697 *mA = usb_ma_table[i].usb_ma;
698 }
699 return rc;
700}
701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702#define PM8921_CHG_WD_MASK 0x1F
703static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
704{
705 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700706 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
707}
708
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700709#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700710#define PM8921_CHG_TCHG_MIN 4
711#define PM8921_CHG_TCHG_MAX 512
712#define PM8921_CHG_TCHG_STEP 4
713static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
714{
715 u8 temp;
716
717 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
718 pr_err("bad max minutes =%d asked to set\n", minutes);
719 return -EINVAL;
720 }
721
722 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
723 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
724 temp);
725}
726
727#define PM8921_CHG_TTRKL_MASK 0x1F
728#define PM8921_CHG_TTRKL_MIN 1
729#define PM8921_CHG_TTRKL_MAX 64
730static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
731{
732 u8 temp;
733
734 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
735 pr_err("bad max minutes =%d asked to set\n", minutes);
736 return -EINVAL;
737 }
738
739 temp = minutes - 1;
740 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
741 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742}
743
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700744#define PM8921_CHG_VTRKL_MIN_MV 2050
745#define PM8921_CHG_VTRKL_MAX_MV 2800
746#define PM8921_CHG_VTRKL_STEP_MV 50
747#define PM8921_CHG_VTRKL_SHIFT 4
748#define PM8921_CHG_VTRKL_MASK 0xF0
749static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
750{
751 u8 temp;
752
753 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
754 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
755 pr_err("bad voltage = %dmV asked to set\n", millivolts);
756 return -EINVAL;
757 }
758
759 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
760 temp = temp << PM8921_CHG_VTRKL_SHIFT;
761 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
762 temp);
763}
764
765#define PM8921_CHG_VWEAK_MIN_MV 2100
766#define PM8921_CHG_VWEAK_MAX_MV 3600
767#define PM8921_CHG_VWEAK_STEP_MV 100
768#define PM8921_CHG_VWEAK_MASK 0x0F
769static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
770{
771 u8 temp;
772
773 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
774 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
775 pr_err("bad voltage = %dmV asked to set\n", millivolts);
776 return -EINVAL;
777 }
778
779 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
780 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
781 temp);
782}
783
784#define PM8921_CHG_ITRKL_MIN_MA 50
785#define PM8921_CHG_ITRKL_MAX_MA 200
786#define PM8921_CHG_ITRKL_MASK 0x0F
787#define PM8921_CHG_ITRKL_STEP_MA 10
788static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
789{
790 u8 temp;
791
792 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
793 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
794 pr_err("bad current = %dmA asked to set\n", milliamps);
795 return -EINVAL;
796 }
797
798 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
799
800 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
801 temp);
802}
803
804#define PM8921_CHG_IWEAK_MIN_MA 325
805#define PM8921_CHG_IWEAK_MAX_MA 525
806#define PM8921_CHG_IWEAK_SHIFT 7
807#define PM8921_CHG_IWEAK_MASK 0x80
808static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
809{
810 u8 temp;
811
812 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
813 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
814 pr_err("bad current = %dmA asked to set\n", milliamps);
815 return -EINVAL;
816 }
817
818 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
819 temp = 0;
820 else
821 temp = 1;
822
823 temp = temp << PM8921_CHG_IWEAK_SHIFT;
824 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
825 temp);
826}
827
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700828#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
829#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
830static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
831 enum pm8921_chg_cold_thr cold_thr)
832{
833 u8 temp;
834
835 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
836 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
837 return pm_chg_masked_write(chip, CHG_CNTRL_2,
838 PM8921_CHG_BATT_TEMP_THR_COLD,
839 temp);
840}
841
842#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
843#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
844static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
845 enum pm8921_chg_hot_thr hot_thr)
846{
847 u8 temp;
848
849 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
850 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
851 return pm_chg_masked_write(chip, CHG_CNTRL_2,
852 PM8921_CHG_BATT_TEMP_THR_HOT,
853 temp);
854}
855
David Keitel8c5201a2012-02-24 16:08:54 -0800856static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
857{
858 u8 temp;
859 int rc;
860
861 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
862 if (rc) {
863 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
864 return;
865 }
866 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
867 if (rc) {
868 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
869 return;
870 }
871 /* set the input voltage disable bit and the write bit */
872 temp |= 0x81;
873 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
874 if (rc) {
875 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
876 return;
877 }
878}
879
880static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
881{
882 u8 temp;
883 int rc;
884
885 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
886 if (rc) {
887 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
888 return;
889 }
890 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
891 if (rc) {
892 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
893 return;
894 }
895 /* unset the input voltage disable bit */
896 temp &= 0xFE;
897 /* set the write bit */
898 temp |= 0x80;
899 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
900 if (rc) {
901 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
902 return;
903 }
904}
905
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700906static int64_t read_battery_id(struct pm8921_chg_chip *chip)
907{
908 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700909 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700910
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700911 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700912 if (rc) {
913 pr_err("error reading batt id channel = %d, rc = %d\n",
914 chip->vbat_channel, rc);
915 return rc;
916 }
917 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
918 result.measurement);
919 return result.physical;
920}
921
922static int is_battery_valid(struct pm8921_chg_chip *chip)
923{
924 int64_t rc;
925
926 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
927 return 1;
928
929 rc = read_battery_id(chip);
930 if (rc < 0) {
931 pr_err("error reading batt id channel = %d, rc = %lld\n",
932 chip->vbat_channel, rc);
933 /* assume battery id is valid when adc error happens */
934 return 1;
935 }
936
937 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
938 pr_err("batt_id phy =%lld is not valid\n", rc);
939 return 0;
940 }
941 return 1;
942}
943
944static void check_battery_valid(struct pm8921_chg_chip *chip)
945{
946 if (is_battery_valid(chip) == 0) {
947 pr_err("batt_id not valid, disbling charging\n");
948 pm_chg_auto_enable(chip, 0);
949 } else {
950 pm_chg_auto_enable(chip, !charging_disabled);
951 }
952}
953
954static void battery_id_valid(struct work_struct *work)
955{
956 struct pm8921_chg_chip *chip = container_of(work,
957 struct pm8921_chg_chip, battery_id_valid_work);
958
959 check_battery_valid(chip);
960}
961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
963{
964 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
965 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
966 enable_irq(chip->pmic_chg_irq[interrupt]);
967 }
968}
969
970static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
971{
972 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
973 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
974 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
975 }
976}
977
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800978static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
979{
980 return test_bit(interrupt, chip->enabled_irqs);
981}
982
Amir Samuelovd31ef502011-10-26 14:41:36 +0200983static bool is_ext_charging(struct pm8921_chg_chip *chip)
984{
David Keitel88e1b572012-01-11 11:57:14 -0800985 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200986
David Keitel88e1b572012-01-11 11:57:14 -0800987 if (!chip->ext_psy)
988 return false;
989 if (chip->ext_psy->get_property(chip->ext_psy,
990 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
991 return false;
992 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
993 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200994
995 return false;
996}
997
998static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
999{
David Keitel88e1b572012-01-11 11:57:14 -08001000 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001001
David Keitel88e1b572012-01-11 11:57:14 -08001002 if (!chip->ext_psy)
1003 return false;
1004 if (chip->ext_psy->get_property(chip->ext_psy,
1005 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1006 return false;
1007 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001008 return true;
1009
1010 return false;
1011}
1012
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013static int is_battery_charging(int fsm_state)
1014{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001015 if (is_ext_charging(the_chip))
1016 return 1;
1017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 switch (fsm_state) {
1019 case FSM_STATE_ATC_2A:
1020 case FSM_STATE_ATC_2B:
1021 case FSM_STATE_ON_CHG_AND_BAT_6:
1022 case FSM_STATE_FAST_CHG_7:
1023 case FSM_STATE_TRKL_CHG_8:
1024 return 1;
1025 }
1026 return 0;
1027}
1028
1029static void bms_notify(struct work_struct *work)
1030{
1031 struct bms_notify *n = container_of(work, struct bms_notify, work);
1032
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001033 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001035 } else {
1036 pm8921_bms_charging_end(n->is_battery_full);
1037 n->is_battery_full = 0;
1038 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039}
1040
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001041static void bms_notify_check(struct pm8921_chg_chip *chip)
1042{
1043 int fsm_state, new_is_charging;
1044
1045 fsm_state = pm_chg_get_fsm_state(chip);
1046 new_is_charging = is_battery_charging(fsm_state);
1047
1048 if (chip->bms_notify.is_charging ^ new_is_charging) {
1049 chip->bms_notify.is_charging = new_is_charging;
1050 schedule_work(&(chip->bms_notify.work));
1051 }
1052}
1053
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001054static enum power_supply_property pm_power_props_usb[] = {
1055 POWER_SUPPLY_PROP_PRESENT,
1056 POWER_SUPPLY_PROP_ONLINE,
1057 POWER_SUPPLY_PROP_CURRENT_MAX,
1058};
1059
1060static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001062 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063};
1064
1065static char *pm_power_supplied_to[] = {
1066 "battery",
1067};
1068
David Keitel6ed71a52012-01-30 12:42:18 -08001069#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001070static int pm_power_get_property_mains(struct power_supply *psy,
1071 enum power_supply_property psp,
1072 union power_supply_propval *val)
1073{
1074 int current_max;
1075
1076 /* Check if called before init */
1077 if (!the_chip)
1078 return -EINVAL;
1079
1080 switch (psp) {
1081 case POWER_SUPPLY_PROP_PRESENT:
1082 case POWER_SUPPLY_PROP_ONLINE:
1083 val->intval = 0;
1084 if (charging_disabled)
1085 return 0;
1086
1087 /* check external charger first before the dc path */
1088 if (is_ext_charging(the_chip)) {
1089 val->intval = 1;
1090 return 0;
1091 }
1092
1093 if (pm_is_chg_charge_dis(the_chip)) {
1094 val->intval = 0;
1095 return 0;
1096 }
1097
1098 if (the_chip->dc_present) {
1099 val->intval = 1;
1100 return 0;
1101 }
1102
1103 /* USB with max current greater than 500 mA connected */
1104 pm_chg_iusbmax_get(the_chip, &current_max);
1105 if (current_max > USB_WALL_THRESHOLD_MA)
1106 val->intval = is_usb_chg_plugged_in(the_chip);
1107 return 0;
1108
1109 break;
1110 default:
1111 return -EINVAL;
1112 }
1113 return 0;
1114}
1115
1116static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 enum power_supply_property psp,
1118 union power_supply_propval *val)
1119{
David Keitel6ed71a52012-01-30 12:42:18 -08001120 int current_max;
1121
1122 /* Check if called before init */
1123 if (!the_chip)
1124 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125
1126 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001127 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001128 if (pm_is_chg_charge_dis(the_chip)) {
1129 val->intval = 0;
1130 } else {
1131 pm_chg_iusbmax_get(the_chip, &current_max);
1132 val->intval = current_max;
1133 }
David Keitel6ed71a52012-01-30 12:42:18 -08001134 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001136 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001137 val->intval = 0;
1138 if (charging_disabled)
1139 return 0;
1140
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001141 /*
1142 * if drawing any current from usb is disabled behave
1143 * as if no usb cable is connected
1144 */
1145 if (pm_is_chg_charge_dis(the_chip))
1146 return 0;
1147
David Keitel63f71662012-02-08 20:30:00 -08001148 /* USB charging */
David Keitel70f6cdc22012-03-15 15:33:26 -07001149 val->intval = is_usb_chg_plugged_in(the_chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150 break;
1151 default:
1152 return -EINVAL;
1153 }
1154 return 0;
1155}
1156
1157static enum power_supply_property msm_batt_power_props[] = {
1158 POWER_SUPPLY_PROP_STATUS,
1159 POWER_SUPPLY_PROP_CHARGE_TYPE,
1160 POWER_SUPPLY_PROP_HEALTH,
1161 POWER_SUPPLY_PROP_PRESENT,
1162 POWER_SUPPLY_PROP_TECHNOLOGY,
1163 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1164 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1165 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1166 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001167 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001168 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001169 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170};
1171
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001172static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173{
1174 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001175 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001177 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 if (rc) {
1179 pr_err("error reading adc channel = %d, rc = %d\n",
1180 chip->vbat_channel, rc);
1181 return rc;
1182 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001183 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 result.measurement);
1185 return (int)result.physical;
1186}
1187
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001188static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1189{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001190 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1191 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1192 unsigned int low_voltage = chip->min_voltage_mv;
1193 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001194
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001195 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001196 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001197 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001198 return 100;
1199 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001200 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001201 / (high_voltage - low_voltage);
1202}
1203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1205{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001206 int percent_soc = pm8921_bms_get_percent_charge();
1207
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001208 if (percent_soc == -ENXIO)
1209 percent_soc = voltage_based_capacity(chip);
1210
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001211 if (percent_soc <= 10)
1212 pr_warn("low battery charge = %d%%\n", percent_soc);
1213
1214 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215}
1216
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001217static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1218{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001219 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001220
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001221 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001222 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001223 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001224 }
1225
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001226 if (rc) {
1227 pr_err("unable to get batt current rc = %d\n", rc);
1228 return rc;
1229 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001230 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001231 }
1232}
1233
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001234static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1235{
1236 int rc;
1237
1238 rc = pm8921_bms_get_fcc();
1239 if (rc < 0)
1240 pr_err("unable to get batt fcc rc = %d\n", rc);
1241 return rc;
1242}
1243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1245{
1246 int temp;
1247
1248 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1249 if (temp)
1250 return POWER_SUPPLY_HEALTH_OVERHEAT;
1251
1252 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1253 if (temp)
1254 return POWER_SUPPLY_HEALTH_COLD;
1255
1256 return POWER_SUPPLY_HEALTH_GOOD;
1257}
1258
1259static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1260{
1261 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1262}
1263
1264static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1265{
1266 int temp;
1267
Amir Samuelovd31ef502011-10-26 14:41:36 +02001268 if (!get_prop_batt_present(chip))
1269 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1270
1271 if (is_ext_trickle_charging(chip))
1272 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1273
1274 if (is_ext_charging(chip))
1275 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1278 if (temp)
1279 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1280
1281 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1282 if (temp)
1283 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1284
1285 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1286}
1287
1288static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1289{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001290 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1291 int fsm_state = pm_chg_get_fsm_state(chip);
1292 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293
David Keitel88e1b572012-01-11 11:57:14 -08001294 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001295 if (chip->ext_charge_done)
1296 return POWER_SUPPLY_STATUS_FULL;
1297 if (chip->ext_charging)
1298 return POWER_SUPPLY_STATUS_CHARGING;
1299 }
1300
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001301 for (i = 0; i < ARRAY_SIZE(map); i++)
1302 if (map[i].fsm_state == fsm_state)
1303 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001304
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001305 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1306 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1307 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001308 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1309 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001310
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001311 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001312 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001313 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314}
1315
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001316#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001317static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1318{
1319 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001320 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001321
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001322 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001323 if (rc) {
1324 pr_err("error reading adc channel = %d, rc = %d\n",
1325 chip->vbat_channel, rc);
1326 return rc;
1327 }
1328 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1329 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001330 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1331 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1332 (int) result.physical);
1333
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001334 return (int)result.physical;
1335}
1336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337static int pm_batt_power_get_property(struct power_supply *psy,
1338 enum power_supply_property psp,
1339 union power_supply_propval *val)
1340{
1341 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1342 batt_psy);
1343
1344 switch (psp) {
1345 case POWER_SUPPLY_PROP_STATUS:
1346 val->intval = get_prop_batt_status(chip);
1347 break;
1348 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1349 val->intval = get_prop_charge_type(chip);
1350 break;
1351 case POWER_SUPPLY_PROP_HEALTH:
1352 val->intval = get_prop_batt_health(chip);
1353 break;
1354 case POWER_SUPPLY_PROP_PRESENT:
1355 val->intval = get_prop_batt_present(chip);
1356 break;
1357 case POWER_SUPPLY_PROP_TECHNOLOGY:
1358 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1359 break;
1360 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001361 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 break;
1363 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001364 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365 break;
1366 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001367 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 break;
1369 case POWER_SUPPLY_PROP_CAPACITY:
1370 val->intval = get_prop_batt_capacity(chip);
1371 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001372 case POWER_SUPPLY_PROP_CURRENT_NOW:
1373 val->intval = get_prop_batt_current(chip);
1374 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001375 case POWER_SUPPLY_PROP_TEMP:
1376 val->intval = get_prop_batt_temp(chip);
1377 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001378 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001379 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001380 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001381 default:
1382 return -EINVAL;
1383 }
1384
1385 return 0;
1386}
1387
1388static void (*notify_vbus_state_func_ptr)(int);
1389static int usb_chg_current;
1390static DEFINE_SPINLOCK(vbus_lock);
1391
1392int pm8921_charger_register_vbus_sn(void (*callback)(int))
1393{
1394 pr_debug("%p\n", callback);
1395 notify_vbus_state_func_ptr = callback;
1396 return 0;
1397}
1398EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1399
1400/* this is passed to the hsusb via platform_data msm_otg_pdata */
1401void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1402{
1403 pr_debug("%p\n", callback);
1404 notify_vbus_state_func_ptr = NULL;
1405}
1406EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1407
1408static void notify_usb_of_the_plugin_event(int plugin)
1409{
1410 plugin = !!plugin;
1411 if (notify_vbus_state_func_ptr) {
1412 pr_debug("notifying plugin\n");
1413 (*notify_vbus_state_func_ptr) (plugin);
1414 } else {
1415 pr_debug("unable to notify plugin\n");
1416 }
1417}
1418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419/* assumes vbus_lock is held */
1420static void __pm8921_charger_vbus_draw(unsigned int mA)
1421{
1422 int i, rc;
1423
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001424 if (usb_max_current && mA > usb_max_current) {
1425 pr_warn("restricting usb current to %d instead of %d\n",
1426 usb_max_current, mA);
1427 mA = usb_max_current;
1428 }
1429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 if (mA > 0 && mA <= 2) {
1431 usb_chg_current = 0;
1432 rc = pm_chg_iusbmax_set(the_chip,
1433 usb_ma_table[0].chg_iusb_value);
1434 if (rc) {
1435 pr_err("unable to set iusb to %d rc = %d\n",
1436 usb_ma_table[0].chg_iusb_value, rc);
1437 }
1438 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1439 if (rc)
1440 pr_err("fail to set suspend bit rc=%d\n", rc);
1441 } else {
1442 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1443 if (rc)
1444 pr_err("fail to reset suspend bit rc=%d\n", rc);
1445 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1446 if (usb_ma_table[i].usb_ma <= mA)
1447 break;
1448 }
1449 if (i < 0)
1450 i = 0;
1451 rc = pm_chg_iusbmax_set(the_chip,
1452 usb_ma_table[i].chg_iusb_value);
1453 if (rc) {
1454 pr_err("unable to set iusb to %d rc = %d\n",
1455 usb_ma_table[i].chg_iusb_value, rc);
1456 }
1457 }
1458}
1459
1460/* USB calls these to tell us how much max usb current the system can draw */
1461void pm8921_charger_vbus_draw(unsigned int mA)
1462{
1463 unsigned long flags;
1464
1465 pr_debug("Enter charge=%d\n", mA);
1466 spin_lock_irqsave(&vbus_lock, flags);
1467 if (the_chip) {
1468 __pm8921_charger_vbus_draw(mA);
1469 } else {
1470 /*
1471 * called before pmic initialized,
1472 * save this value and use it at probe
1473 */
1474 usb_chg_current = mA;
1475 }
1476 spin_unlock_irqrestore(&vbus_lock, flags);
1477}
1478EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1479
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001480int pm8921_charger_enable(bool enable)
1481{
1482 int rc;
1483
1484 if (!the_chip) {
1485 pr_err("called before init\n");
1486 return -EINVAL;
1487 }
1488 enable = !!enable;
1489 rc = pm_chg_auto_enable(the_chip, enable);
1490 if (rc)
1491 pr_err("Failed rc=%d\n", rc);
1492 return rc;
1493}
1494EXPORT_SYMBOL(pm8921_charger_enable);
1495
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001496int pm8921_is_usb_chg_plugged_in(void)
1497{
1498 if (!the_chip) {
1499 pr_err("called before init\n");
1500 return -EINVAL;
1501 }
1502 return is_usb_chg_plugged_in(the_chip);
1503}
1504EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1505
1506int pm8921_is_dc_chg_plugged_in(void)
1507{
1508 if (!the_chip) {
1509 pr_err("called before init\n");
1510 return -EINVAL;
1511 }
1512 return is_dc_chg_plugged_in(the_chip);
1513}
1514EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1515
1516int pm8921_is_battery_present(void)
1517{
1518 if (!the_chip) {
1519 pr_err("called before init\n");
1520 return -EINVAL;
1521 }
1522 return get_prop_batt_present(the_chip);
1523}
1524EXPORT_SYMBOL(pm8921_is_battery_present);
1525
David Keitel012deef2011-12-02 11:49:33 -08001526/*
1527 * Disabling the charge current limit causes current
1528 * current limits to have no monitoring. An adequate charger
1529 * capable of supplying high current while sustaining VIN_MIN
1530 * is required if the limiting is disabled.
1531 */
1532int pm8921_disable_input_current_limit(bool disable)
1533{
1534 if (!the_chip) {
1535 pr_err("called before init\n");
1536 return -EINVAL;
1537 }
1538 if (disable) {
1539 pr_warn("Disabling input current limit!\n");
1540
1541 return pm8xxx_writeb(the_chip->dev->parent,
1542 CHG_BUCK_CTRL_TEST3, 0xF2);
1543 }
1544 return 0;
1545}
1546EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1547
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001548int pm8921_set_max_battery_charge_current(int ma)
1549{
1550 if (!the_chip) {
1551 pr_err("called before init\n");
1552 return -EINVAL;
1553 }
1554 return pm_chg_ibatmax_set(the_chip, ma);
1555}
1556EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1557
1558int pm8921_disable_source_current(bool disable)
1559{
1560 if (!the_chip) {
1561 pr_err("called before init\n");
1562 return -EINVAL;
1563 }
1564 if (disable)
1565 pr_warn("current drawn from chg=0, battery provides current\n");
1566 return pm_chg_charge_dis(the_chip, disable);
1567}
1568EXPORT_SYMBOL(pm8921_disable_source_current);
1569
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001570int pm8921_regulate_input_voltage(int voltage)
1571{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001572 int rc;
1573
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001574 if (!the_chip) {
1575 pr_err("called before init\n");
1576 return -EINVAL;
1577 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001578 rc = pm_chg_vinmin_set(the_chip, voltage);
1579
1580 if (rc == 0)
1581 the_chip->vin_min = voltage;
1582
1583 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001584}
1585
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001586#define USB_OV_THRESHOLD_MASK 0x60
1587#define USB_OV_THRESHOLD_SHIFT 5
1588int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1589{
1590 u8 temp;
1591
1592 if (!the_chip) {
1593 pr_err("called before init\n");
1594 return -EINVAL;
1595 }
1596
1597 if (ov > PM_USB_OV_7V) {
1598 pr_err("limiting to over voltage threshold to 7volts\n");
1599 ov = PM_USB_OV_7V;
1600 }
1601
1602 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1603
1604 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1605 USB_OV_THRESHOLD_MASK, temp);
1606}
1607EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1608
1609#define USB_DEBOUNCE_TIME_MASK 0x06
1610#define USB_DEBOUNCE_TIME_SHIFT 1
1611int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1612{
1613 u8 temp;
1614
1615 if (!the_chip) {
1616 pr_err("called before init\n");
1617 return -EINVAL;
1618 }
1619
1620 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1621 pr_err("limiting debounce to 80.5ms\n");
1622 ms = PM_USB_DEBOUNCE_80P5MS;
1623 }
1624
1625 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1626
1627 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1628 USB_DEBOUNCE_TIME_MASK, temp);
1629}
1630EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1631
1632#define USB_OVP_DISABLE_MASK 0x80
1633int pm8921_usb_ovp_disable(int disable)
1634{
1635 u8 temp = 0;
1636
1637 if (!the_chip) {
1638 pr_err("called before init\n");
1639 return -EINVAL;
1640 }
1641
1642 if (disable)
1643 temp = USB_OVP_DISABLE_MASK;
1644
1645 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1646 USB_OVP_DISABLE_MASK, temp);
1647}
1648
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001649bool pm8921_is_battery_charging(int *source)
1650{
1651 int fsm_state, is_charging, dc_present, usb_present;
1652
1653 if (!the_chip) {
1654 pr_err("called before init\n");
1655 return -EINVAL;
1656 }
1657 fsm_state = pm_chg_get_fsm_state(the_chip);
1658 is_charging = is_battery_charging(fsm_state);
1659 if (is_charging == 0) {
1660 *source = PM8921_CHG_SRC_NONE;
1661 return is_charging;
1662 }
1663
1664 if (source == NULL)
1665 return is_charging;
1666
1667 /* the battery is charging, the source is requested, find it */
1668 dc_present = is_dc_chg_plugged_in(the_chip);
1669 usb_present = is_usb_chg_plugged_in(the_chip);
1670
1671 if (dc_present && !usb_present)
1672 *source = PM8921_CHG_SRC_DC;
1673
1674 if (usb_present && !dc_present)
1675 *source = PM8921_CHG_SRC_USB;
1676
1677 if (usb_present && dc_present)
1678 /*
1679 * The system always chooses dc for charging since it has
1680 * higher priority.
1681 */
1682 *source = PM8921_CHG_SRC_DC;
1683
1684 return is_charging;
1685}
1686EXPORT_SYMBOL(pm8921_is_battery_charging);
1687
1688int pm8921_batt_temperature(void)
1689{
1690 if (!the_chip) {
1691 pr_err("called before init\n");
1692 return -EINVAL;
1693 }
1694 return get_prop_batt_temp(the_chip);
1695}
1696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1698{
1699 int usb_present;
1700
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001701 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 usb_present = is_usb_chg_plugged_in(chip);
1703 if (chip->usb_present ^ usb_present) {
1704 notify_usb_of_the_plugin_event(usb_present);
1705 chip->usb_present = usb_present;
1706 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001707 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001708 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001710 if (usb_present) {
1711 schedule_delayed_work(&chip->unplug_check_work,
1712 round_jiffies_relative(msecs_to_jiffies
1713 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001714 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1715 } else {
1716 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001717 }
David Keitel8c5201a2012-02-24 16:08:54 -08001718 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001719 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720}
1721
Amir Samuelovd31ef502011-10-26 14:41:36 +02001722static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1723{
David Keitel88e1b572012-01-11 11:57:14 -08001724 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001725 pr_debug("external charger not registered.\n");
1726 return;
1727 }
1728
1729 if (!chip->ext_charging) {
1730 pr_debug("already not charging.\n");
1731 return;
1732 }
1733
David Keitel88e1b572012-01-11 11:57:14 -08001734 power_supply_set_charge_type(chip->ext_psy,
1735 POWER_SUPPLY_CHARGE_TYPE_NONE);
1736 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001737 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001738 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001739 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001740 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001741}
1742
1743static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1744{
1745 int dc_present;
1746 int batt_present;
1747 int batt_temp_ok;
1748 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001749 unsigned long delay =
1750 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1751
David Keitel88e1b572012-01-11 11:57:14 -08001752 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001753 pr_debug("external charger not registered.\n");
1754 return;
1755 }
1756
1757 if (chip->ext_charging) {
1758 pr_debug("already charging.\n");
1759 return;
1760 }
1761
David Keitel88e1b572012-01-11 11:57:14 -08001762 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001763 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1764 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001765
1766 if (!dc_present) {
1767 pr_warn("%s. dc not present.\n", __func__);
1768 return;
1769 }
1770 if (!batt_present) {
1771 pr_warn("%s. battery not present.\n", __func__);
1772 return;
1773 }
1774 if (!batt_temp_ok) {
1775 pr_warn("%s. battery temperature not ok.\n", __func__);
1776 return;
1777 }
David Keitel88e1b572012-01-11 11:57:14 -08001778 pm8921_disable_source_current(true); /* Force BATFET=ON */
1779 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001780 if (vbat_ov) {
1781 pr_warn("%s. battery over voltage.\n", __func__);
1782 return;
1783 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001784
David Keitel63f71662012-02-08 20:30:00 -08001785 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001786 power_supply_set_charge_type(chip->ext_psy,
1787 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001788 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001789 chip->ext_charging = true;
1790 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001791 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001792 /* Start BMS */
1793 schedule_delayed_work(&chip->eoc_work, delay);
1794 wake_lock(&chip->eoc_wake_lock);
1795}
1796
David Keitel8c5201a2012-02-24 16:08:54 -08001797static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001798{
1799 u8 temp;
1800 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001801
David Keitel8c5201a2012-02-24 16:08:54 -08001802 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001803 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001804 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1805 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001806 }
David Keitel8c5201a2012-02-24 16:08:54 -08001807 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1808 if (rc) {
1809 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1810 return;
1811 }
1812 /* set ovp fet disable bit and the write bit */
1813 temp |= 0x81;
1814 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1815 if (rc) {
1816 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1817 return;
1818 }
1819}
1820
1821static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1822{
1823 u8 temp;
1824 int rc;
1825
1826 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1827 if (rc) {
1828 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1829 return;
1830 }
1831 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1832 if (rc) {
1833 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1834 return;
1835 }
1836 /* unset ovp fet disable bit and set the write bit */
1837 temp &= 0xFE;
1838 temp |= 0x80;
1839 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1840 if (rc) {
1841 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1842 temp, rc);
1843 return;
1844 }
1845}
1846
1847static int param_open_ovp_counter = 10;
1848module_param(param_open_ovp_counter, int, 0644);
1849
1850#define WRITE_BANK_4 0xC0
1851#define USB_OVP_DEBOUNCE_TIME 0x06
1852static void unplug_ovp_fet_open_worker(struct work_struct *work)
1853{
1854 struct pm8921_chg_chip *chip = container_of(work,
1855 struct pm8921_chg_chip,
1856 unplug_ovp_fet_open_work);
1857 int chg_gone, usb_chg_plugged_in;
1858 int count = 0;
1859
1860 while (count++ < param_open_ovp_counter) {
1861 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1862 USB_OVP_DEBOUNCE_TIME, 0x0);
1863 usleep(10);
1864 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1865 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1866 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1867 count, chg_gone, usb_chg_plugged_in);
1868
1869 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1870 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1871 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1872 turn_off_usb_ovp_fet(chip);
1873
1874 msleep(20);
1875
1876 turn_on_usb_ovp_fet(chip);
1877 } else {
1878 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1879 USB_OVP_DEBOUNCE_TIME, 0x1);
1880 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1881 count, chg_gone, usb_chg_plugged_in);
1882 return;
1883 }
1884 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001885}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1887{
1888 handle_usb_insertion_removal(data);
1889 return IRQ_HANDLED;
1890}
1891
1892static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1893{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001894 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001895 return IRQ_HANDLED;
1896}
1897
1898static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1899{
1900 struct pm8921_chg_chip *chip = data;
1901 int status;
1902
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001903 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1904 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001905 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 pr_debug("battery present=%d", status);
1907 power_supply_changed(&chip->batt_psy);
1908 return IRQ_HANDLED;
1909}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001910
1911/*
1912 * this interrupt used to restart charging a battery.
1913 *
1914 * Note: When DC-inserted the VBAT can't go low.
1915 * VPH_PWR is provided by the ext-charger.
1916 * After End-Of-Charging from DC, charging can be resumed only
1917 * if DC is removed and then inserted after the battery was in use.
1918 * Therefore the handle_start_ext_chg() is not called.
1919 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1921{
1922 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001923 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001925 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001926
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001927 if (high_transition) {
1928 /* enable auto charging */
1929 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001930 pr_info("batt fell below resume voltage %s\n",
1931 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001932 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001933 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 power_supply_changed(&chip->batt_psy);
1936 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001937 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001939 return IRQ_HANDLED;
1940}
1941
1942static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1943{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001944 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001945 return IRQ_HANDLED;
1946}
1947
1948static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1949{
1950 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1951 return IRQ_HANDLED;
1952}
1953
1954static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1955{
1956 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1957 return IRQ_HANDLED;
1958}
1959
1960static irqreturn_t vcp_irq_handler(int irq, void *data)
1961{
David Keitel8c5201a2012-02-24 16:08:54 -08001962 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 return IRQ_HANDLED;
1964}
1965
1966static irqreturn_t atcdone_irq_handler(int irq, void *data)
1967{
1968 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1969 return IRQ_HANDLED;
1970}
1971
1972static irqreturn_t atcfail_irq_handler(int irq, void *data)
1973{
1974 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1975 return IRQ_HANDLED;
1976}
1977
1978static irqreturn_t chgdone_irq_handler(int irq, void *data)
1979{
1980 struct pm8921_chg_chip *chip = data;
1981
1982 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001983
1984 handle_stop_ext_chg(chip);
1985
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 power_supply_changed(&chip->batt_psy);
1987 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001988 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001989
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001990 bms_notify_check(chip);
1991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992 return IRQ_HANDLED;
1993}
1994
1995static irqreturn_t chgfail_irq_handler(int irq, void *data)
1996{
1997 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001998 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999
David Keitel753ec8d2011-11-02 10:56:37 -07002000 ret = pm_chg_failed_clear(chip, 1);
2001 if (ret)
2002 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2003
2004 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2005 get_prop_batt_present(chip),
2006 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2007 pm_chg_get_fsm_state(data));
2008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 power_supply_changed(&chip->batt_psy);
2010 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002011 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 return IRQ_HANDLED;
2013}
2014
2015static irqreturn_t chgstate_irq_handler(int irq, void *data)
2016{
2017 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018
2019 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2020 power_supply_changed(&chip->batt_psy);
2021 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002022 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002024 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 return IRQ_HANDLED;
2027}
2028
David Keitel8c5201a2012-02-24 16:08:54 -08002029static int param_vin_disable_counter = 5;
2030module_param(param_vin_disable_counter, int, 0644);
2031
2032static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2033 int count, int usb_ma)
2034{
2035 pm8921_charger_vbus_draw(500);
2036 pr_debug("count = %d iusb=500mA\n", count);
2037 disable_input_voltage_regulation(chip);
2038 pr_debug("count = %d disable_input_regulation\n", count);
2039
2040 msleep(20);
2041
2042 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2043 count,
2044 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2045 is_usb_chg_plugged_in(chip));
2046 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2047 count, usb_ma);
2048 enable_input_voltage_regulation(chip);
2049 pm8921_charger_vbus_draw(usb_ma);
2050}
2051
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002052#define VIN_ACTIVE_BIT BIT(0)
2053#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2054#define VIN_MIN_INCREASE_MV 100
2055static void unplug_check_worker(struct work_struct *work)
2056{
2057 struct delayed_work *dwork = to_delayed_work(work);
2058 struct pm8921_chg_chip *chip = container_of(dwork,
2059 struct pm8921_chg_chip, unplug_check_work);
2060 u8 reg_loop;
2061 int ibat, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002062 int usb_ma;
2063 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002064
2065 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2066 if (!usb_chg_plugged_in) {
2067 pr_debug("Stopping Unplug Check Worker since USB is removed"
2068 "reg_loop = %d, fsm = %d ibat = %d\n",
2069 pm_chg_get_regulation_loop(chip),
2070 pm_chg_get_fsm_state(chip),
2071 get_prop_batt_current(chip)
2072 );
2073 return;
2074 }
David Keitel8c5201a2012-02-24 16:08:54 -08002075
2076 pm_chg_iusbmax_get(chip, &usb_ma);
2077 if (usb_ma == 500) {
2078 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2079 disable_input_voltage_regulation(chip);
2080 return;
2081 }
2082
2083 if (usb_ma <= 100) {
2084 pr_debug(
2085 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2086 usb_ma);
2087 goto check_again_later;
2088 }
2089 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2090 pr_debug("chg gone irq is enabled\n");
2091
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002092 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002093 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002094
2095 if (reg_loop & VIN_ACTIVE_BIT) {
2096 ibat = get_prop_batt_current(chip);
2097
2098 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2099 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2100 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002101 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002102
David Keitel8c5201a2012-02-24 16:08:54 -08002103 while (count++ < param_vin_disable_counter
2104 && usb_chg_plugged_in == 1) {
2105 attempt_reverse_boost_fix(chip, count, usb_ma);
2106 usb_chg_plugged_in
2107 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002108 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002109 }
2110 }
2111
David Keitel8c5201a2012-02-24 16:08:54 -08002112 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2113 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2114
2115 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2116 /* run the worker directly */
2117 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2118 chg_gone, usb_chg_plugged_in);
2119 schedule_work(&chip->unplug_ovp_fet_open_work);
2120 }
2121
2122check_again_later:
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002123 schedule_delayed_work(&chip->unplug_check_work,
2124 round_jiffies_relative(msecs_to_jiffies
2125 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2126}
2127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128static irqreturn_t loop_change_irq_handler(int irq, void *data)
2129{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002130 struct pm8921_chg_chip *chip = data;
2131
2132 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2133 pm_chg_get_fsm_state(data),
2134 pm_chg_get_regulation_loop(data));
2135 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 return IRQ_HANDLED;
2137}
2138
2139static irqreturn_t fastchg_irq_handler(int irq, void *data)
2140{
2141 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002142 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002144 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2145 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2146 wake_lock(&chip->eoc_wake_lock);
2147 schedule_delayed_work(&chip->eoc_work,
2148 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002149 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002150 }
2151 power_supply_changed(&chip->batt_psy);
2152 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 return IRQ_HANDLED;
2154}
2155
2156static irqreturn_t trklchg_irq_handler(int irq, void *data)
2157{
2158 struct pm8921_chg_chip *chip = data;
2159
2160 power_supply_changed(&chip->batt_psy);
2161 return IRQ_HANDLED;
2162}
2163
2164static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2165{
2166 struct pm8921_chg_chip *chip = data;
2167 int status;
2168
2169 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2170 pr_debug("battery present=%d state=%d", !status,
2171 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002172 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 power_supply_changed(&chip->batt_psy);
2174 return IRQ_HANDLED;
2175}
2176
2177static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2178{
2179 struct pm8921_chg_chip *chip = data;
2180
Amir Samuelovd31ef502011-10-26 14:41:36 +02002181 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182 power_supply_changed(&chip->batt_psy);
2183 return IRQ_HANDLED;
2184}
2185
2186static irqreturn_t chghot_irq_handler(int irq, void *data)
2187{
2188 struct pm8921_chg_chip *chip = data;
2189
2190 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2191 power_supply_changed(&chip->batt_psy);
2192 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002193 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 return IRQ_HANDLED;
2195}
2196
2197static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2198{
2199 struct pm8921_chg_chip *chip = data;
2200
2201 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002202 handle_stop_ext_chg(chip);
2203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 power_supply_changed(&chip->batt_psy);
2205 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002206 return IRQ_HANDLED;
2207}
2208
2209static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2210{
2211 struct pm8921_chg_chip *chip = data;
David Keitel8c5201a2012-02-24 16:08:54 -08002212 int chg_gone, usb_chg_plugged_in;
2213
2214 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2215 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2216
2217 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2218 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219
2220 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2221 power_supply_changed(&chip->batt_psy);
2222 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 return IRQ_HANDLED;
2224}
David Keitel52fda532011-11-10 10:43:44 -08002225/*
2226 *
2227 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2228 * fire for two cases:
2229 *
2230 * If the interrupt line switches to high temperature is okay
2231 * and thus charging begins.
2232 * If bat_temp_ok is low this means the temperature is now
2233 * too hot or cold, so charging is stopped.
2234 *
2235 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2237{
David Keitel52fda532011-11-10 10:43:44 -08002238 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 struct pm8921_chg_chip *chip = data;
2240
David Keitel52fda532011-11-10 10:43:44 -08002241 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2242
2243 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2244 bat_temp_ok, pm_chg_get_fsm_state(data));
2245
2246 if (bat_temp_ok)
2247 handle_start_ext_chg(chip);
2248 else
2249 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 power_supply_changed(&chip->batt_psy);
2252 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002253 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 return IRQ_HANDLED;
2255}
2256
2257static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2258{
2259 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2260 return IRQ_HANDLED;
2261}
2262
2263static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2264{
2265 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2266 return IRQ_HANDLED;
2267}
2268
2269static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2270{
2271 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2272 return IRQ_HANDLED;
2273}
2274
2275static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2276{
2277 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2278 return IRQ_HANDLED;
2279}
2280
2281static irqreturn_t batfet_irq_handler(int irq, void *data)
2282{
2283 struct pm8921_chg_chip *chip = data;
2284
2285 pr_debug("vreg ov\n");
2286 power_supply_changed(&chip->batt_psy);
2287 return IRQ_HANDLED;
2288}
2289
2290static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2291{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002292 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002293 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002294
David Keitel88e1b572012-01-11 11:57:14 -08002295 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2296 if (chip->ext_psy)
2297 power_supply_set_online(chip->ext_psy, dc_present);
2298 chip->dc_present = dc_present;
2299 if (dc_present)
2300 handle_start_ext_chg(chip);
2301 else
2302 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 return IRQ_HANDLED;
2304}
2305
2306static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2307{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002308 struct pm8921_chg_chip *chip = data;
2309
Amir Samuelovd31ef502011-10-26 14:41:36 +02002310 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 return IRQ_HANDLED;
2312}
2313
2314static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2315{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002316 struct pm8921_chg_chip *chip = data;
2317
Amir Samuelovd31ef502011-10-26 14:41:36 +02002318 handle_stop_ext_chg(chip);
2319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 return IRQ_HANDLED;
2321}
2322
David Keitel88e1b572012-01-11 11:57:14 -08002323static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2324{
2325 struct power_supply *psy = &the_chip->batt_psy;
2326 struct power_supply *epsy = dev_get_drvdata(dev);
2327 int i, dcin_irq;
2328
2329 /* Only search for external supply if none is registered */
2330 if (!the_chip->ext_psy) {
2331 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2332 for (i = 0; i < epsy->num_supplicants; i++) {
2333 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2334 if (!strncmp(epsy->name, "dc", 2)) {
2335 the_chip->ext_psy = epsy;
2336 dcin_valid_irq_handler(dcin_irq,
2337 the_chip);
2338 }
2339 }
2340 }
2341 }
2342 return 0;
2343}
2344
2345static void pm_batt_external_power_changed(struct power_supply *psy)
2346{
2347 /* Only look for an external supply if it hasn't been registered */
2348 if (!the_chip->ext_psy)
2349 class_for_each_device(power_supply_class, NULL, psy,
2350 __pm_batt_external_power_changed_work);
2351}
2352
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002353/**
2354 * update_heartbeat - internal function to update userspace
2355 * per update_time minutes
2356 *
2357 */
2358static void update_heartbeat(struct work_struct *work)
2359{
2360 struct delayed_work *dwork = to_delayed_work(work);
2361 struct pm8921_chg_chip *chip = container_of(dwork,
2362 struct pm8921_chg_chip, update_heartbeat_work);
2363
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002364 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002365 power_supply_changed(&chip->batt_psy);
2366 schedule_delayed_work(&chip->update_heartbeat_work,
2367 round_jiffies_relative(msecs_to_jiffies
2368 (chip->update_time)));
2369}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002370#define VDD_LOOP_ACTIVE_BIT BIT(3)
2371#define VDD_MAX_INCREASE_MV 400
2372static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2373module_param(vdd_max_increase_mv, int, 0644);
2374
2375static int ichg_threshold_ua = -400000;
2376module_param(ichg_threshold_ua, int, 0644);
2377static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2378{
2379 int ichg_meas_ua, vbat_uv;
2380 int ichg_meas_ma;
2381 int adj_vdd_max_mv, programmed_vdd_max;
2382 int vbat_batt_terminal_uv;
2383 int vbat_batt_terminal_mv;
2384 int reg_loop;
2385 int delta_mv = 0;
2386
2387 if (chip->rconn_mohm == 0) {
2388 pr_debug("Exiting as rconn_mohm is 0\n");
2389 return;
2390 }
2391 /* adjust vdd_max only in normal temperature zone */
2392 if (chip->is_bat_cool || chip->is_bat_warm) {
2393 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2394 chip->is_bat_cool, chip->is_bat_warm);
2395 return;
2396 }
2397
2398 reg_loop = pm_chg_get_regulation_loop(chip);
2399 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2400 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2401 reg_loop);
2402 return;
2403 }
2404
2405 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2406 &vbat_uv);
2407 if (ichg_meas_ua >= 0) {
2408 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2409 return;
2410 }
2411 if (ichg_meas_ua <= ichg_threshold_ua) {
2412 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2413 ichg_meas_ua, ichg_threshold_ua);
2414 return;
2415 }
2416 ichg_meas_ma = ichg_meas_ua / 1000;
2417
2418 /* rconn_mohm is in milliOhms */
2419 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2420 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2421 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2422
2423 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2424
2425 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2426 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2427 delta_mv,
2428 programmed_vdd_max,
2429 adj_vdd_max_mv);
2430
2431 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2432 pr_debug("adj vdd_max lower than default max voltage\n");
2433 return;
2434 }
2435
2436 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2437 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2438
2439 pr_debug("adjusting vdd_max_mv to %d to make "
2440 "vbat_batt_termial_uv = %d to %d\n",
2441 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2442 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2443}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002444
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002445enum {
2446 CHG_IN_PROGRESS,
2447 CHG_NOT_IN_PROGRESS,
2448 CHG_FINISHED,
2449};
2450
2451#define VBAT_TOLERANCE_MV 70
2452#define CHG_DISABLE_MSLEEP 100
2453static int is_charging_finished(struct pm8921_chg_chip *chip)
2454{
2455 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2456 int ichg_meas_ma, iterm_programmed;
2457 int regulation_loop, fast_chg, vcp;
2458 int rc;
2459 static int last_vbat_programmed = -EINVAL;
2460
2461 if (!is_ext_charging(chip)) {
2462 /* return if the battery is not being fastcharged */
2463 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2464 pr_debug("fast_chg = %d\n", fast_chg);
2465 if (fast_chg == 0)
2466 return CHG_NOT_IN_PROGRESS;
2467
2468 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2469 pr_debug("vcp = %d\n", vcp);
2470 if (vcp == 1)
2471 return CHG_IN_PROGRESS;
2472
2473 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2474 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2475 if (vbatdet_low == 1)
2476 return CHG_IN_PROGRESS;
2477
2478 /* reset count if battery is hot/cold */
2479 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2480 pr_debug("batt_temp_ok = %d\n", rc);
2481 if (rc == 0)
2482 return CHG_IN_PROGRESS;
2483
2484 /* reset count if battery voltage is less than vddmax */
2485 vbat_meas_uv = get_prop_battery_uvolts(chip);
2486 if (vbat_meas_uv < 0)
2487 return CHG_IN_PROGRESS;
2488 vbat_meas_mv = vbat_meas_uv / 1000;
2489
2490 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2491 if (rc) {
2492 pr_err("couldnt read vddmax rc = %d\n", rc);
2493 return CHG_IN_PROGRESS;
2494 }
2495 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2496 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002497
2498 if (last_vbat_programmed == -EINVAL)
2499 last_vbat_programmed = vbat_programmed;
2500 if (last_vbat_programmed != vbat_programmed) {
2501 /* vddmax changed, reset and check again */
2502 pr_debug("vddmax = %d last_vdd_max=%d\n",
2503 vbat_programmed, last_vbat_programmed);
2504 last_vbat_programmed = vbat_programmed;
2505 return CHG_IN_PROGRESS;
2506 }
2507
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002508 regulation_loop = pm_chg_get_regulation_loop(chip);
2509 if (regulation_loop < 0) {
2510 pr_err("couldnt read the regulation loop err=%d\n",
2511 regulation_loop);
2512 return CHG_IN_PROGRESS;
2513 }
2514 pr_debug("regulation_loop=%d\n", regulation_loop);
2515
2516 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2517 return CHG_IN_PROGRESS;
2518 } /* !is_ext_charging */
2519
2520 /* reset count if battery chg current is more than iterm */
2521 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2522 if (rc) {
2523 pr_err("couldnt read iterm rc = %d\n", rc);
2524 return CHG_IN_PROGRESS;
2525 }
2526
2527 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2528 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2529 iterm_programmed, ichg_meas_ma);
2530 /*
2531 * ichg_meas_ma < 0 means battery is drawing current
2532 * ichg_meas_ma > 0 means battery is providing current
2533 */
2534 if (ichg_meas_ma > 0)
2535 return CHG_IN_PROGRESS;
2536
2537 if (ichg_meas_ma * -1 > iterm_programmed)
2538 return CHG_IN_PROGRESS;
2539
2540 return CHG_FINISHED;
2541}
2542
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002543/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002544 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002545 * has happened
2546 *
2547 * If all conditions favouring, if the charge current is
2548 * less than the term current for three consecutive times
2549 * an EOC has happened.
2550 * The wakelock is released if there is no need to reshedule
2551 * - this happens when the battery is removed or EOC has
2552 * happened
2553 */
2554#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002555static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002556{
2557 struct delayed_work *dwork = to_delayed_work(work);
2558 struct pm8921_chg_chip *chip = container_of(dwork,
2559 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002560 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002561 int end;
2562
2563 pm_chg_failed_clear(chip, 1);
2564 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002565
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002566 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002567 count = 0;
2568 wake_unlock(&chip->eoc_wake_lock);
2569 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002570 }
2571
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002572 if (end == CHG_FINISHED) {
2573 count++;
2574 } else {
2575 count = 0;
2576 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002577
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002578 if (count == CONSECUTIVE_COUNT) {
2579 count = 0;
2580 pr_info("End of Charging\n");
2581
2582 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002583
Amir Samuelovd31ef502011-10-26 14:41:36 +02002584 if (is_ext_charging(chip))
2585 chip->ext_charge_done = true;
2586
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002587 if (chip->is_bat_warm || chip->is_bat_cool)
2588 chip->bms_notify.is_battery_full = 0;
2589 else
2590 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002591 /* declare end of charging by invoking chgdone interrupt */
2592 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2593 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002594 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002595 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002596 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002597 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002598 round_jiffies_relative(msecs_to_jiffies
2599 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002600 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002601}
2602
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002603static void btm_configure_work(struct work_struct *work)
2604{
2605 int rc;
2606
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002607 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002608 if (rc)
2609 pr_err("failed to configure btm rc=%d", rc);
2610}
2611
2612DECLARE_WORK(btm_config_work, btm_configure_work);
2613
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002614static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2615{
2616 unsigned int chg_current = chip->max_bat_chg_current;
2617
2618 if (chip->is_bat_cool)
2619 chg_current = min(chg_current, chip->cool_bat_chg_current);
2620
2621 if (chip->is_bat_warm)
2622 chg_current = min(chg_current, chip->warm_bat_chg_current);
2623
David Keitelfdef3a42011-12-14 19:02:54 -08002624 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002625 chg_current = min(chg_current,
2626 chip->thermal_mitigation[thermal_mitigation]);
2627
2628 pm_chg_ibatmax_set(the_chip, chg_current);
2629}
2630
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002631#define TEMP_HYSTERISIS_DEGC 2
2632static void battery_cool(bool enter)
2633{
2634 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002635 if (enter == the_chip->is_bat_cool)
2636 return;
2637 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002638 if (enter) {
2639 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002640 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002641 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002642 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002643 pm_chg_vbatdet_set(the_chip,
2644 the_chip->cool_bat_voltage
2645 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002646 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002647 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002648 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002649 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002650 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002651 the_chip->max_voltage_mv
2652 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002653 }
2654 schedule_work(&btm_config_work);
2655}
2656
2657static void battery_warm(bool enter)
2658{
2659 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002660 if (enter == the_chip->is_bat_warm)
2661 return;
2662 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002663 if (enter) {
2664 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002665 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002666 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002667 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002668 pm_chg_vbatdet_set(the_chip,
2669 the_chip->warm_bat_voltage
2670 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002671 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002672 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002673 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002674 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002675 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002676 the_chip->max_voltage_mv
2677 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002678 }
2679 schedule_work(&btm_config_work);
2680}
2681
2682static int configure_btm(struct pm8921_chg_chip *chip)
2683{
2684 int rc;
2685
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002686 if (chip->warm_temp_dc != INT_MIN)
2687 btm_config.btm_warm_fn = battery_warm;
2688 else
2689 btm_config.btm_warm_fn = NULL;
2690
2691 if (chip->cool_temp_dc != INT_MIN)
2692 btm_config.btm_cool_fn = battery_cool;
2693 else
2694 btm_config.btm_cool_fn = NULL;
2695
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002696 btm_config.low_thr_temp = chip->cool_temp_dc;
2697 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002698 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002699 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002700 if (rc)
2701 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002702 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002703 if (rc)
2704 pr_err("failed to start btm rc = %d\n", rc);
2705
2706 return rc;
2707}
2708
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002709/**
2710 * set_disable_status_param -
2711 *
2712 * Internal function to disable battery charging and also disable drawing
2713 * any current from the source. The device is forced to run on a battery
2714 * after this.
2715 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716static int set_disable_status_param(const char *val, struct kernel_param *kp)
2717{
2718 int ret;
2719 struct pm8921_chg_chip *chip = the_chip;
2720
2721 ret = param_set_int(val, kp);
2722 if (ret) {
2723 pr_err("error setting value %d\n", ret);
2724 return ret;
2725 }
2726 pr_info("factory set disable param to %d\n", charging_disabled);
2727 if (chip) {
2728 pm_chg_auto_enable(chip, !charging_disabled);
2729 pm_chg_charge_dis(chip, charging_disabled);
2730 }
2731 return 0;
2732}
2733module_param_call(disabled, set_disable_status_param, param_get_uint,
2734 &charging_disabled, 0644);
2735
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002736static int rconn_mohm;
2737static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2738{
2739 int ret;
2740 struct pm8921_chg_chip *chip = the_chip;
2741
2742 ret = param_set_int(val, kp);
2743 if (ret) {
2744 pr_err("error setting value %d\n", ret);
2745 return ret;
2746 }
2747 if (chip)
2748 chip->rconn_mohm = rconn_mohm;
2749 return 0;
2750}
2751module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2752 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002753/**
2754 * set_thermal_mitigation_level -
2755 *
2756 * Internal function to control battery charging current to reduce
2757 * temperature
2758 */
2759static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2760{
2761 int ret;
2762 struct pm8921_chg_chip *chip = the_chip;
2763
2764 ret = param_set_int(val, kp);
2765 if (ret) {
2766 pr_err("error setting value %d\n", ret);
2767 return ret;
2768 }
2769
2770 if (!chip) {
2771 pr_err("called before init\n");
2772 return -EINVAL;
2773 }
2774
2775 if (!chip->thermal_mitigation) {
2776 pr_err("no thermal mitigation\n");
2777 return -EINVAL;
2778 }
2779
2780 if (thermal_mitigation < 0
2781 || thermal_mitigation >= chip->thermal_levels) {
2782 pr_err("out of bound level selected\n");
2783 return -EINVAL;
2784 }
2785
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002786 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002787 return ret;
2788}
2789module_param_call(thermal_mitigation, set_therm_mitigation_level,
2790 param_get_uint,
2791 &thermal_mitigation, 0644);
2792
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002793static int set_usb_max_current(const char *val, struct kernel_param *kp)
2794{
2795 int ret, mA;
2796 struct pm8921_chg_chip *chip = the_chip;
2797
2798 ret = param_set_int(val, kp);
2799 if (ret) {
2800 pr_err("error setting value %d\n", ret);
2801 return ret;
2802 }
2803 if (chip) {
2804 pr_warn("setting current max to %d\n", usb_max_current);
2805 pm_chg_iusbmax_get(chip, &mA);
2806 if (mA > usb_max_current)
2807 pm8921_charger_vbus_draw(usb_max_current);
2808 return 0;
2809 }
2810 return -EINVAL;
2811}
2812module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2813 &usb_max_current, 0644);
2814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815static void free_irqs(struct pm8921_chg_chip *chip)
2816{
2817 int i;
2818
2819 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2820 if (chip->pmic_chg_irq[i]) {
2821 free_irq(chip->pmic_chg_irq[i], chip);
2822 chip->pmic_chg_irq[i] = 0;
2823 }
2824}
2825
David Keitel88e1b572012-01-11 11:57:14 -08002826/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2828{
2829 unsigned long flags;
2830 int fsm_state;
2831
2832 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2833 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2834
2835 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002836 if (chip->usb_present) {
2837 schedule_delayed_work(&chip->unplug_check_work,
2838 round_jiffies_relative(msecs_to_jiffies
2839 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002840 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002841 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842
2843 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2844 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2845 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002846 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2847 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2848 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2849 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2850 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002851 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002852 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2853 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002854 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855
2856 spin_lock_irqsave(&vbus_lock, flags);
2857 if (usb_chg_current) {
2858 /* reissue a vbus draw call */
2859 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002860 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861 }
2862 spin_unlock_irqrestore(&vbus_lock, flags);
2863
2864 fsm_state = pm_chg_get_fsm_state(chip);
2865 if (is_battery_charging(fsm_state)) {
2866 chip->bms_notify.is_charging = 1;
2867 pm8921_bms_charging_began();
2868 }
2869
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002870 check_battery_valid(chip);
2871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2873 chip->usb_present,
2874 chip->dc_present,
2875 get_prop_batt_present(chip),
2876 fsm_state);
2877}
2878
2879struct pm_chg_irq_init_data {
2880 unsigned int irq_id;
2881 char *name;
2882 unsigned long flags;
2883 irqreturn_t (*handler)(int, void *);
2884};
2885
2886#define CHG_IRQ(_id, _flags, _handler) \
2887{ \
2888 .irq_id = _id, \
2889 .name = #_id, \
2890 .flags = _flags, \
2891 .handler = _handler, \
2892}
2893struct pm_chg_irq_init_data chg_irq_data[] = {
2894 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2895 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002896 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2898 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002899 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2900 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2902 usbin_uv_irq_handler),
2903 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2904 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2905 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2906 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2907 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2908 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2909 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2910 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2911 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002912 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2913 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2915 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2916 batt_removed_irq_handler),
2917 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2918 batttemp_hot_irq_handler),
2919 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2920 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2921 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08002922 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2923 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002924 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2925 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2927 coarse_det_low_irq_handler),
2928 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2929 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2930 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2931 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2932 batfet_irq_handler),
2933 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2934 dcin_valid_irq_handler),
2935 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2936 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002937 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938};
2939
2940static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2941 struct platform_device *pdev)
2942{
2943 struct resource *res;
2944 int ret, i;
2945
2946 ret = 0;
2947 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2948
2949 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2950 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2951 chg_irq_data[i].name);
2952 if (res == NULL) {
2953 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2954 goto err_out;
2955 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002956 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957 ret = request_irq(res->start, chg_irq_data[i].handler,
2958 chg_irq_data[i].flags,
2959 chg_irq_data[i].name, chip);
2960 if (ret < 0) {
2961 pr_err("couldn't request %d (%s) %d\n", res->start,
2962 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002963 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 goto err_out;
2965 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2967 }
2968 return 0;
2969
2970err_out:
2971 free_irqs(chip);
2972 return -EINVAL;
2973}
2974
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002975static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2976{
2977 int err;
2978 u8 temp;
2979
2980 temp = 0xD1;
2981 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2982 if (err) {
2983 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2984 return;
2985 }
2986
2987 temp = 0xD3;
2988 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2989 if (err) {
2990 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2991 return;
2992 }
2993
2994 temp = 0xD1;
2995 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2996 if (err) {
2997 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2998 return;
2999 }
3000
3001 temp = 0xD5;
3002 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3003 if (err) {
3004 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3005 return;
3006 }
3007
3008 udelay(183);
3009
3010 temp = 0xD1;
3011 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3012 if (err) {
3013 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3014 return;
3015 }
3016
3017 temp = 0xD0;
3018 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3019 if (err) {
3020 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3021 return;
3022 }
3023 udelay(32);
3024
3025 temp = 0xD1;
3026 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3027 if (err) {
3028 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3029 return;
3030 }
3031
3032 temp = 0xD3;
3033 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3034 if (err) {
3035 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3036 return;
3037 }
3038}
3039
3040static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3041{
3042 int err;
3043 u8 temp;
3044
3045 temp = 0xD1;
3046 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3047 if (err) {
3048 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3049 return;
3050 }
3051
3052 temp = 0xD0;
3053 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3054 if (err) {
3055 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3056 return;
3057 }
3058}
3059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060#define ENUM_TIMER_STOP_BIT BIT(1)
3061#define BOOT_DONE_BIT BIT(6)
3062#define CHG_BATFET_ON_BIT BIT(3)
3063#define CHG_VCP_EN BIT(0)
3064#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3065#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003066#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3068{
3069 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003070 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003071
3072 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3073 BOOT_DONE_BIT, BOOT_DONE_BIT);
3074 if (rc) {
3075 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3076 return rc;
3077 }
3078
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003079 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3080
3081 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3082 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3083
3084 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003086 if (rc) {
3087 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003088 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 return rc;
3090 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003091 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003092 chip->max_voltage_mv
3093 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 if (rc) {
3095 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003096 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 return rc;
3098 }
3099
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003100 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 if (rc) {
3102 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003103 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104 return rc;
3105 }
3106 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3107 if (rc) {
3108 pr_err("Failed to set max voltage to %d rc=%d\n",
3109 SAFE_CURRENT_MA, rc);
3110 return rc;
3111 }
3112
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003113 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003114 if (rc) {
3115 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3116 return rc;
3117 }
3118
3119 rc = pm_chg_iterm_set(chip, chip->term_current);
3120 if (rc) {
3121 pr_err("Failed to set term current to %d rc=%d\n",
3122 chip->term_current, rc);
3123 return rc;
3124 }
3125
3126 /* Disable the ENUM TIMER */
3127 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3128 ENUM_TIMER_STOP_BIT);
3129 if (rc) {
3130 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3131 return rc;
3132 }
3133
3134 /* init with the lowest USB current */
3135 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
3136 if (rc) {
3137 pr_err("Failed to set usb max to %d rc=%d\n",
3138 usb_ma_table[0].chg_iusb_value, rc);
3139 return rc;
3140 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003141
3142 if (chip->safety_time != 0) {
3143 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3144 if (rc) {
3145 pr_err("Failed to set max time to %d minutes rc=%d\n",
3146 chip->safety_time, rc);
3147 return rc;
3148 }
3149 }
3150
3151 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003152 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003153 if (rc) {
3154 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3155 chip->safety_time, rc);
3156 return rc;
3157 }
3158 }
3159
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003160 if (chip->vin_min != 0) {
3161 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3162 if (rc) {
3163 pr_err("Failed to set vin min to %d mV rc=%d\n",
3164 chip->vin_min, rc);
3165 return rc;
3166 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003167 } else {
3168 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003169 }
3170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003171 rc = pm_chg_disable_wd(chip);
3172 if (rc) {
3173 pr_err("Failed to disable wd rc=%d\n", rc);
3174 return rc;
3175 }
3176
3177 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3178 CHG_BAT_TEMP_DIS_BIT, 0);
3179 if (rc) {
3180 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3181 return rc;
3182 }
3183 /* switch to a 3.2Mhz for the buck */
3184 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3185 if (rc) {
3186 pr_err("Failed to switch buck clk rc=%d\n", rc);
3187 return rc;
3188 }
3189
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003190 if (chip->trkl_voltage != 0) {
3191 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3192 if (rc) {
3193 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3194 chip->trkl_voltage, rc);
3195 return rc;
3196 }
3197 }
3198
3199 if (chip->weak_voltage != 0) {
3200 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3201 if (rc) {
3202 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3203 chip->weak_voltage, rc);
3204 return rc;
3205 }
3206 }
3207
3208 if (chip->trkl_current != 0) {
3209 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3210 if (rc) {
3211 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3212 chip->trkl_voltage, rc);
3213 return rc;
3214 }
3215 }
3216
3217 if (chip->weak_current != 0) {
3218 rc = pm_chg_iweak_set(chip, chip->weak_current);
3219 if (rc) {
3220 pr_err("Failed to set weak current to %dmA rc=%d\n",
3221 chip->weak_current, rc);
3222 return rc;
3223 }
3224 }
3225
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003226 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3227 if (rc) {
3228 pr_err("Failed to set cold config %d rc=%d\n",
3229 chip->cold_thr, rc);
3230 }
3231
3232 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3233 if (rc) {
3234 pr_err("Failed to set hot config %d rc=%d\n",
3235 chip->hot_thr, rc);
3236 }
3237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 /* Workarounds for die 1.1 and 1.0 */
3239 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3240 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003241 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3242 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003243
3244 /* software workaround for correct battery_id detection */
3245 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3246 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3247 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3248 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3249 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3250 udelay(100);
3251 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 }
3253
David Keitelb51995e2011-11-18 17:03:31 -08003254 /* Workarounds for die 3.0 */
3255 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3256 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3257
3258 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3259
David Keitela3c0d822011-11-03 14:18:52 -07003260 /* Disable EOC FSM processing */
3261 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3262
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003263 pm8921_chg_force_19p2mhz_clk(chip);
3264
3265 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3266 VREF_BATT_THERM_FORCE_ON);
3267 if (rc)
3268 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270 rc = pm_chg_charge_dis(chip, charging_disabled);
3271 if (rc) {
3272 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3273 return rc;
3274 }
3275
3276 rc = pm_chg_auto_enable(chip, !charging_disabled);
3277 if (rc) {
3278 pr_err("Failed to enable charging rc=%d\n", rc);
3279 return rc;
3280 }
3281
3282 return 0;
3283}
3284
3285static int get_rt_status(void *data, u64 * val)
3286{
3287 int i = (int)data;
3288 int ret;
3289
3290 /* global irq number is passed in via data */
3291 ret = pm_chg_get_rt_status(the_chip, i);
3292 *val = ret;
3293 return 0;
3294}
3295DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3296
3297static int get_fsm_status(void *data, u64 * val)
3298{
3299 u8 temp;
3300
3301 temp = pm_chg_get_fsm_state(the_chip);
3302 *val = temp;
3303 return 0;
3304}
3305DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3306
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003307static int get_reg_loop(void *data, u64 * val)
3308{
3309 u8 temp;
3310
3311 if (!the_chip) {
3312 pr_err("%s called before init\n", __func__);
3313 return -EINVAL;
3314 }
3315 temp = pm_chg_get_regulation_loop(the_chip);
3316 *val = temp;
3317 return 0;
3318}
3319DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321static int get_reg(void *data, u64 * val)
3322{
3323 int addr = (int)data;
3324 int ret;
3325 u8 temp;
3326
3327 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3328 if (ret) {
3329 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3330 addr, temp, ret);
3331 return -EAGAIN;
3332 }
3333 *val = temp;
3334 return 0;
3335}
3336
3337static int set_reg(void *data, u64 val)
3338{
3339 int addr = (int)data;
3340 int ret;
3341 u8 temp;
3342
3343 temp = (u8) val;
3344 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3345 if (ret) {
3346 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3347 addr, temp, ret);
3348 return -EAGAIN;
3349 }
3350 return 0;
3351}
3352DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3353
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003354enum {
3355 BAT_WARM_ZONE,
3356 BAT_COOL_ZONE,
3357};
3358static int get_warm_cool(void *data, u64 * val)
3359{
3360 if (!the_chip) {
3361 pr_err("%s called before init\n", __func__);
3362 return -EINVAL;
3363 }
3364 if ((int)data == BAT_WARM_ZONE)
3365 *val = the_chip->is_bat_warm;
3366 if ((int)data == BAT_COOL_ZONE)
3367 *val = the_chip->is_bat_cool;
3368 return 0;
3369}
3370DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3373{
3374 int i;
3375
3376 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3377
3378 if (IS_ERR(chip->dent)) {
3379 pr_err("pmic charger couldnt create debugfs dir\n");
3380 return;
3381 }
3382
3383 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3384 (void *)CHG_CNTRL, &reg_fops);
3385 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3386 (void *)CHG_CNTRL_2, &reg_fops);
3387 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3388 (void *)CHG_CNTRL_3, &reg_fops);
3389 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3390 (void *)PBL_ACCESS1, &reg_fops);
3391 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3392 (void *)PBL_ACCESS2, &reg_fops);
3393 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3394 (void *)SYS_CONFIG_1, &reg_fops);
3395 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3396 (void *)SYS_CONFIG_2, &reg_fops);
3397 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3398 (void *)CHG_VDD_MAX, &reg_fops);
3399 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3400 (void *)CHG_VDD_SAFE, &reg_fops);
3401 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3402 (void *)CHG_VBAT_DET, &reg_fops);
3403 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3404 (void *)CHG_IBAT_MAX, &reg_fops);
3405 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3406 (void *)CHG_IBAT_SAFE, &reg_fops);
3407 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3408 (void *)CHG_VIN_MIN, &reg_fops);
3409 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3410 (void *)CHG_VTRICKLE, &reg_fops);
3411 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3412 (void *)CHG_ITRICKLE, &reg_fops);
3413 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3414 (void *)CHG_ITERM, &reg_fops);
3415 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3416 (void *)CHG_TCHG_MAX, &reg_fops);
3417 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3418 (void *)CHG_TWDOG, &reg_fops);
3419 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3420 (void *)CHG_TEMP_THRESH, &reg_fops);
3421 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3422 (void *)CHG_COMP_OVR, &reg_fops);
3423 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3424 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3425 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3426 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3427 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3428 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3429 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3430 (void *)CHG_TEST, &reg_fops);
3431
3432 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3433 &fsm_fops);
3434
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003435 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3436 &reg_loop_fops);
3437
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003438 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3439 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3440 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3441 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3444 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3445 debugfs_create_file(chg_irq_data[i].name, 0444,
3446 chip->dent,
3447 (void *)chg_irq_data[i].irq_id,
3448 &rt_fops);
3449 }
3450}
3451
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003452static int pm8921_charger_suspend_noirq(struct device *dev)
3453{
3454 int rc;
3455 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3456
3457 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3458 if (rc)
3459 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3460 pm8921_chg_set_hw_clk_switching(chip);
3461 return 0;
3462}
3463
3464static int pm8921_charger_resume_noirq(struct device *dev)
3465{
3466 int rc;
3467 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3468
3469 pm8921_chg_force_19p2mhz_clk(chip);
3470
3471 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3472 VREF_BATT_THERM_FORCE_ON);
3473 if (rc)
3474 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3475 return 0;
3476}
3477
David Keitelf2226022011-12-13 15:55:50 -08003478static int pm8921_charger_resume(struct device *dev)
3479{
3480 int rc;
3481 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3482
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003483 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003484 && !(chip->keep_btm_on_suspend)) {
3485 rc = pm8xxx_adc_btm_configure(&btm_config);
3486 if (rc)
3487 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3488
3489 rc = pm8xxx_adc_btm_start();
3490 if (rc)
3491 pr_err("couldn't restart btm rc=%d\n", rc);
3492 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003493 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3494 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3495 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3496 }
David Keitelf2226022011-12-13 15:55:50 -08003497 return 0;
3498}
3499
3500static int pm8921_charger_suspend(struct device *dev)
3501{
3502 int rc;
3503 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3504
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003505 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003506 && !(chip->keep_btm_on_suspend)) {
3507 rc = pm8xxx_adc_btm_end();
3508 if (rc)
3509 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3510 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003511
3512 if (is_usb_chg_plugged_in(chip)) {
3513 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3514 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3515 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003516
David Keitelf2226022011-12-13 15:55:50 -08003517 return 0;
3518}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3520{
3521 int rc = 0;
3522 struct pm8921_chg_chip *chip;
3523 const struct pm8921_charger_platform_data *pdata
3524 = pdev->dev.platform_data;
3525
3526 if (!pdata) {
3527 pr_err("missing platform data\n");
3528 return -EINVAL;
3529 }
3530
3531 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3532 GFP_KERNEL);
3533 if (!chip) {
3534 pr_err("Cannot allocate pm_chg_chip\n");
3535 return -ENOMEM;
3536 }
3537
3538 chip->dev = &pdev->dev;
3539 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003540 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003542 chip->max_voltage_mv = pdata->max_voltage;
3543 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003544 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 chip->term_current = pdata->term_current;
3546 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003547 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003548 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3549 chip->batt_id_min = pdata->batt_id_min;
3550 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003551 if (pdata->cool_temp != INT_MIN)
3552 chip->cool_temp_dc = pdata->cool_temp * 10;
3553 else
3554 chip->cool_temp_dc = INT_MIN;
3555
3556 if (pdata->warm_temp != INT_MIN)
3557 chip->warm_temp_dc = pdata->warm_temp * 10;
3558 else
3559 chip->warm_temp_dc = INT_MIN;
3560
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003561 chip->temp_check_period = pdata->temp_check_period;
3562 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3563 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3564 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3565 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3566 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003567 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003568 chip->trkl_voltage = pdata->trkl_voltage;
3569 chip->weak_voltage = pdata->weak_voltage;
3570 chip->trkl_current = pdata->trkl_current;
3571 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003572 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003573 chip->thermal_mitigation = pdata->thermal_mitigation;
3574 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003575
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003576 chip->cold_thr = pdata->cold_thr;
3577 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003578 chip->rconn_mohm = pdata->rconn_mohm;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 rc = pm8921_chg_hw_init(chip);
3581 if (rc) {
3582 pr_err("couldn't init hardware rc=%d\n", rc);
3583 goto free_chip;
3584 }
3585
3586 chip->usb_psy.name = "usb",
3587 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3588 chip->usb_psy.supplied_to = pm_power_supplied_to,
3589 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003590 chip->usb_psy.properties = pm_power_props_usb,
3591 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3592 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003593
David Keitel6ed71a52012-01-30 12:42:18 -08003594 chip->dc_psy.name = "pm8921-dc",
3595 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3596 chip->dc_psy.supplied_to = pm_power_supplied_to,
3597 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003598 chip->dc_psy.properties = pm_power_props_mains,
3599 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3600 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003602 chip->batt_psy.name = "battery",
3603 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3604 chip->batt_psy.properties = msm_batt_power_props,
3605 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3606 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003607 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 rc = power_supply_register(chip->dev, &chip->usb_psy);
3609 if (rc < 0) {
3610 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003611 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003612 }
3613
David Keitel6ed71a52012-01-30 12:42:18 -08003614 rc = power_supply_register(chip->dev, &chip->dc_psy);
3615 if (rc < 0) {
3616 pr_err("power_supply_register usb failed rc = %d\n", rc);
3617 goto unregister_usb;
3618 }
3619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 rc = power_supply_register(chip->dev, &chip->batt_psy);
3621 if (rc < 0) {
3622 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003623 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624 }
3625
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003626 platform_set_drvdata(pdev, chip);
3627 the_chip = chip;
3628
3629 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003630 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003631 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3632 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003633 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 rc = request_irqs(chip, pdev);
3636 if (rc) {
3637 pr_err("couldn't register interrupts rc=%d\n", rc);
3638 goto unregister_batt;
3639 }
3640
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003641 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3642 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3643 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003644 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3645 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003646 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003647 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003648 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003649 * care for jeita compliance
3650 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003651 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003652 rc = configure_btm(chip);
3653 if (rc) {
3654 pr_err("couldn't register with btm rc=%d\n", rc);
3655 goto free_irq;
3656 }
3657 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003659 create_debugfs_entries(chip);
3660
3661 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003662 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003664 /* determine what state the charger is in */
3665 determine_initial_state(chip);
3666
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003667 if (chip->update_time) {
3668 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3669 update_heartbeat);
3670 schedule_delayed_work(&chip->update_heartbeat_work,
3671 round_jiffies_relative(msecs_to_jiffies
3672 (chip->update_time)));
3673 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674 return 0;
3675
3676free_irq:
3677 free_irqs(chip);
3678unregister_batt:
3679 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003680unregister_dc:
3681 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682unregister_usb:
3683 power_supply_unregister(&chip->usb_psy);
3684free_chip:
3685 kfree(chip);
3686 return rc;
3687}
3688
3689static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3690{
3691 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3692
3693 free_irqs(chip);
3694 platform_set_drvdata(pdev, NULL);
3695 the_chip = NULL;
3696 kfree(chip);
3697 return 0;
3698}
David Keitelf2226022011-12-13 15:55:50 -08003699static const struct dev_pm_ops pm8921_pm_ops = {
3700 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003701 .suspend_noirq = pm8921_charger_suspend_noirq,
3702 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003703 .resume = pm8921_charger_resume,
3704};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003706 .probe = pm8921_charger_probe,
3707 .remove = __devexit_p(pm8921_charger_remove),
3708 .driver = {
3709 .name = PM8921_CHARGER_DEV_NAME,
3710 .owner = THIS_MODULE,
3711 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712 },
3713};
3714
3715static int __init pm8921_charger_init(void)
3716{
3717 return platform_driver_register(&pm8921_charger_driver);
3718}
3719
3720static void __exit pm8921_charger_exit(void)
3721{
3722 platform_driver_unregister(&pm8921_charger_driver);
3723}
3724
3725late_initcall(pm8921_charger_init);
3726module_exit(pm8921_charger_exit);
3727
3728MODULE_LICENSE("GPL v2");
3729MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3730MODULE_VERSION("1.0");
3731MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);