blob: 78757f953496f3aa253357abdcc6286e575a1eeb [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;
David Keitel8c5201a2012-02-24 16:08:54 -0800261 struct wake_lock unplug_ovp_fet_open_wake_lock;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct wake_lock eoc_wake_lock;
263 enum pm8921_chg_cold_thr cold_thr;
264 enum pm8921_chg_hot_thr hot_thr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265};
266
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800267static int usb_max_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700269static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271static struct pm8921_chg_chip *the_chip;
272
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700273static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
276 u8 mask, u8 val)
277{
278 int rc;
279 u8 reg;
280
281 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
282 if (rc) {
283 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
284 return rc;
285 }
286 reg &= ~mask;
287 reg |= val & mask;
288 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
289 if (rc) {
290 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
291 return rc;
292 }
293 return 0;
294}
295
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 */
1149 if (psy->type == POWER_SUPPLY_TYPE_USB ||
David Keitel6ed71a52012-01-30 12:42:18 -08001150 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
1151 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
1152 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
David Keitel63f71662012-02-08 20:30:00 -08001153 val->intval = is_usb_chg_plugged_in(the_chip);
1154 return 0;
1155 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 break;
1157 default:
1158 return -EINVAL;
1159 }
1160 return 0;
1161}
1162
1163static enum power_supply_property msm_batt_power_props[] = {
1164 POWER_SUPPLY_PROP_STATUS,
1165 POWER_SUPPLY_PROP_CHARGE_TYPE,
1166 POWER_SUPPLY_PROP_HEALTH,
1167 POWER_SUPPLY_PROP_PRESENT,
1168 POWER_SUPPLY_PROP_TECHNOLOGY,
1169 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1170 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1171 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1172 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001173 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001174 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001175 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176};
1177
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001178static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179{
1180 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001181 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001183 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 if (rc) {
1185 pr_err("error reading adc channel = %d, rc = %d\n",
1186 chip->vbat_channel, rc);
1187 return rc;
1188 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001189 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 result.measurement);
1191 return (int)result.physical;
1192}
1193
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001194static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1195{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001196 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1197 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1198 unsigned int low_voltage = chip->min_voltage_mv;
1199 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001200
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001201 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001202 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001203 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001204 return 100;
1205 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001206 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001207 / (high_voltage - low_voltage);
1208}
1209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1211{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001212 int percent_soc = pm8921_bms_get_percent_charge();
1213
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001214 if (percent_soc == -ENXIO)
1215 percent_soc = voltage_based_capacity(chip);
1216
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001217 if (percent_soc <= 10)
1218 pr_warn("low battery charge = %d%%\n", percent_soc);
1219
1220 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221}
1222
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001223static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1224{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001225 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001226
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001227 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001228 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001229 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001230 }
1231
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001232 if (rc) {
1233 pr_err("unable to get batt current rc = %d\n", rc);
1234 return rc;
1235 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001236 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001237 }
1238}
1239
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001240static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1241{
1242 int rc;
1243
1244 rc = pm8921_bms_get_fcc();
1245 if (rc < 0)
1246 pr_err("unable to get batt fcc rc = %d\n", rc);
1247 return rc;
1248}
1249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1251{
1252 int temp;
1253
1254 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1255 if (temp)
1256 return POWER_SUPPLY_HEALTH_OVERHEAT;
1257
1258 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1259 if (temp)
1260 return POWER_SUPPLY_HEALTH_COLD;
1261
1262 return POWER_SUPPLY_HEALTH_GOOD;
1263}
1264
1265static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1266{
1267 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1268}
1269
1270static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1271{
1272 int temp;
1273
Amir Samuelovd31ef502011-10-26 14:41:36 +02001274 if (!get_prop_batt_present(chip))
1275 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1276
1277 if (is_ext_trickle_charging(chip))
1278 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1279
1280 if (is_ext_charging(chip))
1281 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1284 if (temp)
1285 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1286
1287 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1288 if (temp)
1289 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1290
1291 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1292}
1293
1294static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1295{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001296 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1297 int fsm_state = pm_chg_get_fsm_state(chip);
1298 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299
David Keitel88e1b572012-01-11 11:57:14 -08001300 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001301 if (chip->ext_charge_done)
1302 return POWER_SUPPLY_STATUS_FULL;
1303 if (chip->ext_charging)
1304 return POWER_SUPPLY_STATUS_CHARGING;
1305 }
1306
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001307 for (i = 0; i < ARRAY_SIZE(map); i++)
1308 if (map[i].fsm_state == fsm_state)
1309 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001310
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001311 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1312 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1313 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001314 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1315 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001316
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001317 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001318 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001319 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320}
1321
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001322#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001323static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1324{
1325 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001326 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001327
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001328 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001329 if (rc) {
1330 pr_err("error reading adc channel = %d, rc = %d\n",
1331 chip->vbat_channel, rc);
1332 return rc;
1333 }
1334 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1335 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001336 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1337 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1338 (int) result.physical);
1339
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001340 return (int)result.physical;
1341}
1342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343static int pm_batt_power_get_property(struct power_supply *psy,
1344 enum power_supply_property psp,
1345 union power_supply_propval *val)
1346{
1347 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1348 batt_psy);
1349
1350 switch (psp) {
1351 case POWER_SUPPLY_PROP_STATUS:
1352 val->intval = get_prop_batt_status(chip);
1353 break;
1354 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1355 val->intval = get_prop_charge_type(chip);
1356 break;
1357 case POWER_SUPPLY_PROP_HEALTH:
1358 val->intval = get_prop_batt_health(chip);
1359 break;
1360 case POWER_SUPPLY_PROP_PRESENT:
1361 val->intval = get_prop_batt_present(chip);
1362 break;
1363 case POWER_SUPPLY_PROP_TECHNOLOGY:
1364 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1365 break;
1366 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001367 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 break;
1369 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001370 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 break;
1372 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001373 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 break;
1375 case POWER_SUPPLY_PROP_CAPACITY:
1376 val->intval = get_prop_batt_capacity(chip);
1377 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001378 case POWER_SUPPLY_PROP_CURRENT_NOW:
1379 val->intval = get_prop_batt_current(chip);
1380 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001381 case POWER_SUPPLY_PROP_TEMP:
1382 val->intval = get_prop_batt_temp(chip);
1383 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001384 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001385 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001386 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 default:
1388 return -EINVAL;
1389 }
1390
1391 return 0;
1392}
1393
1394static void (*notify_vbus_state_func_ptr)(int);
1395static int usb_chg_current;
1396static DEFINE_SPINLOCK(vbus_lock);
1397
1398int pm8921_charger_register_vbus_sn(void (*callback)(int))
1399{
1400 pr_debug("%p\n", callback);
1401 notify_vbus_state_func_ptr = callback;
1402 return 0;
1403}
1404EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1405
1406/* this is passed to the hsusb via platform_data msm_otg_pdata */
1407void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1408{
1409 pr_debug("%p\n", callback);
1410 notify_vbus_state_func_ptr = NULL;
1411}
1412EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1413
1414static void notify_usb_of_the_plugin_event(int plugin)
1415{
1416 plugin = !!plugin;
1417 if (notify_vbus_state_func_ptr) {
1418 pr_debug("notifying plugin\n");
1419 (*notify_vbus_state_func_ptr) (plugin);
1420 } else {
1421 pr_debug("unable to notify plugin\n");
1422 }
1423}
1424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425/* assumes vbus_lock is held */
1426static void __pm8921_charger_vbus_draw(unsigned int mA)
1427{
1428 int i, rc;
1429
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001430 if (usb_max_current && mA > usb_max_current) {
1431 pr_warn("restricting usb current to %d instead of %d\n",
1432 usb_max_current, mA);
1433 mA = usb_max_current;
1434 }
1435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 if (mA > 0 && mA <= 2) {
1437 usb_chg_current = 0;
1438 rc = pm_chg_iusbmax_set(the_chip,
1439 usb_ma_table[0].chg_iusb_value);
1440 if (rc) {
1441 pr_err("unable to set iusb to %d rc = %d\n",
1442 usb_ma_table[0].chg_iusb_value, rc);
1443 }
1444 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1445 if (rc)
1446 pr_err("fail to set suspend bit rc=%d\n", rc);
1447 } else {
1448 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1449 if (rc)
1450 pr_err("fail to reset suspend bit rc=%d\n", rc);
1451 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1452 if (usb_ma_table[i].usb_ma <= mA)
1453 break;
1454 }
1455 if (i < 0)
1456 i = 0;
1457 rc = pm_chg_iusbmax_set(the_chip,
1458 usb_ma_table[i].chg_iusb_value);
1459 if (rc) {
1460 pr_err("unable to set iusb to %d rc = %d\n",
1461 usb_ma_table[i].chg_iusb_value, rc);
1462 }
1463 }
1464}
1465
1466/* USB calls these to tell us how much max usb current the system can draw */
1467void pm8921_charger_vbus_draw(unsigned int mA)
1468{
1469 unsigned long flags;
1470
1471 pr_debug("Enter charge=%d\n", mA);
1472 spin_lock_irqsave(&vbus_lock, flags);
1473 if (the_chip) {
1474 __pm8921_charger_vbus_draw(mA);
1475 } else {
1476 /*
1477 * called before pmic initialized,
1478 * save this value and use it at probe
1479 */
1480 usb_chg_current = mA;
1481 }
1482 spin_unlock_irqrestore(&vbus_lock, flags);
1483}
1484EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1485
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001486int pm8921_charger_enable(bool enable)
1487{
1488 int rc;
1489
1490 if (!the_chip) {
1491 pr_err("called before init\n");
1492 return -EINVAL;
1493 }
1494 enable = !!enable;
1495 rc = pm_chg_auto_enable(the_chip, enable);
1496 if (rc)
1497 pr_err("Failed rc=%d\n", rc);
1498 return rc;
1499}
1500EXPORT_SYMBOL(pm8921_charger_enable);
1501
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001502int pm8921_is_usb_chg_plugged_in(void)
1503{
1504 if (!the_chip) {
1505 pr_err("called before init\n");
1506 return -EINVAL;
1507 }
1508 return is_usb_chg_plugged_in(the_chip);
1509}
1510EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1511
1512int pm8921_is_dc_chg_plugged_in(void)
1513{
1514 if (!the_chip) {
1515 pr_err("called before init\n");
1516 return -EINVAL;
1517 }
1518 return is_dc_chg_plugged_in(the_chip);
1519}
1520EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1521
1522int pm8921_is_battery_present(void)
1523{
1524 if (!the_chip) {
1525 pr_err("called before init\n");
1526 return -EINVAL;
1527 }
1528 return get_prop_batt_present(the_chip);
1529}
1530EXPORT_SYMBOL(pm8921_is_battery_present);
1531
David Keitel012deef2011-12-02 11:49:33 -08001532/*
1533 * Disabling the charge current limit causes current
1534 * current limits to have no monitoring. An adequate charger
1535 * capable of supplying high current while sustaining VIN_MIN
1536 * is required if the limiting is disabled.
1537 */
1538int pm8921_disable_input_current_limit(bool disable)
1539{
1540 if (!the_chip) {
1541 pr_err("called before init\n");
1542 return -EINVAL;
1543 }
1544 if (disable) {
1545 pr_warn("Disabling input current limit!\n");
1546
1547 return pm8xxx_writeb(the_chip->dev->parent,
1548 CHG_BUCK_CTRL_TEST3, 0xF2);
1549 }
1550 return 0;
1551}
1552EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1553
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001554int pm8921_set_max_battery_charge_current(int ma)
1555{
1556 if (!the_chip) {
1557 pr_err("called before init\n");
1558 return -EINVAL;
1559 }
1560 return pm_chg_ibatmax_set(the_chip, ma);
1561}
1562EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1563
1564int pm8921_disable_source_current(bool disable)
1565{
1566 if (!the_chip) {
1567 pr_err("called before init\n");
1568 return -EINVAL;
1569 }
1570 if (disable)
1571 pr_warn("current drawn from chg=0, battery provides current\n");
1572 return pm_chg_charge_dis(the_chip, disable);
1573}
1574EXPORT_SYMBOL(pm8921_disable_source_current);
1575
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001576int pm8921_regulate_input_voltage(int voltage)
1577{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001578 int rc;
1579
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001580 if (!the_chip) {
1581 pr_err("called before init\n");
1582 return -EINVAL;
1583 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001584 rc = pm_chg_vinmin_set(the_chip, voltage);
1585
1586 if (rc == 0)
1587 the_chip->vin_min = voltage;
1588
1589 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001590}
1591
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001592#define USB_OV_THRESHOLD_MASK 0x60
1593#define USB_OV_THRESHOLD_SHIFT 5
1594int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1595{
1596 u8 temp;
1597
1598 if (!the_chip) {
1599 pr_err("called before init\n");
1600 return -EINVAL;
1601 }
1602
1603 if (ov > PM_USB_OV_7V) {
1604 pr_err("limiting to over voltage threshold to 7volts\n");
1605 ov = PM_USB_OV_7V;
1606 }
1607
1608 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1609
1610 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1611 USB_OV_THRESHOLD_MASK, temp);
1612}
1613EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1614
1615#define USB_DEBOUNCE_TIME_MASK 0x06
1616#define USB_DEBOUNCE_TIME_SHIFT 1
1617int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1618{
1619 u8 temp;
1620
1621 if (!the_chip) {
1622 pr_err("called before init\n");
1623 return -EINVAL;
1624 }
1625
1626 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1627 pr_err("limiting debounce to 80.5ms\n");
1628 ms = PM_USB_DEBOUNCE_80P5MS;
1629 }
1630
1631 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1632
1633 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1634 USB_DEBOUNCE_TIME_MASK, temp);
1635}
1636EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1637
1638#define USB_OVP_DISABLE_MASK 0x80
1639int pm8921_usb_ovp_disable(int disable)
1640{
1641 u8 temp = 0;
1642
1643 if (!the_chip) {
1644 pr_err("called before init\n");
1645 return -EINVAL;
1646 }
1647
1648 if (disable)
1649 temp = USB_OVP_DISABLE_MASK;
1650
1651 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1652 USB_OVP_DISABLE_MASK, temp);
1653}
1654
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001655bool pm8921_is_battery_charging(int *source)
1656{
1657 int fsm_state, is_charging, dc_present, usb_present;
1658
1659 if (!the_chip) {
1660 pr_err("called before init\n");
1661 return -EINVAL;
1662 }
1663 fsm_state = pm_chg_get_fsm_state(the_chip);
1664 is_charging = is_battery_charging(fsm_state);
1665 if (is_charging == 0) {
1666 *source = PM8921_CHG_SRC_NONE;
1667 return is_charging;
1668 }
1669
1670 if (source == NULL)
1671 return is_charging;
1672
1673 /* the battery is charging, the source is requested, find it */
1674 dc_present = is_dc_chg_plugged_in(the_chip);
1675 usb_present = is_usb_chg_plugged_in(the_chip);
1676
1677 if (dc_present && !usb_present)
1678 *source = PM8921_CHG_SRC_DC;
1679
1680 if (usb_present && !dc_present)
1681 *source = PM8921_CHG_SRC_USB;
1682
1683 if (usb_present && dc_present)
1684 /*
1685 * The system always chooses dc for charging since it has
1686 * higher priority.
1687 */
1688 *source = PM8921_CHG_SRC_DC;
1689
1690 return is_charging;
1691}
1692EXPORT_SYMBOL(pm8921_is_battery_charging);
1693
David Keitel6df9cea2011-12-21 12:36:45 -08001694int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1695{
1696 if (!the_chip) {
1697 pr_err("called before init\n");
1698 return -EINVAL;
1699 }
1700
1701 if (type < POWER_SUPPLY_TYPE_USB)
1702 return -EINVAL;
1703
1704 the_chip->usb_psy.type = type;
1705 power_supply_changed(&the_chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001706 power_supply_changed(&the_chip->dc_psy);
David Keitel6df9cea2011-12-21 12:36:45 -08001707 return 0;
1708}
1709EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1710
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001711int pm8921_batt_temperature(void)
1712{
1713 if (!the_chip) {
1714 pr_err("called before init\n");
1715 return -EINVAL;
1716 }
1717 return get_prop_batt_temp(the_chip);
1718}
1719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1721{
1722 int usb_present;
1723
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001724 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725 usb_present = is_usb_chg_plugged_in(chip);
1726 if (chip->usb_present ^ usb_present) {
1727 notify_usb_of_the_plugin_event(usb_present);
1728 chip->usb_present = usb_present;
1729 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001730 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001732 if (usb_present) {
1733 schedule_delayed_work(&chip->unplug_check_work,
1734 round_jiffies_relative(msecs_to_jiffies
1735 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001736 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1737 } else {
1738 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001739 }
David Keitel8c5201a2012-02-24 16:08:54 -08001740 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001741 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742}
1743
Amir Samuelovd31ef502011-10-26 14:41:36 +02001744static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1745{
David Keitel88e1b572012-01-11 11:57:14 -08001746 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001747 pr_debug("external charger not registered.\n");
1748 return;
1749 }
1750
1751 if (!chip->ext_charging) {
1752 pr_debug("already not charging.\n");
1753 return;
1754 }
1755
David Keitel88e1b572012-01-11 11:57:14 -08001756 power_supply_set_charge_type(chip->ext_psy,
1757 POWER_SUPPLY_CHARGE_TYPE_NONE);
1758 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001759 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001760 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001761 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001762 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001763}
1764
1765static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1766{
1767 int dc_present;
1768 int batt_present;
1769 int batt_temp_ok;
1770 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001771 unsigned long delay =
1772 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1773
David Keitel88e1b572012-01-11 11:57:14 -08001774 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001775 pr_debug("external charger not registered.\n");
1776 return;
1777 }
1778
1779 if (chip->ext_charging) {
1780 pr_debug("already charging.\n");
1781 return;
1782 }
1783
David Keitel88e1b572012-01-11 11:57:14 -08001784 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001785 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1786 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001787
1788 if (!dc_present) {
1789 pr_warn("%s. dc not present.\n", __func__);
1790 return;
1791 }
1792 if (!batt_present) {
1793 pr_warn("%s. battery not present.\n", __func__);
1794 return;
1795 }
1796 if (!batt_temp_ok) {
1797 pr_warn("%s. battery temperature not ok.\n", __func__);
1798 return;
1799 }
David Keitel88e1b572012-01-11 11:57:14 -08001800 pm8921_disable_source_current(true); /* Force BATFET=ON */
1801 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001802 if (vbat_ov) {
1803 pr_warn("%s. battery over voltage.\n", __func__);
1804 return;
1805 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001806
David Keitel63f71662012-02-08 20:30:00 -08001807 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001808 power_supply_set_charge_type(chip->ext_psy,
1809 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001810 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001811 chip->ext_charging = true;
1812 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001813 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001814 /* Start BMS */
1815 schedule_delayed_work(&chip->eoc_work, delay);
1816 wake_lock(&chip->eoc_wake_lock);
1817}
1818
David Keitel8c5201a2012-02-24 16:08:54 -08001819static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001820{
1821 u8 temp;
1822 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001823
David Keitel8c5201a2012-02-24 16:08:54 -08001824 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001825 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001826 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1827 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001828 }
David Keitel8c5201a2012-02-24 16:08:54 -08001829 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1830 if (rc) {
1831 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1832 return;
1833 }
1834 /* set ovp fet disable bit and the write bit */
1835 temp |= 0x81;
1836 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1837 if (rc) {
1838 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1839 return;
1840 }
1841}
1842
1843static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1844{
1845 u8 temp;
1846 int rc;
1847
1848 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1849 if (rc) {
1850 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1851 return;
1852 }
1853 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1854 if (rc) {
1855 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1856 return;
1857 }
1858 /* unset ovp fet disable bit and set the write bit */
1859 temp &= 0xFE;
1860 temp |= 0x80;
1861 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1862 if (rc) {
1863 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1864 temp, rc);
1865 return;
1866 }
1867}
1868
1869static int param_open_ovp_counter = 10;
1870module_param(param_open_ovp_counter, int, 0644);
1871
1872#define WRITE_BANK_4 0xC0
1873#define USB_OVP_DEBOUNCE_TIME 0x06
1874static void unplug_ovp_fet_open_worker(struct work_struct *work)
1875{
1876 struct pm8921_chg_chip *chip = container_of(work,
1877 struct pm8921_chg_chip,
1878 unplug_ovp_fet_open_work);
1879 int chg_gone, usb_chg_plugged_in;
1880 int count = 0;
1881
1882 while (count++ < param_open_ovp_counter) {
1883 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1884 USB_OVP_DEBOUNCE_TIME, 0x0);
1885 usleep(10);
1886 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1887 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1888 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1889 count, chg_gone, usb_chg_plugged_in);
1890
1891 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1892 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1893 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1894 turn_off_usb_ovp_fet(chip);
1895
1896 msleep(20);
1897
1898 turn_on_usb_ovp_fet(chip);
1899 } else {
1900 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1901 USB_OVP_DEBOUNCE_TIME, 0x1);
1902 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1903 count, chg_gone, usb_chg_plugged_in);
1904 return;
1905 }
1906 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001907}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1909{
1910 handle_usb_insertion_removal(data);
1911 return IRQ_HANDLED;
1912}
1913
1914static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1915{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001916 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 return IRQ_HANDLED;
1918}
1919
1920static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1921{
1922 struct pm8921_chg_chip *chip = data;
1923 int status;
1924
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001925 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1926 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001927 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 pr_debug("battery present=%d", status);
1929 power_supply_changed(&chip->batt_psy);
1930 return IRQ_HANDLED;
1931}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001932
1933/*
1934 * this interrupt used to restart charging a battery.
1935 *
1936 * Note: When DC-inserted the VBAT can't go low.
1937 * VPH_PWR is provided by the ext-charger.
1938 * After End-Of-Charging from DC, charging can be resumed only
1939 * if DC is removed and then inserted after the battery was in use.
1940 * Therefore the handle_start_ext_chg() is not called.
1941 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1943{
1944 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001945 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001947 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001948
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001949 if (high_transition) {
1950 /* enable auto charging */
1951 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001952 pr_info("batt fell below resume voltage %s\n",
1953 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001954 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 power_supply_changed(&chip->batt_psy);
1958 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001959 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 return IRQ_HANDLED;
1962}
1963
1964static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1965{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001966 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 return IRQ_HANDLED;
1968}
1969
1970static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1971{
1972 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1973 return IRQ_HANDLED;
1974}
1975
1976static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1977{
1978 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1979 return IRQ_HANDLED;
1980}
1981
1982static irqreturn_t vcp_irq_handler(int irq, void *data)
1983{
David Keitel8c5201a2012-02-24 16:08:54 -08001984 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 return IRQ_HANDLED;
1986}
1987
1988static irqreturn_t atcdone_irq_handler(int irq, void *data)
1989{
1990 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1991 return IRQ_HANDLED;
1992}
1993
1994static irqreturn_t atcfail_irq_handler(int irq, void *data)
1995{
1996 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1997 return IRQ_HANDLED;
1998}
1999
2000static irqreturn_t chgdone_irq_handler(int irq, void *data)
2001{
2002 struct pm8921_chg_chip *chip = data;
2003
2004 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002005
2006 handle_stop_ext_chg(chip);
2007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 power_supply_changed(&chip->batt_psy);
2009 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002010 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002011
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002012 bms_notify_check(chip);
2013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 return IRQ_HANDLED;
2015}
2016
2017static irqreturn_t chgfail_irq_handler(int irq, void *data)
2018{
2019 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002020 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021
David Keitel753ec8d2011-11-02 10:56:37 -07002022 ret = pm_chg_failed_clear(chip, 1);
2023 if (ret)
2024 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2025
2026 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2027 get_prop_batt_present(chip),
2028 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2029 pm_chg_get_fsm_state(data));
2030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 power_supply_changed(&chip->batt_psy);
2032 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002033 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 return IRQ_HANDLED;
2035}
2036
2037static irqreturn_t chgstate_irq_handler(int irq, void *data)
2038{
2039 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040
2041 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2042 power_supply_changed(&chip->batt_psy);
2043 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002044 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002046 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 return IRQ_HANDLED;
2049}
2050
David Keitel8c5201a2012-02-24 16:08:54 -08002051static int param_vin_disable_counter = 5;
2052module_param(param_vin_disable_counter, int, 0644);
2053
2054static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2055 int count, int usb_ma)
2056{
2057 pm8921_charger_vbus_draw(500);
2058 pr_debug("count = %d iusb=500mA\n", count);
2059 disable_input_voltage_regulation(chip);
2060 pr_debug("count = %d disable_input_regulation\n", count);
2061
2062 msleep(20);
2063
2064 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2065 count,
2066 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2067 is_usb_chg_plugged_in(chip));
2068 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2069 count, usb_ma);
2070 enable_input_voltage_regulation(chip);
2071 pm8921_charger_vbus_draw(usb_ma);
2072}
2073
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002074#define VIN_ACTIVE_BIT BIT(0)
2075#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2076#define VIN_MIN_INCREASE_MV 100
2077static void unplug_check_worker(struct work_struct *work)
2078{
2079 struct delayed_work *dwork = to_delayed_work(work);
2080 struct pm8921_chg_chip *chip = container_of(dwork,
2081 struct pm8921_chg_chip, unplug_check_work);
2082 u8 reg_loop;
2083 int ibat, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002084 int usb_ma;
2085 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002086
2087 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2088 if (!usb_chg_plugged_in) {
2089 pr_debug("Stopping Unplug Check Worker since USB is removed"
2090 "reg_loop = %d, fsm = %d ibat = %d\n",
2091 pm_chg_get_regulation_loop(chip),
2092 pm_chg_get_fsm_state(chip),
2093 get_prop_batt_current(chip)
2094 );
2095 return;
2096 }
David Keitel8c5201a2012-02-24 16:08:54 -08002097
2098 pm_chg_iusbmax_get(chip, &usb_ma);
2099 if (usb_ma == 500) {
2100 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2101 disable_input_voltage_regulation(chip);
2102 return;
2103 }
2104
2105 if (usb_ma <= 100) {
2106 pr_debug(
2107 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2108 usb_ma);
2109 goto check_again_later;
2110 }
2111 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2112 pr_debug("chg gone irq is enabled\n");
2113
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002114 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002115 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002116
2117 if (reg_loop & VIN_ACTIVE_BIT) {
2118 ibat = get_prop_batt_current(chip);
2119
2120 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2121 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2122 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002123 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002124
David Keitel8c5201a2012-02-24 16:08:54 -08002125 while (count++ < param_vin_disable_counter
2126 && usb_chg_plugged_in == 1) {
2127 attempt_reverse_boost_fix(chip, count, usb_ma);
2128 usb_chg_plugged_in
2129 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002130 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002131 }
2132 }
2133
David Keitel8c5201a2012-02-24 16:08:54 -08002134 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2135 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2136
2137 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2138 /* run the worker directly */
2139 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2140 chg_gone, usb_chg_plugged_in);
2141 schedule_work(&chip->unplug_ovp_fet_open_work);
2142 }
2143
2144check_again_later:
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002145 schedule_delayed_work(&chip->unplug_check_work,
2146 round_jiffies_relative(msecs_to_jiffies
2147 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2148}
2149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150static irqreturn_t loop_change_irq_handler(int irq, void *data)
2151{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002152 struct pm8921_chg_chip *chip = data;
2153
2154 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2155 pm_chg_get_fsm_state(data),
2156 pm_chg_get_regulation_loop(data));
2157 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 return IRQ_HANDLED;
2159}
2160
2161static irqreturn_t fastchg_irq_handler(int irq, void *data)
2162{
2163 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002164 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002166 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2167 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2168 wake_lock(&chip->eoc_wake_lock);
2169 schedule_delayed_work(&chip->eoc_work,
2170 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002171 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002172 }
2173 power_supply_changed(&chip->batt_psy);
2174 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 return IRQ_HANDLED;
2176}
2177
2178static irqreturn_t trklchg_irq_handler(int irq, void *data)
2179{
2180 struct pm8921_chg_chip *chip = data;
2181
2182 power_supply_changed(&chip->batt_psy);
2183 return IRQ_HANDLED;
2184}
2185
2186static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2187{
2188 struct pm8921_chg_chip *chip = data;
2189 int status;
2190
2191 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2192 pr_debug("battery present=%d state=%d", !status,
2193 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002194 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 power_supply_changed(&chip->batt_psy);
2196 return IRQ_HANDLED;
2197}
2198
2199static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2200{
2201 struct pm8921_chg_chip *chip = data;
2202
Amir Samuelovd31ef502011-10-26 14:41:36 +02002203 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 power_supply_changed(&chip->batt_psy);
2205 return IRQ_HANDLED;
2206}
2207
2208static irqreturn_t chghot_irq_handler(int irq, void *data)
2209{
2210 struct pm8921_chg_chip *chip = data;
2211
2212 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2213 power_supply_changed(&chip->batt_psy);
2214 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002215 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 return IRQ_HANDLED;
2217}
2218
2219static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2220{
2221 struct pm8921_chg_chip *chip = data;
2222
2223 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002224 handle_stop_ext_chg(chip);
2225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 power_supply_changed(&chip->batt_psy);
2227 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 return IRQ_HANDLED;
2229}
2230
2231static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2232{
2233 struct pm8921_chg_chip *chip = data;
David Keitel8c5201a2012-02-24 16:08:54 -08002234 int chg_gone, usb_chg_plugged_in;
2235
2236 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2237 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2238
2239 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2240 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241
2242 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2243 power_supply_changed(&chip->batt_psy);
2244 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 return IRQ_HANDLED;
2246}
David Keitel52fda532011-11-10 10:43:44 -08002247/*
2248 *
2249 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2250 * fire for two cases:
2251 *
2252 * If the interrupt line switches to high temperature is okay
2253 * and thus charging begins.
2254 * If bat_temp_ok is low this means the temperature is now
2255 * too hot or cold, so charging is stopped.
2256 *
2257 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2259{
David Keitel52fda532011-11-10 10:43:44 -08002260 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 struct pm8921_chg_chip *chip = data;
2262
David Keitel52fda532011-11-10 10:43:44 -08002263 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2264
2265 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2266 bat_temp_ok, pm_chg_get_fsm_state(data));
2267
2268 if (bat_temp_ok)
2269 handle_start_ext_chg(chip);
2270 else
2271 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 power_supply_changed(&chip->batt_psy);
2274 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002275 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 return IRQ_HANDLED;
2277}
2278
2279static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2280{
2281 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2282 return IRQ_HANDLED;
2283}
2284
2285static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2286{
2287 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2288 return IRQ_HANDLED;
2289}
2290
2291static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2292{
2293 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2294 return IRQ_HANDLED;
2295}
2296
2297static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2298{
2299 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2300 return IRQ_HANDLED;
2301}
2302
2303static irqreturn_t batfet_irq_handler(int irq, void *data)
2304{
2305 struct pm8921_chg_chip *chip = data;
2306
2307 pr_debug("vreg ov\n");
2308 power_supply_changed(&chip->batt_psy);
2309 return IRQ_HANDLED;
2310}
2311
2312static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2313{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002314 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002315 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002316
David Keitel88e1b572012-01-11 11:57:14 -08002317 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2318 if (chip->ext_psy)
2319 power_supply_set_online(chip->ext_psy, dc_present);
2320 chip->dc_present = dc_present;
2321 if (dc_present)
2322 handle_start_ext_chg(chip);
2323 else
2324 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 return IRQ_HANDLED;
2326}
2327
2328static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2329{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002330 struct pm8921_chg_chip *chip = data;
2331
Amir Samuelovd31ef502011-10-26 14:41:36 +02002332 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 return IRQ_HANDLED;
2334}
2335
2336static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2337{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002338 struct pm8921_chg_chip *chip = data;
2339
Amir Samuelovd31ef502011-10-26 14:41:36 +02002340 handle_stop_ext_chg(chip);
2341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 return IRQ_HANDLED;
2343}
2344
David Keitel88e1b572012-01-11 11:57:14 -08002345static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2346{
2347 struct power_supply *psy = &the_chip->batt_psy;
2348 struct power_supply *epsy = dev_get_drvdata(dev);
2349 int i, dcin_irq;
2350
2351 /* Only search for external supply if none is registered */
2352 if (!the_chip->ext_psy) {
2353 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2354 for (i = 0; i < epsy->num_supplicants; i++) {
2355 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2356 if (!strncmp(epsy->name, "dc", 2)) {
2357 the_chip->ext_psy = epsy;
2358 dcin_valid_irq_handler(dcin_irq,
2359 the_chip);
2360 }
2361 }
2362 }
2363 }
2364 return 0;
2365}
2366
2367static void pm_batt_external_power_changed(struct power_supply *psy)
2368{
2369 /* Only look for an external supply if it hasn't been registered */
2370 if (!the_chip->ext_psy)
2371 class_for_each_device(power_supply_class, NULL, psy,
2372 __pm_batt_external_power_changed_work);
2373}
2374
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002375/**
2376 * update_heartbeat - internal function to update userspace
2377 * per update_time minutes
2378 *
2379 */
2380static void update_heartbeat(struct work_struct *work)
2381{
2382 struct delayed_work *dwork = to_delayed_work(work);
2383 struct pm8921_chg_chip *chip = container_of(dwork,
2384 struct pm8921_chg_chip, update_heartbeat_work);
2385
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002386 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002387 power_supply_changed(&chip->batt_psy);
2388 schedule_delayed_work(&chip->update_heartbeat_work,
2389 round_jiffies_relative(msecs_to_jiffies
2390 (chip->update_time)));
2391}
2392
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002393enum {
2394 CHG_IN_PROGRESS,
2395 CHG_NOT_IN_PROGRESS,
2396 CHG_FINISHED,
2397};
2398
2399#define VBAT_TOLERANCE_MV 70
2400#define CHG_DISABLE_MSLEEP 100
2401static int is_charging_finished(struct pm8921_chg_chip *chip)
2402{
2403 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2404 int ichg_meas_ma, iterm_programmed;
2405 int regulation_loop, fast_chg, vcp;
2406 int rc;
2407 static int last_vbat_programmed = -EINVAL;
2408
2409 if (!is_ext_charging(chip)) {
2410 /* return if the battery is not being fastcharged */
2411 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2412 pr_debug("fast_chg = %d\n", fast_chg);
2413 if (fast_chg == 0)
2414 return CHG_NOT_IN_PROGRESS;
2415
2416 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2417 pr_debug("vcp = %d\n", vcp);
2418 if (vcp == 1)
2419 return CHG_IN_PROGRESS;
2420
2421 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2422 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2423 if (vbatdet_low == 1)
2424 return CHG_IN_PROGRESS;
2425
2426 /* reset count if battery is hot/cold */
2427 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2428 pr_debug("batt_temp_ok = %d\n", rc);
2429 if (rc == 0)
2430 return CHG_IN_PROGRESS;
2431
2432 /* reset count if battery voltage is less than vddmax */
2433 vbat_meas_uv = get_prop_battery_uvolts(chip);
2434 if (vbat_meas_uv < 0)
2435 return CHG_IN_PROGRESS;
2436 vbat_meas_mv = vbat_meas_uv / 1000;
2437
2438 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2439 if (rc) {
2440 pr_err("couldnt read vddmax rc = %d\n", rc);
2441 return CHG_IN_PROGRESS;
2442 }
2443 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2444 vbat_programmed, vbat_meas_mv);
2445 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2446 return CHG_IN_PROGRESS;
2447
2448 if (last_vbat_programmed == -EINVAL)
2449 last_vbat_programmed = vbat_programmed;
2450 if (last_vbat_programmed != vbat_programmed) {
2451 /* vddmax changed, reset and check again */
2452 pr_debug("vddmax = %d last_vdd_max=%d\n",
2453 vbat_programmed, last_vbat_programmed);
2454 last_vbat_programmed = vbat_programmed;
2455 return CHG_IN_PROGRESS;
2456 }
2457
2458 /*
2459 * TODO if charging from an external charger
2460 * check SOC instead of regulation loop
2461 */
2462 regulation_loop = pm_chg_get_regulation_loop(chip);
2463 if (regulation_loop < 0) {
2464 pr_err("couldnt read the regulation loop err=%d\n",
2465 regulation_loop);
2466 return CHG_IN_PROGRESS;
2467 }
2468 pr_debug("regulation_loop=%d\n", regulation_loop);
2469
2470 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2471 return CHG_IN_PROGRESS;
2472 } /* !is_ext_charging */
2473
2474 /* reset count if battery chg current is more than iterm */
2475 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2476 if (rc) {
2477 pr_err("couldnt read iterm rc = %d\n", rc);
2478 return CHG_IN_PROGRESS;
2479 }
2480
2481 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2482 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2483 iterm_programmed, ichg_meas_ma);
2484 /*
2485 * ichg_meas_ma < 0 means battery is drawing current
2486 * ichg_meas_ma > 0 means battery is providing current
2487 */
2488 if (ichg_meas_ma > 0)
2489 return CHG_IN_PROGRESS;
2490
2491 if (ichg_meas_ma * -1 > iterm_programmed)
2492 return CHG_IN_PROGRESS;
2493
2494 return CHG_FINISHED;
2495}
2496
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002497/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002498 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002499 * has happened
2500 *
2501 * If all conditions favouring, if the charge current is
2502 * less than the term current for three consecutive times
2503 * an EOC has happened.
2504 * The wakelock is released if there is no need to reshedule
2505 * - this happens when the battery is removed or EOC has
2506 * happened
2507 */
2508#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002509static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002510{
2511 struct delayed_work *dwork = to_delayed_work(work);
2512 struct pm8921_chg_chip *chip = container_of(dwork,
2513 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002514 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002515 int end;
2516
2517 pm_chg_failed_clear(chip, 1);
2518 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002519
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002520 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002521 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002522 count = 0;
2523 wake_unlock(&chip->eoc_wake_lock);
2524 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002525 }
2526
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002527 if (end == CHG_FINISHED) {
2528 count++;
2529 } else {
2530 count = 0;
2531 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002532
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002533 if (count == CONSECUTIVE_COUNT) {
2534 count = 0;
2535 pr_info("End of Charging\n");
2536
2537 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002538
Amir Samuelovd31ef502011-10-26 14:41:36 +02002539 if (is_ext_charging(chip))
2540 chip->ext_charge_done = true;
2541
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002542 if (chip->is_bat_warm || chip->is_bat_cool)
2543 chip->bms_notify.is_battery_full = 0;
2544 else
2545 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002546 /* declare end of charging by invoking chgdone interrupt */
2547 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2548 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002549 } else {
2550 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002551 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002552 round_jiffies_relative(msecs_to_jiffies
2553 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002554 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002555}
2556
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002557static void btm_configure_work(struct work_struct *work)
2558{
2559 int rc;
2560
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002561 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002562 if (rc)
2563 pr_err("failed to configure btm rc=%d", rc);
2564}
2565
2566DECLARE_WORK(btm_config_work, btm_configure_work);
2567
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002568static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2569{
2570 unsigned int chg_current = chip->max_bat_chg_current;
2571
2572 if (chip->is_bat_cool)
2573 chg_current = min(chg_current, chip->cool_bat_chg_current);
2574
2575 if (chip->is_bat_warm)
2576 chg_current = min(chg_current, chip->warm_bat_chg_current);
2577
David Keitelfdef3a42011-12-14 19:02:54 -08002578 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002579 chg_current = min(chg_current,
2580 chip->thermal_mitigation[thermal_mitigation]);
2581
2582 pm_chg_ibatmax_set(the_chip, chg_current);
2583}
2584
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002585#define TEMP_HYSTERISIS_DEGC 2
2586static void battery_cool(bool enter)
2587{
2588 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002589 if (enter == the_chip->is_bat_cool)
2590 return;
2591 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002592 if (enter) {
2593 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002594 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002595 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002596 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002597 pm_chg_vbatdet_set(the_chip,
2598 the_chip->cool_bat_voltage
2599 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002600 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002601 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002602 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002603 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002604 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002605 the_chip->max_voltage_mv
2606 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002607 }
2608 schedule_work(&btm_config_work);
2609}
2610
2611static void battery_warm(bool enter)
2612{
2613 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002614 if (enter == the_chip->is_bat_warm)
2615 return;
2616 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002617 if (enter) {
2618 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002619 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002620 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002621 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002622 pm_chg_vbatdet_set(the_chip,
2623 the_chip->warm_bat_voltage
2624 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002625 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002626 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002627 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002628 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002629 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002630 the_chip->max_voltage_mv
2631 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002632 }
2633 schedule_work(&btm_config_work);
2634}
2635
2636static int configure_btm(struct pm8921_chg_chip *chip)
2637{
2638 int rc;
2639
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002640 if (chip->warm_temp_dc != INT_MIN)
2641 btm_config.btm_warm_fn = battery_warm;
2642 else
2643 btm_config.btm_warm_fn = NULL;
2644
2645 if (chip->cool_temp_dc != INT_MIN)
2646 btm_config.btm_cool_fn = battery_cool;
2647 else
2648 btm_config.btm_cool_fn = NULL;
2649
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002650 btm_config.low_thr_temp = chip->cool_temp_dc;
2651 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002652 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002653 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002654 if (rc)
2655 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002656 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002657 if (rc)
2658 pr_err("failed to start btm rc = %d\n", rc);
2659
2660 return rc;
2661}
2662
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002663/**
2664 * set_disable_status_param -
2665 *
2666 * Internal function to disable battery charging and also disable drawing
2667 * any current from the source. The device is forced to run on a battery
2668 * after this.
2669 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670static int set_disable_status_param(const char *val, struct kernel_param *kp)
2671{
2672 int ret;
2673 struct pm8921_chg_chip *chip = the_chip;
2674
2675 ret = param_set_int(val, kp);
2676 if (ret) {
2677 pr_err("error setting value %d\n", ret);
2678 return ret;
2679 }
2680 pr_info("factory set disable param to %d\n", charging_disabled);
2681 if (chip) {
2682 pm_chg_auto_enable(chip, !charging_disabled);
2683 pm_chg_charge_dis(chip, charging_disabled);
2684 }
2685 return 0;
2686}
2687module_param_call(disabled, set_disable_status_param, param_get_uint,
2688 &charging_disabled, 0644);
2689
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002690/**
2691 * set_thermal_mitigation_level -
2692 *
2693 * Internal function to control battery charging current to reduce
2694 * temperature
2695 */
2696static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2697{
2698 int ret;
2699 struct pm8921_chg_chip *chip = the_chip;
2700
2701 ret = param_set_int(val, kp);
2702 if (ret) {
2703 pr_err("error setting value %d\n", ret);
2704 return ret;
2705 }
2706
2707 if (!chip) {
2708 pr_err("called before init\n");
2709 return -EINVAL;
2710 }
2711
2712 if (!chip->thermal_mitigation) {
2713 pr_err("no thermal mitigation\n");
2714 return -EINVAL;
2715 }
2716
2717 if (thermal_mitigation < 0
2718 || thermal_mitigation >= chip->thermal_levels) {
2719 pr_err("out of bound level selected\n");
2720 return -EINVAL;
2721 }
2722
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002723 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002724 return ret;
2725}
2726module_param_call(thermal_mitigation, set_therm_mitigation_level,
2727 param_get_uint,
2728 &thermal_mitigation, 0644);
2729
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002730static int set_usb_max_current(const char *val, struct kernel_param *kp)
2731{
2732 int ret, mA;
2733 struct pm8921_chg_chip *chip = the_chip;
2734
2735 ret = param_set_int(val, kp);
2736 if (ret) {
2737 pr_err("error setting value %d\n", ret);
2738 return ret;
2739 }
2740 if (chip) {
2741 pr_warn("setting current max to %d\n", usb_max_current);
2742 pm_chg_iusbmax_get(chip, &mA);
2743 if (mA > usb_max_current)
2744 pm8921_charger_vbus_draw(usb_max_current);
2745 return 0;
2746 }
2747 return -EINVAL;
2748}
2749module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2750 &usb_max_current, 0644);
2751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002752static void free_irqs(struct pm8921_chg_chip *chip)
2753{
2754 int i;
2755
2756 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2757 if (chip->pmic_chg_irq[i]) {
2758 free_irq(chip->pmic_chg_irq[i], chip);
2759 chip->pmic_chg_irq[i] = 0;
2760 }
2761}
2762
David Keitel88e1b572012-01-11 11:57:14 -08002763/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2765{
2766 unsigned long flags;
2767 int fsm_state;
2768
2769 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2770 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2771
2772 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002773 if (chip->usb_present) {
2774 schedule_delayed_work(&chip->unplug_check_work,
2775 round_jiffies_relative(msecs_to_jiffies
2776 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002777 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002778 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779
2780 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2781 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2782 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002783 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2784 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2785 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2786 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2787 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002788 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002789 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2790 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002791 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792
2793 spin_lock_irqsave(&vbus_lock, flags);
2794 if (usb_chg_current) {
2795 /* reissue a vbus draw call */
2796 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002797 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 }
2799 spin_unlock_irqrestore(&vbus_lock, flags);
2800
2801 fsm_state = pm_chg_get_fsm_state(chip);
2802 if (is_battery_charging(fsm_state)) {
2803 chip->bms_notify.is_charging = 1;
2804 pm8921_bms_charging_began();
2805 }
2806
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002807 check_battery_valid(chip);
2808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002809 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2810 chip->usb_present,
2811 chip->dc_present,
2812 get_prop_batt_present(chip),
2813 fsm_state);
2814}
2815
2816struct pm_chg_irq_init_data {
2817 unsigned int irq_id;
2818 char *name;
2819 unsigned long flags;
2820 irqreturn_t (*handler)(int, void *);
2821};
2822
2823#define CHG_IRQ(_id, _flags, _handler) \
2824{ \
2825 .irq_id = _id, \
2826 .name = #_id, \
2827 .flags = _flags, \
2828 .handler = _handler, \
2829}
2830struct pm_chg_irq_init_data chg_irq_data[] = {
2831 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2832 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002833 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002834 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2835 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002836 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2837 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2839 usbin_uv_irq_handler),
2840 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2841 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2842 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2843 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2844 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2845 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2846 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2847 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2848 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002849 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2850 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2852 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2853 batt_removed_irq_handler),
2854 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2855 batttemp_hot_irq_handler),
2856 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2857 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2858 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08002859 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2860 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002861 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2862 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2864 coarse_det_low_irq_handler),
2865 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2866 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2867 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2868 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2869 batfet_irq_handler),
2870 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2871 dcin_valid_irq_handler),
2872 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2873 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002874 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875};
2876
2877static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2878 struct platform_device *pdev)
2879{
2880 struct resource *res;
2881 int ret, i;
2882
2883 ret = 0;
2884 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2885
2886 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2887 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2888 chg_irq_data[i].name);
2889 if (res == NULL) {
2890 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2891 goto err_out;
2892 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002893 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 ret = request_irq(res->start, chg_irq_data[i].handler,
2895 chg_irq_data[i].flags,
2896 chg_irq_data[i].name, chip);
2897 if (ret < 0) {
2898 pr_err("couldn't request %d (%s) %d\n", res->start,
2899 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002900 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002901 goto err_out;
2902 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002903 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2904 }
2905 return 0;
2906
2907err_out:
2908 free_irqs(chip);
2909 return -EINVAL;
2910}
2911
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002912static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2913{
2914 int err;
2915 u8 temp;
2916
2917 temp = 0xD1;
2918 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2919 if (err) {
2920 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2921 return;
2922 }
2923
2924 temp = 0xD3;
2925 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2926 if (err) {
2927 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2928 return;
2929 }
2930
2931 temp = 0xD1;
2932 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2933 if (err) {
2934 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2935 return;
2936 }
2937
2938 temp = 0xD5;
2939 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2940 if (err) {
2941 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2942 return;
2943 }
2944
2945 udelay(183);
2946
2947 temp = 0xD1;
2948 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2949 if (err) {
2950 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2951 return;
2952 }
2953
2954 temp = 0xD0;
2955 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2956 if (err) {
2957 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2958 return;
2959 }
2960 udelay(32);
2961
2962 temp = 0xD1;
2963 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2964 if (err) {
2965 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2966 return;
2967 }
2968
2969 temp = 0xD3;
2970 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2971 if (err) {
2972 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2973 return;
2974 }
2975}
2976
2977static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2978{
2979 int err;
2980 u8 temp;
2981
2982 temp = 0xD1;
2983 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2984 if (err) {
2985 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2986 return;
2987 }
2988
2989 temp = 0xD0;
2990 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2991 if (err) {
2992 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2993 return;
2994 }
2995}
2996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997#define ENUM_TIMER_STOP_BIT BIT(1)
2998#define BOOT_DONE_BIT BIT(6)
2999#define CHG_BATFET_ON_BIT BIT(3)
3000#define CHG_VCP_EN BIT(0)
3001#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3002#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003003#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3005{
3006 int rc;
3007
3008 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3009 BOOT_DONE_BIT, BOOT_DONE_BIT);
3010 if (rc) {
3011 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3012 return rc;
3013 }
3014
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003015 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003016 if (rc) {
3017 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003018 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 return rc;
3020 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003021 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003022 chip->max_voltage_mv
3023 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 if (rc) {
3025 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003026 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 return rc;
3028 }
3029
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003030 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 if (rc) {
3032 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003033 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 return rc;
3035 }
3036 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3037 if (rc) {
3038 pr_err("Failed to set max voltage to %d rc=%d\n",
3039 SAFE_CURRENT_MA, rc);
3040 return rc;
3041 }
3042
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003043 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044 if (rc) {
3045 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3046 return rc;
3047 }
3048
3049 rc = pm_chg_iterm_set(chip, chip->term_current);
3050 if (rc) {
3051 pr_err("Failed to set term current to %d rc=%d\n",
3052 chip->term_current, rc);
3053 return rc;
3054 }
3055
3056 /* Disable the ENUM TIMER */
3057 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3058 ENUM_TIMER_STOP_BIT);
3059 if (rc) {
3060 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3061 return rc;
3062 }
3063
3064 /* init with the lowest USB current */
3065 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
3066 if (rc) {
3067 pr_err("Failed to set usb max to %d rc=%d\n",
3068 usb_ma_table[0].chg_iusb_value, rc);
3069 return rc;
3070 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003071
3072 if (chip->safety_time != 0) {
3073 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3074 if (rc) {
3075 pr_err("Failed to set max time to %d minutes rc=%d\n",
3076 chip->safety_time, rc);
3077 return rc;
3078 }
3079 }
3080
3081 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003082 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003083 if (rc) {
3084 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3085 chip->safety_time, rc);
3086 return rc;
3087 }
3088 }
3089
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003090 if (chip->vin_min != 0) {
3091 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3092 if (rc) {
3093 pr_err("Failed to set vin min to %d mV rc=%d\n",
3094 chip->vin_min, rc);
3095 return rc;
3096 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003097 } else {
3098 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003099 }
3100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 rc = pm_chg_disable_wd(chip);
3102 if (rc) {
3103 pr_err("Failed to disable wd rc=%d\n", rc);
3104 return rc;
3105 }
3106
3107 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3108 CHG_BAT_TEMP_DIS_BIT, 0);
3109 if (rc) {
3110 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3111 return rc;
3112 }
3113 /* switch to a 3.2Mhz for the buck */
3114 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3115 if (rc) {
3116 pr_err("Failed to switch buck clk rc=%d\n", rc);
3117 return rc;
3118 }
3119
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003120 if (chip->trkl_voltage != 0) {
3121 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3122 if (rc) {
3123 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3124 chip->trkl_voltage, rc);
3125 return rc;
3126 }
3127 }
3128
3129 if (chip->weak_voltage != 0) {
3130 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3131 if (rc) {
3132 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3133 chip->weak_voltage, rc);
3134 return rc;
3135 }
3136 }
3137
3138 if (chip->trkl_current != 0) {
3139 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3140 if (rc) {
3141 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3142 chip->trkl_voltage, rc);
3143 return rc;
3144 }
3145 }
3146
3147 if (chip->weak_current != 0) {
3148 rc = pm_chg_iweak_set(chip, chip->weak_current);
3149 if (rc) {
3150 pr_err("Failed to set weak current to %dmA rc=%d\n",
3151 chip->weak_current, rc);
3152 return rc;
3153 }
3154 }
3155
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003156 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3157 if (rc) {
3158 pr_err("Failed to set cold config %d rc=%d\n",
3159 chip->cold_thr, rc);
3160 }
3161
3162 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3163 if (rc) {
3164 pr_err("Failed to set hot config %d rc=%d\n",
3165 chip->hot_thr, rc);
3166 }
3167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003168 /* Workarounds for die 1.1 and 1.0 */
3169 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3170 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003171 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3172 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003173
3174 /* software workaround for correct battery_id detection */
3175 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3176 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3177 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3178 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3179 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3180 udelay(100);
3181 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182 }
3183
David Keitelb51995e2011-11-18 17:03:31 -08003184 /* Workarounds for die 3.0 */
3185 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3186 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3187
3188 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3189
David Keitela3c0d822011-11-03 14:18:52 -07003190 /* Disable EOC FSM processing */
3191 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3192
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003193 pm8921_chg_force_19p2mhz_clk(chip);
3194
3195 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3196 VREF_BATT_THERM_FORCE_ON);
3197 if (rc)
3198 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 rc = pm_chg_charge_dis(chip, charging_disabled);
3201 if (rc) {
3202 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3203 return rc;
3204 }
3205
3206 rc = pm_chg_auto_enable(chip, !charging_disabled);
3207 if (rc) {
3208 pr_err("Failed to enable charging rc=%d\n", rc);
3209 return rc;
3210 }
3211
3212 return 0;
3213}
3214
3215static int get_rt_status(void *data, u64 * val)
3216{
3217 int i = (int)data;
3218 int ret;
3219
3220 /* global irq number is passed in via data */
3221 ret = pm_chg_get_rt_status(the_chip, i);
3222 *val = ret;
3223 return 0;
3224}
3225DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3226
3227static int get_fsm_status(void *data, u64 * val)
3228{
3229 u8 temp;
3230
3231 temp = pm_chg_get_fsm_state(the_chip);
3232 *val = temp;
3233 return 0;
3234}
3235DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3236
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003237static int get_reg_loop(void *data, u64 * val)
3238{
3239 u8 temp;
3240
3241 if (!the_chip) {
3242 pr_err("%s called before init\n", __func__);
3243 return -EINVAL;
3244 }
3245 temp = pm_chg_get_regulation_loop(the_chip);
3246 *val = temp;
3247 return 0;
3248}
3249DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003251static int get_reg(void *data, u64 * val)
3252{
3253 int addr = (int)data;
3254 int ret;
3255 u8 temp;
3256
3257 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3258 if (ret) {
3259 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3260 addr, temp, ret);
3261 return -EAGAIN;
3262 }
3263 *val = temp;
3264 return 0;
3265}
3266
3267static int set_reg(void *data, u64 val)
3268{
3269 int addr = (int)data;
3270 int ret;
3271 u8 temp;
3272
3273 temp = (u8) val;
3274 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3275 if (ret) {
3276 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3277 addr, temp, ret);
3278 return -EAGAIN;
3279 }
3280 return 0;
3281}
3282DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3283
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003284enum {
3285 BAT_WARM_ZONE,
3286 BAT_COOL_ZONE,
3287};
3288static int get_warm_cool(void *data, u64 * val)
3289{
3290 if (!the_chip) {
3291 pr_err("%s called before init\n", __func__);
3292 return -EINVAL;
3293 }
3294 if ((int)data == BAT_WARM_ZONE)
3295 *val = the_chip->is_bat_warm;
3296 if ((int)data == BAT_COOL_ZONE)
3297 *val = the_chip->is_bat_cool;
3298 return 0;
3299}
3300DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003302static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3303{
3304 int i;
3305
3306 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3307
3308 if (IS_ERR(chip->dent)) {
3309 pr_err("pmic charger couldnt create debugfs dir\n");
3310 return;
3311 }
3312
3313 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3314 (void *)CHG_CNTRL, &reg_fops);
3315 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3316 (void *)CHG_CNTRL_2, &reg_fops);
3317 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3318 (void *)CHG_CNTRL_3, &reg_fops);
3319 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3320 (void *)PBL_ACCESS1, &reg_fops);
3321 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3322 (void *)PBL_ACCESS2, &reg_fops);
3323 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3324 (void *)SYS_CONFIG_1, &reg_fops);
3325 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3326 (void *)SYS_CONFIG_2, &reg_fops);
3327 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3328 (void *)CHG_VDD_MAX, &reg_fops);
3329 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3330 (void *)CHG_VDD_SAFE, &reg_fops);
3331 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3332 (void *)CHG_VBAT_DET, &reg_fops);
3333 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3334 (void *)CHG_IBAT_MAX, &reg_fops);
3335 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3336 (void *)CHG_IBAT_SAFE, &reg_fops);
3337 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3338 (void *)CHG_VIN_MIN, &reg_fops);
3339 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3340 (void *)CHG_VTRICKLE, &reg_fops);
3341 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3342 (void *)CHG_ITRICKLE, &reg_fops);
3343 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3344 (void *)CHG_ITERM, &reg_fops);
3345 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3346 (void *)CHG_TCHG_MAX, &reg_fops);
3347 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3348 (void *)CHG_TWDOG, &reg_fops);
3349 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3350 (void *)CHG_TEMP_THRESH, &reg_fops);
3351 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3352 (void *)CHG_COMP_OVR, &reg_fops);
3353 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3354 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3355 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3356 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3357 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3358 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3359 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3360 (void *)CHG_TEST, &reg_fops);
3361
3362 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3363 &fsm_fops);
3364
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003365 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3366 &reg_loop_fops);
3367
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003368 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3369 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3370 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3371 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3372
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3374 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3375 debugfs_create_file(chg_irq_data[i].name, 0444,
3376 chip->dent,
3377 (void *)chg_irq_data[i].irq_id,
3378 &rt_fops);
3379 }
3380}
3381
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003382static int pm8921_charger_suspend_noirq(struct device *dev)
3383{
3384 int rc;
3385 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3386
3387 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3388 if (rc)
3389 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3390 pm8921_chg_set_hw_clk_switching(chip);
3391 return 0;
3392}
3393
3394static int pm8921_charger_resume_noirq(struct device *dev)
3395{
3396 int rc;
3397 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3398
3399 pm8921_chg_force_19p2mhz_clk(chip);
3400
3401 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3402 VREF_BATT_THERM_FORCE_ON);
3403 if (rc)
3404 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3405 return 0;
3406}
3407
David Keitelf2226022011-12-13 15:55:50 -08003408static int pm8921_charger_resume(struct device *dev)
3409{
3410 int rc;
3411 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3412
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003413 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003414 && !(chip->keep_btm_on_suspend)) {
3415 rc = pm8xxx_adc_btm_configure(&btm_config);
3416 if (rc)
3417 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3418
3419 rc = pm8xxx_adc_btm_start();
3420 if (rc)
3421 pr_err("couldn't restart btm rc=%d\n", rc);
3422 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003423 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3424 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3425 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3426 }
David Keitelf2226022011-12-13 15:55:50 -08003427 return 0;
3428}
3429
3430static int pm8921_charger_suspend(struct device *dev)
3431{
3432 int rc;
3433 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3434
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003435 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003436 && !(chip->keep_btm_on_suspend)) {
3437 rc = pm8xxx_adc_btm_end();
3438 if (rc)
3439 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3440 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003441
3442 if (is_usb_chg_plugged_in(chip)) {
3443 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3444 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3445 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003446
David Keitelf2226022011-12-13 15:55:50 -08003447 return 0;
3448}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003449static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3450{
3451 int rc = 0;
3452 struct pm8921_chg_chip *chip;
3453 const struct pm8921_charger_platform_data *pdata
3454 = pdev->dev.platform_data;
3455
3456 if (!pdata) {
3457 pr_err("missing platform data\n");
3458 return -EINVAL;
3459 }
3460
3461 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3462 GFP_KERNEL);
3463 if (!chip) {
3464 pr_err("Cannot allocate pm_chg_chip\n");
3465 return -ENOMEM;
3466 }
3467
3468 chip->dev = &pdev->dev;
3469 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003470 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003472 chip->max_voltage_mv = pdata->max_voltage;
3473 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003474 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003475 chip->term_current = pdata->term_current;
3476 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003477 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003478 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3479 chip->batt_id_min = pdata->batt_id_min;
3480 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003481 if (pdata->cool_temp != INT_MIN)
3482 chip->cool_temp_dc = pdata->cool_temp * 10;
3483 else
3484 chip->cool_temp_dc = INT_MIN;
3485
3486 if (pdata->warm_temp != INT_MIN)
3487 chip->warm_temp_dc = pdata->warm_temp * 10;
3488 else
3489 chip->warm_temp_dc = INT_MIN;
3490
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003491 chip->temp_check_period = pdata->temp_check_period;
3492 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3493 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3494 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3495 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3496 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003497 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003498 chip->trkl_voltage = pdata->trkl_voltage;
3499 chip->weak_voltage = pdata->weak_voltage;
3500 chip->trkl_current = pdata->trkl_current;
3501 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003502 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003503 chip->thermal_mitigation = pdata->thermal_mitigation;
3504 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003506 chip->cold_thr = pdata->cold_thr;
3507 chip->hot_thr = pdata->hot_thr;
3508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003509 rc = pm8921_chg_hw_init(chip);
3510 if (rc) {
3511 pr_err("couldn't init hardware rc=%d\n", rc);
3512 goto free_chip;
3513 }
3514
3515 chip->usb_psy.name = "usb",
3516 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3517 chip->usb_psy.supplied_to = pm_power_supplied_to,
3518 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003519 chip->usb_psy.properties = pm_power_props_usb,
3520 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3521 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003522
David Keitel6ed71a52012-01-30 12:42:18 -08003523 chip->dc_psy.name = "pm8921-dc",
3524 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3525 chip->dc_psy.supplied_to = pm_power_supplied_to,
3526 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003527 chip->dc_psy.properties = pm_power_props_mains,
3528 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3529 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 chip->batt_psy.name = "battery",
3532 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3533 chip->batt_psy.properties = msm_batt_power_props,
3534 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3535 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003536 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003537 rc = power_supply_register(chip->dev, &chip->usb_psy);
3538 if (rc < 0) {
3539 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003540 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 }
3542
David Keitel6ed71a52012-01-30 12:42:18 -08003543 rc = power_supply_register(chip->dev, &chip->dc_psy);
3544 if (rc < 0) {
3545 pr_err("power_supply_register usb failed rc = %d\n", rc);
3546 goto unregister_usb;
3547 }
3548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549 rc = power_supply_register(chip->dev, &chip->batt_psy);
3550 if (rc < 0) {
3551 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003552 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003553 }
3554
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003555 platform_set_drvdata(pdev, chip);
3556 the_chip = chip;
3557
3558 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
David Keitel8c5201a2012-02-24 16:08:54 -08003559 wake_lock_init(&chip->unplug_ovp_fet_open_wake_lock,
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003560 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003561 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003562 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3563 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003564 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003566 rc = request_irqs(chip, pdev);
3567 if (rc) {
3568 pr_err("couldn't register interrupts rc=%d\n", rc);
3569 goto unregister_batt;
3570 }
3571
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003572 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3573 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3574 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003575 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3576 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003577 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003578 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003579 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003580 * care for jeita compliance
3581 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003582 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003583 rc = configure_btm(chip);
3584 if (rc) {
3585 pr_err("couldn't register with btm rc=%d\n", rc);
3586 goto free_irq;
3587 }
3588 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590 create_debugfs_entries(chip);
3591
3592 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003593 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595 /* determine what state the charger is in */
3596 determine_initial_state(chip);
3597
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003598 if (chip->update_time) {
3599 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3600 update_heartbeat);
3601 schedule_delayed_work(&chip->update_heartbeat_work,
3602 round_jiffies_relative(msecs_to_jiffies
3603 (chip->update_time)));
3604 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605 return 0;
3606
3607free_irq:
3608 free_irqs(chip);
3609unregister_batt:
3610 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003611unregister_dc:
3612 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613unregister_usb:
3614 power_supply_unregister(&chip->usb_psy);
3615free_chip:
3616 kfree(chip);
3617 return rc;
3618}
3619
3620static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3621{
3622 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3623
3624 free_irqs(chip);
3625 platform_set_drvdata(pdev, NULL);
3626 the_chip = NULL;
3627 kfree(chip);
3628 return 0;
3629}
David Keitelf2226022011-12-13 15:55:50 -08003630static const struct dev_pm_ops pm8921_pm_ops = {
3631 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003632 .suspend_noirq = pm8921_charger_suspend_noirq,
3633 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003634 .resume = pm8921_charger_resume,
3635};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003637 .probe = pm8921_charger_probe,
3638 .remove = __devexit_p(pm8921_charger_remove),
3639 .driver = {
3640 .name = PM8921_CHARGER_DEV_NAME,
3641 .owner = THIS_MODULE,
3642 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003643 },
3644};
3645
3646static int __init pm8921_charger_init(void)
3647{
3648 return platform_driver_register(&pm8921_charger_driver);
3649}
3650
3651static void __exit pm8921_charger_exit(void)
3652{
3653 platform_driver_unregister(&pm8921_charger_driver);
3654}
3655
3656late_initcall(pm8921_charger_init);
3657module_exit(pm8921_charger_exit);
3658
3659MODULE_LICENSE("GPL v2");
3660MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3661MODULE_VERSION("1.0");
3662MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);