blob: cdc6c506e53a515209c9ec0eb0420f90f90cc798 [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 Keitelacf57c82012-03-07 18:48:50 -0800261 struct delayed_work vin_collapse_check_work;
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;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800265 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700266 enum pm8921_chg_led_src_config led_src_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267};
268
David Keitelacf57c82012-03-07 18:48:50 -0800269/* user space parameter to limit usb current */
270static unsigned int usb_max_current;
271/*
272 * usb_target_ma is used for wall charger
273 * adaptive input current limiting only. Use
274 * pm_iusbmax_get() to get current maximum usb current setting.
275 */
276static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700278static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279
280static struct pm8921_chg_chip *the_chip;
281
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700282static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
285 u8 mask, u8 val)
286{
287 int rc;
288 u8 reg;
289
290 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
291 if (rc) {
292 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
293 return rc;
294 }
295 reg &= ~mask;
296 reg |= val & mask;
297 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
298 if (rc) {
299 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
300 return rc;
301 }
302 return 0;
303}
304
David Keitelcf867232012-01-27 18:40:12 -0800305static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
306{
307 return pm8xxx_read_irq_stat(chip->dev->parent,
308 chip->pmic_chg_irq[irq_id]);
309}
310
311/* Treat OverVoltage/UnderVoltage as source missing */
312static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
313{
314 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
315}
316
317/* Treat OverVoltage/UnderVoltage as source missing */
318static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
319{
320 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
321}
322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323#define CAPTURE_FSM_STATE_CMD 0xC2
324#define READ_BANK_7 0x70
325#define READ_BANK_4 0x40
326static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
327{
328 u8 temp;
329 int err, ret = 0;
330
331 temp = CAPTURE_FSM_STATE_CMD;
332 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
333 if (err) {
334 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
335 return err;
336 }
337
338 temp = READ_BANK_7;
339 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
340 if (err) {
341 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
342 return err;
343 }
344
345 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
346 if (err) {
347 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
348 return err;
349 }
350 /* get the lower 4 bits */
351 ret = temp & 0xF;
352
353 temp = READ_BANK_4;
354 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
355 if (err) {
356 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
357 return err;
358 }
359
360 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
361 if (err) {
362 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
363 return err;
364 }
365 /* get the upper 1 bit */
366 ret |= (temp & 0x1) << 4;
367 return ret;
368}
369
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700370#define READ_BANK_6 0x60
371static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
372{
373 u8 temp;
374 int err;
375
376 temp = READ_BANK_6;
377 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
378 if (err) {
379 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
380 return err;
381 }
382
383 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
384 if (err) {
385 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
386 return err;
387 }
388
389 /* return the lower 4 bits */
390 return temp & CHG_ALL_LOOPS;
391}
392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393#define CHG_USB_SUSPEND_BIT BIT(2)
394static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
395{
396 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
397 enable ? CHG_USB_SUSPEND_BIT : 0);
398}
399
400#define CHG_EN_BIT BIT(7)
401static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
402{
403 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
404 enable ? CHG_EN_BIT : 0);
405}
406
David Keitel753ec8d2011-11-02 10:56:37 -0700407#define CHG_FAILED_CLEAR BIT(0)
408#define ATC_FAILED_CLEAR BIT(1)
409static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
410{
411 int rc;
412
413 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
414 clear ? ATC_FAILED_CLEAR : 0);
415 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
416 clear ? CHG_FAILED_CLEAR : 0);
417 return rc;
418}
419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420#define CHG_CHARGE_DIS_BIT BIT(1)
421static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
422{
423 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
424 disable ? CHG_CHARGE_DIS_BIT : 0);
425}
426
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800427static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
428{
429 u8 temp;
430
431 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
432 return temp & CHG_CHARGE_DIS_BIT;
433}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434#define PM8921_CHG_V_MIN_MV 3240
435#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800436#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437#define PM8921_CHG_VDDMAX_MAX 4500
438#define PM8921_CHG_VDDMAX_MIN 3400
439#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800440static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800442 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800443 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800445 if (voltage < PM8921_CHG_VDDMAX_MIN
446 || voltage > PM8921_CHG_VDDMAX_MAX) {
447 pr_err("bad mV=%d asked to set\n", voltage);
448 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 }
David Keitelcf867232012-01-27 18:40:12 -0800450
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800451 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
452
453 remainder = voltage % 20;
454 if (remainder >= 10) {
455 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
456 }
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800459 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460}
461
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700462static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
463{
464 u8 temp;
465 int rc;
466
467 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
468 if (rc) {
469 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700470 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700471 return rc;
472 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800473 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
474 + PM8921_CHG_V_MIN_MV;
475 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
476 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700477 return 0;
478}
479
David Keitelcf867232012-01-27 18:40:12 -0800480static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
481{
482 int current_mv, ret, steps, i;
483 bool increase;
484
485 ret = 0;
486
487 if (voltage < PM8921_CHG_VDDMAX_MIN
488 || voltage > PM8921_CHG_VDDMAX_MAX) {
489 pr_err("bad mV=%d asked to set\n", voltage);
490 return -EINVAL;
491 }
492
493 ret = pm_chg_vddmax_get(chip, &current_mv);
494 if (ret) {
495 pr_err("Failed to read vddmax rc=%d\n", ret);
496 return -EINVAL;
497 }
498 if (current_mv == voltage)
499 return 0;
500
501 /* Only change in increments when USB is present */
502 if (is_usb_chg_plugged_in(chip)) {
503 if (current_mv < voltage) {
504 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
505 increase = true;
506 } else {
507 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
508 increase = false;
509 }
510 for (i = 0; i < steps; i++) {
511 if (increase)
512 current_mv += PM8921_CHG_V_STEP_MV;
513 else
514 current_mv -= PM8921_CHG_V_STEP_MV;
515 ret |= __pm_chg_vddmax_set(chip, current_mv);
516 }
517 }
518 ret |= __pm_chg_vddmax_set(chip, voltage);
519 return ret;
520}
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522#define PM8921_CHG_VDDSAFE_MIN 3400
523#define PM8921_CHG_VDDSAFE_MAX 4500
524static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
525{
526 u8 temp;
527
528 if (voltage < PM8921_CHG_VDDSAFE_MIN
529 || voltage > PM8921_CHG_VDDSAFE_MAX) {
530 pr_err("bad mV=%d asked to set\n", voltage);
531 return -EINVAL;
532 }
533 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
534 pr_debug("voltage=%d setting %02x\n", voltage, temp);
535 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
536}
537
538#define PM8921_CHG_VBATDET_MIN 3240
539#define PM8921_CHG_VBATDET_MAX 5780
540static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
541{
542 u8 temp;
543
544 if (voltage < PM8921_CHG_VBATDET_MIN
545 || voltage > PM8921_CHG_VBATDET_MAX) {
546 pr_err("bad mV=%d asked to set\n", voltage);
547 return -EINVAL;
548 }
549 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
550 pr_debug("voltage=%d setting %02x\n", voltage, temp);
551 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
552}
553
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700554#define PM8921_CHG_VINMIN_MIN_MV 3800
555#define PM8921_CHG_VINMIN_STEP_MV 100
556#define PM8921_CHG_VINMIN_USABLE_MAX 6500
557#define PM8921_CHG_VINMIN_USABLE_MIN 4300
558#define PM8921_CHG_VINMIN_MASK 0x1F
559static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
560{
561 u8 temp;
562
563 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
564 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
565 pr_err("bad mV=%d asked to set\n", voltage);
566 return -EINVAL;
567 }
568 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
569 pr_debug("voltage=%d setting %02x\n", voltage, temp);
570 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
571 temp);
572}
573
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800574static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
575{
576 u8 temp;
577 int rc, voltage_mv;
578
579 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
580 temp &= PM8921_CHG_VINMIN_MASK;
581
582 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
583 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
584
585 return voltage_mv;
586}
587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588#define PM8921_CHG_IBATMAX_MIN 325
589#define PM8921_CHG_IBATMAX_MAX 2000
590#define PM8921_CHG_I_MIN_MA 225
591#define PM8921_CHG_I_STEP_MA 50
592#define PM8921_CHG_I_MASK 0x3F
593static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
594{
595 u8 temp;
596
597 if (chg_current < PM8921_CHG_IBATMAX_MIN
598 || chg_current > PM8921_CHG_IBATMAX_MAX) {
599 pr_err("bad mA=%d asked to set\n", chg_current);
600 return -EINVAL;
601 }
602 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
603 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
604}
605
606#define PM8921_CHG_IBATSAFE_MIN 225
607#define PM8921_CHG_IBATSAFE_MAX 3375
608static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
609{
610 u8 temp;
611
612 if (chg_current < PM8921_CHG_IBATSAFE_MIN
613 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
614 pr_err("bad mA=%d asked to set\n", chg_current);
615 return -EINVAL;
616 }
617 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
618 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
619 PM8921_CHG_I_MASK, temp);
620}
621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700623#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624#define PM8921_CHG_ITERM_STEP_MA 10
625#define PM8921_CHG_ITERM_MASK 0xF
626static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
627{
628 u8 temp;
629
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700630 if (chg_current < PM8921_CHG_ITERM_MIN_MA
631 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 pr_err("bad mA=%d asked to set\n", chg_current);
633 return -EINVAL;
634 }
635
636 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
637 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700638 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 temp);
640}
641
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700642static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
643{
644 u8 temp;
645 int rc;
646
647 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
648 if (rc) {
649 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700650 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700651 return rc;
652 }
653 temp &= PM8921_CHG_ITERM_MASK;
654 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
655 + PM8921_CHG_ITERM_MIN_MA;
656 return 0;
657}
658
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800659struct usb_ma_limit_entry {
660 int usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800661};
662
663static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitelacf57c82012-03-07 18:48:50 -0800664 {100},
665 {500},
666 {700},
667 {850},
668 {900},
669 {1100},
670 {1300},
671 {1500},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800672};
673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674#define PM8921_CHG_IUSB_MASK 0x1C
675#define PM8921_CHG_IUSB_MAX 7
676#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700677static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678{
679 u8 temp;
680
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700681 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
682 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 return -EINVAL;
684 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700685 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
687 temp);
688}
689
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800690static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
691{
692 u8 temp;
David Keitelacf57c82012-03-07 18:48:50 -0800693 int rc;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800694
695 *mA = 0;
696 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
697 if (rc) {
698 pr_err("err=%d reading PBL_ACCESS2\n", rc);
699 return rc;
700 }
701 temp &= PM8921_CHG_IUSB_MASK;
702 temp = temp >> 2;
David Keitelacf57c82012-03-07 18:48:50 -0800703 *mA = usb_ma_table[temp].usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800704 return rc;
705}
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707#define PM8921_CHG_WD_MASK 0x1F
708static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
709{
710 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700711 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
712}
713
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700714#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700715#define PM8921_CHG_TCHG_MIN 4
716#define PM8921_CHG_TCHG_MAX 512
717#define PM8921_CHG_TCHG_STEP 4
718static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
719{
720 u8 temp;
721
722 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
723 pr_err("bad max minutes =%d asked to set\n", minutes);
724 return -EINVAL;
725 }
726
727 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
728 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
729 temp);
730}
731
732#define PM8921_CHG_TTRKL_MASK 0x1F
733#define PM8921_CHG_TTRKL_MIN 1
734#define PM8921_CHG_TTRKL_MAX 64
735static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
736{
737 u8 temp;
738
739 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
740 pr_err("bad max minutes =%d asked to set\n", minutes);
741 return -EINVAL;
742 }
743
744 temp = minutes - 1;
745 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
746 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747}
748
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700749#define PM8921_CHG_VTRKL_MIN_MV 2050
750#define PM8921_CHG_VTRKL_MAX_MV 2800
751#define PM8921_CHG_VTRKL_STEP_MV 50
752#define PM8921_CHG_VTRKL_SHIFT 4
753#define PM8921_CHG_VTRKL_MASK 0xF0
754static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
755{
756 u8 temp;
757
758 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
759 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
760 pr_err("bad voltage = %dmV asked to set\n", millivolts);
761 return -EINVAL;
762 }
763
764 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
765 temp = temp << PM8921_CHG_VTRKL_SHIFT;
766 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
767 temp);
768}
769
770#define PM8921_CHG_VWEAK_MIN_MV 2100
771#define PM8921_CHG_VWEAK_MAX_MV 3600
772#define PM8921_CHG_VWEAK_STEP_MV 100
773#define PM8921_CHG_VWEAK_MASK 0x0F
774static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
775{
776 u8 temp;
777
778 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
779 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
780 pr_err("bad voltage = %dmV asked to set\n", millivolts);
781 return -EINVAL;
782 }
783
784 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
785 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
786 temp);
787}
788
789#define PM8921_CHG_ITRKL_MIN_MA 50
790#define PM8921_CHG_ITRKL_MAX_MA 200
791#define PM8921_CHG_ITRKL_MASK 0x0F
792#define PM8921_CHG_ITRKL_STEP_MA 10
793static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
794{
795 u8 temp;
796
797 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
798 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
799 pr_err("bad current = %dmA asked to set\n", milliamps);
800 return -EINVAL;
801 }
802
803 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
804
805 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
806 temp);
807}
808
809#define PM8921_CHG_IWEAK_MIN_MA 325
810#define PM8921_CHG_IWEAK_MAX_MA 525
811#define PM8921_CHG_IWEAK_SHIFT 7
812#define PM8921_CHG_IWEAK_MASK 0x80
813static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
814{
815 u8 temp;
816
817 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
818 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
819 pr_err("bad current = %dmA asked to set\n", milliamps);
820 return -EINVAL;
821 }
822
823 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
824 temp = 0;
825 else
826 temp = 1;
827
828 temp = temp << PM8921_CHG_IWEAK_SHIFT;
829 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
830 temp);
831}
832
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700833#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
834#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
835static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
836 enum pm8921_chg_cold_thr cold_thr)
837{
838 u8 temp;
839
840 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
841 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
842 return pm_chg_masked_write(chip, CHG_CNTRL_2,
843 PM8921_CHG_BATT_TEMP_THR_COLD,
844 temp);
845}
846
847#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
848#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
849static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
850 enum pm8921_chg_hot_thr hot_thr)
851{
852 u8 temp;
853
854 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
855 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
856 return pm_chg_masked_write(chip, CHG_CNTRL_2,
857 PM8921_CHG_BATT_TEMP_THR_HOT,
858 temp);
859}
860
Jay Chokshid674a512012-03-15 14:06:04 -0700861#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
862#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
863static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
864 enum pm8921_chg_led_src_config led_src_config)
865{
866 u8 temp;
867
868 if (led_src_config < LED_SRC_GND ||
869 led_src_config > LED_SRC_BYPASS)
870 return -EINVAL;
871
872 if (led_src_config == LED_SRC_BYPASS)
873 return 0;
874
875 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
876
877 return pm_chg_masked_write(chip, CHG_CNTRL_3,
878 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
879}
880
David Keitel8c5201a2012-02-24 16:08:54 -0800881static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
882{
883 u8 temp;
884 int rc;
885
886 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
887 if (rc) {
888 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
889 return;
890 }
891 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
892 if (rc) {
893 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
894 return;
895 }
896 /* set the input voltage disable bit and the write bit */
897 temp |= 0x81;
898 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
899 if (rc) {
900 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
901 return;
902 }
903}
904
905static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
906{
907 u8 temp;
908 int rc;
909
910 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
911 if (rc) {
912 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
913 return;
914 }
915 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
916 if (rc) {
917 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
918 return;
919 }
920 /* unset the input voltage disable bit */
921 temp &= 0xFE;
922 /* set the write bit */
923 temp |= 0x80;
924 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
925 if (rc) {
926 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
927 return;
928 }
929}
930
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700931static int64_t read_battery_id(struct pm8921_chg_chip *chip)
932{
933 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700934 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700935
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700936 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700937 if (rc) {
938 pr_err("error reading batt id channel = %d, rc = %d\n",
939 chip->vbat_channel, rc);
940 return rc;
941 }
942 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
943 result.measurement);
944 return result.physical;
945}
946
947static int is_battery_valid(struct pm8921_chg_chip *chip)
948{
949 int64_t rc;
950
951 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
952 return 1;
953
954 rc = read_battery_id(chip);
955 if (rc < 0) {
956 pr_err("error reading batt id channel = %d, rc = %lld\n",
957 chip->vbat_channel, rc);
958 /* assume battery id is valid when adc error happens */
959 return 1;
960 }
961
962 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
963 pr_err("batt_id phy =%lld is not valid\n", rc);
964 return 0;
965 }
966 return 1;
967}
968
969static void check_battery_valid(struct pm8921_chg_chip *chip)
970{
971 if (is_battery_valid(chip) == 0) {
972 pr_err("batt_id not valid, disbling charging\n");
973 pm_chg_auto_enable(chip, 0);
974 } else {
975 pm_chg_auto_enable(chip, !charging_disabled);
976 }
977}
978
979static void battery_id_valid(struct work_struct *work)
980{
981 struct pm8921_chg_chip *chip = container_of(work,
982 struct pm8921_chg_chip, battery_id_valid_work);
983
984 check_battery_valid(chip);
985}
986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
988{
989 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
990 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
991 enable_irq(chip->pmic_chg_irq[interrupt]);
992 }
993}
994
995static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
996{
997 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
998 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
999 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1000 }
1001}
1002
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001003static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1004{
1005 return test_bit(interrupt, chip->enabled_irqs);
1006}
1007
Amir Samuelovd31ef502011-10-26 14:41:36 +02001008static bool is_ext_charging(struct pm8921_chg_chip *chip)
1009{
David Keitel88e1b572012-01-11 11:57:14 -08001010 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001011
David Keitel88e1b572012-01-11 11:57:14 -08001012 if (!chip->ext_psy)
1013 return false;
1014 if (chip->ext_psy->get_property(chip->ext_psy,
1015 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1016 return false;
1017 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1018 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001019
1020 return false;
1021}
1022
1023static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1024{
David Keitel88e1b572012-01-11 11:57:14 -08001025 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001026
David Keitel88e1b572012-01-11 11:57:14 -08001027 if (!chip->ext_psy)
1028 return false;
1029 if (chip->ext_psy->get_property(chip->ext_psy,
1030 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1031 return false;
1032 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001033 return true;
1034
1035 return false;
1036}
1037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038static int is_battery_charging(int fsm_state)
1039{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001040 if (is_ext_charging(the_chip))
1041 return 1;
1042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 switch (fsm_state) {
1044 case FSM_STATE_ATC_2A:
1045 case FSM_STATE_ATC_2B:
1046 case FSM_STATE_ON_CHG_AND_BAT_6:
1047 case FSM_STATE_FAST_CHG_7:
1048 case FSM_STATE_TRKL_CHG_8:
1049 return 1;
1050 }
1051 return 0;
1052}
1053
1054static void bms_notify(struct work_struct *work)
1055{
1056 struct bms_notify *n = container_of(work, struct bms_notify, work);
1057
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001058 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001060 } else {
1061 pm8921_bms_charging_end(n->is_battery_full);
1062 n->is_battery_full = 0;
1063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064}
1065
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001066static void bms_notify_check(struct pm8921_chg_chip *chip)
1067{
1068 int fsm_state, new_is_charging;
1069
1070 fsm_state = pm_chg_get_fsm_state(chip);
1071 new_is_charging = is_battery_charging(fsm_state);
1072
1073 if (chip->bms_notify.is_charging ^ new_is_charging) {
1074 chip->bms_notify.is_charging = new_is_charging;
1075 schedule_work(&(chip->bms_notify.work));
1076 }
1077}
1078
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001079static enum power_supply_property pm_power_props_usb[] = {
1080 POWER_SUPPLY_PROP_PRESENT,
1081 POWER_SUPPLY_PROP_ONLINE,
1082 POWER_SUPPLY_PROP_CURRENT_MAX,
1083};
1084
1085static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001087 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088};
1089
1090static char *pm_power_supplied_to[] = {
1091 "battery",
1092};
1093
David Keitel6ed71a52012-01-30 12:42:18 -08001094#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001095static int pm_power_get_property_mains(struct power_supply *psy,
1096 enum power_supply_property psp,
1097 union power_supply_propval *val)
1098{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001099 /* Check if called before init */
1100 if (!the_chip)
1101 return -EINVAL;
1102
1103 switch (psp) {
1104 case POWER_SUPPLY_PROP_PRESENT:
1105 case POWER_SUPPLY_PROP_ONLINE:
1106 val->intval = 0;
1107 if (charging_disabled)
1108 return 0;
1109
1110 /* check external charger first before the dc path */
1111 if (is_ext_charging(the_chip)) {
1112 val->intval = 1;
1113 return 0;
1114 }
1115
1116 if (pm_is_chg_charge_dis(the_chip)) {
1117 val->intval = 0;
1118 return 0;
1119 }
1120
1121 if (the_chip->dc_present) {
1122 val->intval = 1;
1123 return 0;
1124 }
1125
1126 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001127 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001128 val->intval = is_usb_chg_plugged_in(the_chip);
1129 return 0;
1130
1131 break;
1132 default:
1133 return -EINVAL;
1134 }
1135 return 0;
1136}
1137
1138static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 enum power_supply_property psp,
1140 union power_supply_propval *val)
1141{
David Keitel6ed71a52012-01-30 12:42:18 -08001142 int current_max;
1143
1144 /* Check if called before init */
1145 if (!the_chip)
1146 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147
1148 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001149 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001150 if (pm_is_chg_charge_dis(the_chip)) {
1151 val->intval = 0;
1152 } else {
1153 pm_chg_iusbmax_get(the_chip, &current_max);
1154 val->intval = current_max;
1155 }
David Keitel6ed71a52012-01-30 12:42:18 -08001156 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001158 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001159 val->intval = 0;
1160 if (charging_disabled)
1161 return 0;
1162
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001163 /*
1164 * if drawing any current from usb is disabled behave
1165 * as if no usb cable is connected
1166 */
1167 if (pm_is_chg_charge_dis(the_chip))
1168 return 0;
1169
David Keitel63f71662012-02-08 20:30:00 -08001170 /* USB charging */
David Keitel70f6cdc22012-03-15 15:33:26 -07001171 val->intval = is_usb_chg_plugged_in(the_chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 break;
1173 default:
1174 return -EINVAL;
1175 }
1176 return 0;
1177}
1178
1179static enum power_supply_property msm_batt_power_props[] = {
1180 POWER_SUPPLY_PROP_STATUS,
1181 POWER_SUPPLY_PROP_CHARGE_TYPE,
1182 POWER_SUPPLY_PROP_HEALTH,
1183 POWER_SUPPLY_PROP_PRESENT,
1184 POWER_SUPPLY_PROP_TECHNOLOGY,
1185 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1186 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1187 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1188 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001189 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001190 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001191 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192};
1193
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001194static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195{
1196 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001197 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001199 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 if (rc) {
1201 pr_err("error reading adc channel = %d, rc = %d\n",
1202 chip->vbat_channel, rc);
1203 return rc;
1204 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001205 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 result.measurement);
1207 return (int)result.physical;
1208}
1209
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001210static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1211{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001212 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1213 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1214 unsigned int low_voltage = chip->min_voltage_mv;
1215 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001216
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001217 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001218 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001219 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001220 return 100;
1221 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001222 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001223 / (high_voltage - low_voltage);
1224}
1225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1227{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001228 int percent_soc = pm8921_bms_get_percent_charge();
1229
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001230 if (percent_soc == -ENXIO)
1231 percent_soc = voltage_based_capacity(chip);
1232
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001233 if (percent_soc <= 10)
1234 pr_warn("low battery charge = %d%%\n", percent_soc);
1235
1236 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237}
1238
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001239static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1240{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001241 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001242
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001243 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001244 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001245 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001246 }
1247
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001248 if (rc) {
1249 pr_err("unable to get batt current rc = %d\n", rc);
1250 return rc;
1251 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001252 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001253 }
1254}
1255
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001256static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1257{
1258 int rc;
1259
1260 rc = pm8921_bms_get_fcc();
1261 if (rc < 0)
1262 pr_err("unable to get batt fcc rc = %d\n", rc);
1263 return rc;
1264}
1265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1267{
1268 int temp;
1269
1270 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1271 if (temp)
1272 return POWER_SUPPLY_HEALTH_OVERHEAT;
1273
1274 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1275 if (temp)
1276 return POWER_SUPPLY_HEALTH_COLD;
1277
1278 return POWER_SUPPLY_HEALTH_GOOD;
1279}
1280
1281static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1282{
1283 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1284}
1285
1286static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1287{
1288 int temp;
1289
Amir Samuelovd31ef502011-10-26 14:41:36 +02001290 if (!get_prop_batt_present(chip))
1291 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1292
1293 if (is_ext_trickle_charging(chip))
1294 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1295
1296 if (is_ext_charging(chip))
1297 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1300 if (temp)
1301 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1302
1303 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1304 if (temp)
1305 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1306
1307 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1308}
1309
1310static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1311{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001312 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1313 int fsm_state = pm_chg_get_fsm_state(chip);
1314 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315
David Keitel88e1b572012-01-11 11:57:14 -08001316 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001317 if (chip->ext_charge_done)
1318 return POWER_SUPPLY_STATUS_FULL;
1319 if (chip->ext_charging)
1320 return POWER_SUPPLY_STATUS_CHARGING;
1321 }
1322
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001323 for (i = 0; i < ARRAY_SIZE(map); i++)
1324 if (map[i].fsm_state == fsm_state)
1325 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001326
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001327 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1328 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1329 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001330 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1331 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001332
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001333 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001334 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001335 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336}
1337
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001338#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001339static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1340{
1341 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001342 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001343
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001344 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001345 if (rc) {
1346 pr_err("error reading adc channel = %d, rc = %d\n",
1347 chip->vbat_channel, rc);
1348 return rc;
1349 }
1350 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1351 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001352 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1353 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1354 (int) result.physical);
1355
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001356 return (int)result.physical;
1357}
1358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359static int pm_batt_power_get_property(struct power_supply *psy,
1360 enum power_supply_property psp,
1361 union power_supply_propval *val)
1362{
1363 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1364 batt_psy);
1365
1366 switch (psp) {
1367 case POWER_SUPPLY_PROP_STATUS:
1368 val->intval = get_prop_batt_status(chip);
1369 break;
1370 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1371 val->intval = get_prop_charge_type(chip);
1372 break;
1373 case POWER_SUPPLY_PROP_HEALTH:
1374 val->intval = get_prop_batt_health(chip);
1375 break;
1376 case POWER_SUPPLY_PROP_PRESENT:
1377 val->intval = get_prop_batt_present(chip);
1378 break;
1379 case POWER_SUPPLY_PROP_TECHNOLOGY:
1380 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1381 break;
1382 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001383 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 break;
1385 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001386 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 break;
1388 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001389 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 break;
1391 case POWER_SUPPLY_PROP_CAPACITY:
1392 val->intval = get_prop_batt_capacity(chip);
1393 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001394 case POWER_SUPPLY_PROP_CURRENT_NOW:
1395 val->intval = get_prop_batt_current(chip);
1396 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001397 case POWER_SUPPLY_PROP_TEMP:
1398 val->intval = get_prop_batt_temp(chip);
1399 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001400 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001401 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001402 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 default:
1404 return -EINVAL;
1405 }
1406
1407 return 0;
1408}
1409
1410static void (*notify_vbus_state_func_ptr)(int);
1411static int usb_chg_current;
1412static DEFINE_SPINLOCK(vbus_lock);
1413
1414int pm8921_charger_register_vbus_sn(void (*callback)(int))
1415{
1416 pr_debug("%p\n", callback);
1417 notify_vbus_state_func_ptr = callback;
1418 return 0;
1419}
1420EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1421
1422/* this is passed to the hsusb via platform_data msm_otg_pdata */
1423void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1424{
1425 pr_debug("%p\n", callback);
1426 notify_vbus_state_func_ptr = NULL;
1427}
1428EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1429
1430static void notify_usb_of_the_plugin_event(int plugin)
1431{
1432 plugin = !!plugin;
1433 if (notify_vbus_state_func_ptr) {
1434 pr_debug("notifying plugin\n");
1435 (*notify_vbus_state_func_ptr) (plugin);
1436 } else {
1437 pr_debug("unable to notify plugin\n");
1438 }
1439}
1440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441/* assumes vbus_lock is held */
1442static void __pm8921_charger_vbus_draw(unsigned int mA)
1443{
1444 int i, rc;
1445
1446 if (mA > 0 && mA <= 2) {
1447 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001448 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001450 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 }
1452 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1453 if (rc)
1454 pr_err("fail to set suspend bit rc=%d\n", rc);
1455 } else {
1456 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1457 if (rc)
1458 pr_err("fail to reset suspend bit rc=%d\n", rc);
1459 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1460 if (usb_ma_table[i].usb_ma <= mA)
1461 break;
1462 }
1463 if (i < 0)
1464 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001465 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001467 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 }
1469 }
1470}
1471
1472/* USB calls these to tell us how much max usb current the system can draw */
1473void pm8921_charger_vbus_draw(unsigned int mA)
1474{
1475 unsigned long flags;
1476
1477 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001478
1479 if (usb_max_current && mA > usb_max_current) {
1480 pr_warn("restricting usb current to %d instead of %d\n",
1481 usb_max_current, mA);
1482 mA = usb_max_current;
1483 }
1484 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1485 usb_target_ma = mA;
1486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 spin_lock_irqsave(&vbus_lock, flags);
1488 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001489 if (mA > USB_WALL_THRESHOLD_MA)
1490 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1491 else
1492 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 } else {
1494 /*
1495 * called before pmic initialized,
1496 * save this value and use it at probe
1497 */
David Keitelacf57c82012-03-07 18:48:50 -08001498 if (mA > USB_WALL_THRESHOLD_MA)
1499 usb_chg_current = USB_WALL_THRESHOLD_MA;
1500 else
1501 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 }
1503 spin_unlock_irqrestore(&vbus_lock, flags);
1504}
1505EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1506
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001507int pm8921_charger_enable(bool enable)
1508{
1509 int rc;
1510
1511 if (!the_chip) {
1512 pr_err("called before init\n");
1513 return -EINVAL;
1514 }
1515 enable = !!enable;
1516 rc = pm_chg_auto_enable(the_chip, enable);
1517 if (rc)
1518 pr_err("Failed rc=%d\n", rc);
1519 return rc;
1520}
1521EXPORT_SYMBOL(pm8921_charger_enable);
1522
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001523int pm8921_is_usb_chg_plugged_in(void)
1524{
1525 if (!the_chip) {
1526 pr_err("called before init\n");
1527 return -EINVAL;
1528 }
1529 return is_usb_chg_plugged_in(the_chip);
1530}
1531EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1532
1533int pm8921_is_dc_chg_plugged_in(void)
1534{
1535 if (!the_chip) {
1536 pr_err("called before init\n");
1537 return -EINVAL;
1538 }
1539 return is_dc_chg_plugged_in(the_chip);
1540}
1541EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1542
1543int pm8921_is_battery_present(void)
1544{
1545 if (!the_chip) {
1546 pr_err("called before init\n");
1547 return -EINVAL;
1548 }
1549 return get_prop_batt_present(the_chip);
1550}
1551EXPORT_SYMBOL(pm8921_is_battery_present);
1552
David Keitel012deef2011-12-02 11:49:33 -08001553/*
1554 * Disabling the charge current limit causes current
1555 * current limits to have no monitoring. An adequate charger
1556 * capable of supplying high current while sustaining VIN_MIN
1557 * is required if the limiting is disabled.
1558 */
1559int pm8921_disable_input_current_limit(bool disable)
1560{
1561 if (!the_chip) {
1562 pr_err("called before init\n");
1563 return -EINVAL;
1564 }
1565 if (disable) {
1566 pr_warn("Disabling input current limit!\n");
1567
1568 return pm8xxx_writeb(the_chip->dev->parent,
1569 CHG_BUCK_CTRL_TEST3, 0xF2);
1570 }
1571 return 0;
1572}
1573EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1574
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001575int pm8921_set_max_battery_charge_current(int ma)
1576{
1577 if (!the_chip) {
1578 pr_err("called before init\n");
1579 return -EINVAL;
1580 }
1581 return pm_chg_ibatmax_set(the_chip, ma);
1582}
1583EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1584
1585int pm8921_disable_source_current(bool disable)
1586{
1587 if (!the_chip) {
1588 pr_err("called before init\n");
1589 return -EINVAL;
1590 }
1591 if (disable)
1592 pr_warn("current drawn from chg=0, battery provides current\n");
1593 return pm_chg_charge_dis(the_chip, disable);
1594}
1595EXPORT_SYMBOL(pm8921_disable_source_current);
1596
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001597int pm8921_regulate_input_voltage(int voltage)
1598{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001599 int rc;
1600
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001601 if (!the_chip) {
1602 pr_err("called before init\n");
1603 return -EINVAL;
1604 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001605 rc = pm_chg_vinmin_set(the_chip, voltage);
1606
1607 if (rc == 0)
1608 the_chip->vin_min = voltage;
1609
1610 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001611}
1612
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001613#define USB_OV_THRESHOLD_MASK 0x60
1614#define USB_OV_THRESHOLD_SHIFT 5
1615int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1616{
1617 u8 temp;
1618
1619 if (!the_chip) {
1620 pr_err("called before init\n");
1621 return -EINVAL;
1622 }
1623
1624 if (ov > PM_USB_OV_7V) {
1625 pr_err("limiting to over voltage threshold to 7volts\n");
1626 ov = PM_USB_OV_7V;
1627 }
1628
1629 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1630
1631 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1632 USB_OV_THRESHOLD_MASK, temp);
1633}
1634EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1635
1636#define USB_DEBOUNCE_TIME_MASK 0x06
1637#define USB_DEBOUNCE_TIME_SHIFT 1
1638int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1639{
1640 u8 temp;
1641
1642 if (!the_chip) {
1643 pr_err("called before init\n");
1644 return -EINVAL;
1645 }
1646
1647 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1648 pr_err("limiting debounce to 80.5ms\n");
1649 ms = PM_USB_DEBOUNCE_80P5MS;
1650 }
1651
1652 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1653
1654 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1655 USB_DEBOUNCE_TIME_MASK, temp);
1656}
1657EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1658
1659#define USB_OVP_DISABLE_MASK 0x80
1660int pm8921_usb_ovp_disable(int disable)
1661{
1662 u8 temp = 0;
1663
1664 if (!the_chip) {
1665 pr_err("called before init\n");
1666 return -EINVAL;
1667 }
1668
1669 if (disable)
1670 temp = USB_OVP_DISABLE_MASK;
1671
1672 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1673 USB_OVP_DISABLE_MASK, temp);
1674}
1675
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001676bool pm8921_is_battery_charging(int *source)
1677{
1678 int fsm_state, is_charging, dc_present, usb_present;
1679
1680 if (!the_chip) {
1681 pr_err("called before init\n");
1682 return -EINVAL;
1683 }
1684 fsm_state = pm_chg_get_fsm_state(the_chip);
1685 is_charging = is_battery_charging(fsm_state);
1686 if (is_charging == 0) {
1687 *source = PM8921_CHG_SRC_NONE;
1688 return is_charging;
1689 }
1690
1691 if (source == NULL)
1692 return is_charging;
1693
1694 /* the battery is charging, the source is requested, find it */
1695 dc_present = is_dc_chg_plugged_in(the_chip);
1696 usb_present = is_usb_chg_plugged_in(the_chip);
1697
1698 if (dc_present && !usb_present)
1699 *source = PM8921_CHG_SRC_DC;
1700
1701 if (usb_present && !dc_present)
1702 *source = PM8921_CHG_SRC_USB;
1703
1704 if (usb_present && dc_present)
1705 /*
1706 * The system always chooses dc for charging since it has
1707 * higher priority.
1708 */
1709 *source = PM8921_CHG_SRC_DC;
1710
1711 return is_charging;
1712}
1713EXPORT_SYMBOL(pm8921_is_battery_charging);
1714
1715int pm8921_batt_temperature(void)
1716{
1717 if (!the_chip) {
1718 pr_err("called before init\n");
1719 return -EINVAL;
1720 }
1721 return get_prop_batt_temp(the_chip);
1722}
1723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1725{
1726 int usb_present;
1727
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001728 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 usb_present = is_usb_chg_plugged_in(chip);
1730 if (chip->usb_present ^ usb_present) {
1731 notify_usb_of_the_plugin_event(usb_present);
1732 chip->usb_present = usb_present;
1733 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001734 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001735 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001737 if (usb_present) {
1738 schedule_delayed_work(&chip->unplug_check_work,
1739 round_jiffies_relative(msecs_to_jiffies
1740 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001741 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1742 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001743 /* USB unplugged reset target current */
1744 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001745 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001746 }
David Keitel8c5201a2012-02-24 16:08:54 -08001747 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001748 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749}
1750
Amir Samuelovd31ef502011-10-26 14:41:36 +02001751static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1752{
David Keitel88e1b572012-01-11 11:57:14 -08001753 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001754 pr_debug("external charger not registered.\n");
1755 return;
1756 }
1757
1758 if (!chip->ext_charging) {
1759 pr_debug("already not charging.\n");
1760 return;
1761 }
1762
David Keitel88e1b572012-01-11 11:57:14 -08001763 power_supply_set_charge_type(chip->ext_psy,
1764 POWER_SUPPLY_CHARGE_TYPE_NONE);
1765 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001766 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001767 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001768 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001769 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001770}
1771
1772static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1773{
1774 int dc_present;
1775 int batt_present;
1776 int batt_temp_ok;
1777 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001778 unsigned long delay =
1779 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1780
David Keitel88e1b572012-01-11 11:57:14 -08001781 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001782 pr_debug("external charger not registered.\n");
1783 return;
1784 }
1785
1786 if (chip->ext_charging) {
1787 pr_debug("already charging.\n");
1788 return;
1789 }
1790
David Keitel88e1b572012-01-11 11:57:14 -08001791 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001792 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1793 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001794
1795 if (!dc_present) {
1796 pr_warn("%s. dc not present.\n", __func__);
1797 return;
1798 }
1799 if (!batt_present) {
1800 pr_warn("%s. battery not present.\n", __func__);
1801 return;
1802 }
1803 if (!batt_temp_ok) {
1804 pr_warn("%s. battery temperature not ok.\n", __func__);
1805 return;
1806 }
David Keitel88e1b572012-01-11 11:57:14 -08001807 pm8921_disable_source_current(true); /* Force BATFET=ON */
1808 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001809 if (vbat_ov) {
1810 pr_warn("%s. battery over voltage.\n", __func__);
1811 return;
1812 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001813
David Keitel63f71662012-02-08 20:30:00 -08001814 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001815 power_supply_set_charge_type(chip->ext_psy,
1816 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001817 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001818 chip->ext_charging = true;
1819 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001820 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001821 /* Start BMS */
1822 schedule_delayed_work(&chip->eoc_work, delay);
1823 wake_lock(&chip->eoc_wake_lock);
1824}
1825
David Keitel8c5201a2012-02-24 16:08:54 -08001826static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001827{
1828 u8 temp;
1829 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001830
David Keitel8c5201a2012-02-24 16:08:54 -08001831 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001832 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001833 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1834 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001835 }
David Keitel8c5201a2012-02-24 16:08:54 -08001836 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1837 if (rc) {
1838 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1839 return;
1840 }
1841 /* set ovp fet disable bit and the write bit */
1842 temp |= 0x81;
1843 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1844 if (rc) {
1845 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1846 return;
1847 }
1848}
1849
1850static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1851{
1852 u8 temp;
1853 int rc;
1854
1855 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1856 if (rc) {
1857 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1858 return;
1859 }
1860 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1861 if (rc) {
1862 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1863 return;
1864 }
1865 /* unset ovp fet disable bit and set the write bit */
1866 temp &= 0xFE;
1867 temp |= 0x80;
1868 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1869 if (rc) {
1870 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1871 temp, rc);
1872 return;
1873 }
1874}
1875
1876static int param_open_ovp_counter = 10;
1877module_param(param_open_ovp_counter, int, 0644);
1878
1879#define WRITE_BANK_4 0xC0
1880#define USB_OVP_DEBOUNCE_TIME 0x06
1881static void unplug_ovp_fet_open_worker(struct work_struct *work)
1882{
1883 struct pm8921_chg_chip *chip = container_of(work,
1884 struct pm8921_chg_chip,
1885 unplug_ovp_fet_open_work);
1886 int chg_gone, usb_chg_plugged_in;
1887 int count = 0;
1888
1889 while (count++ < param_open_ovp_counter) {
1890 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1891 USB_OVP_DEBOUNCE_TIME, 0x0);
1892 usleep(10);
1893 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1894 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1895 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1896 count, chg_gone, usb_chg_plugged_in);
1897
1898 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1899 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1900 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1901 turn_off_usb_ovp_fet(chip);
1902
1903 msleep(20);
1904
1905 turn_on_usb_ovp_fet(chip);
1906 } else {
1907 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1908 USB_OVP_DEBOUNCE_TIME, 0x1);
1909 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1910 count, chg_gone, usb_chg_plugged_in);
1911 return;
1912 }
1913 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001914}
David Keitelacf57c82012-03-07 18:48:50 -08001915
1916static int find_usb_ma_value(int value)
1917{
1918 int i;
1919
1920 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1921 if (value >= usb_ma_table[i].usb_ma)
1922 break;
1923 }
1924
1925 return i;
1926}
1927
1928static void decrease_usb_ma_value(int *value)
1929{
1930 int i;
1931
1932 if (value) {
1933 i = find_usb_ma_value(*value);
1934 if (i > 0)
1935 i--;
1936 *value = usb_ma_table[i].usb_ma;
1937 }
1938}
1939
1940static void increase_usb_ma_value(int *value)
1941{
1942 int i;
1943
1944 if (value) {
1945 i = find_usb_ma_value(*value);
1946
1947 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
1948 i++;
1949 *value = usb_ma_table[i].usb_ma;
1950 }
1951}
1952
1953static void vin_collapse_check_worker(struct work_struct *work)
1954{
1955 struct delayed_work *dwork = to_delayed_work(work);
1956 struct pm8921_chg_chip *chip = container_of(dwork,
1957 struct pm8921_chg_chip, vin_collapse_check_work);
1958
1959 /* AICL only for wall-chargers */
1960 if (is_usb_chg_plugged_in(chip) &&
1961 usb_target_ma > USB_WALL_THRESHOLD_MA) {
1962 /* decrease usb_target_ma */
1963 decrease_usb_ma_value(&usb_target_ma);
1964 /* reset here, increase in unplug_check_worker */
1965 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1966 pr_debug("usb_now=%d, usb_target = %d\n",
1967 USB_WALL_THRESHOLD_MA, usb_target_ma);
1968 } else {
1969 handle_usb_insertion_removal(chip);
1970 }
1971}
1972
1973#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001974static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1975{
David Keitelacf57c82012-03-07 18:48:50 -08001976 if (usb_target_ma)
1977 schedule_delayed_work(&the_chip->vin_collapse_check_work,
1978 round_jiffies_relative(msecs_to_jiffies
1979 (VIN_MIN_COLLAPSE_CHECK_MS)));
1980 else
1981 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 return IRQ_HANDLED;
1983}
1984
1985static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1986{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001987 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 return IRQ_HANDLED;
1989}
1990
1991static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1992{
1993 struct pm8921_chg_chip *chip = data;
1994 int status;
1995
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001996 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1997 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001998 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 pr_debug("battery present=%d", status);
2000 power_supply_changed(&chip->batt_psy);
2001 return IRQ_HANDLED;
2002}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002003
2004/*
2005 * this interrupt used to restart charging a battery.
2006 *
2007 * Note: When DC-inserted the VBAT can't go low.
2008 * VPH_PWR is provided by the ext-charger.
2009 * After End-Of-Charging from DC, charging can be resumed only
2010 * if DC is removed and then inserted after the battery was in use.
2011 * Therefore the handle_start_ext_chg() is not called.
2012 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2014{
2015 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002016 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002018 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002019
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002020 if (high_transition) {
2021 /* enable auto charging */
2022 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002023 pr_info("batt fell below resume voltage %s\n",
2024 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002025 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 power_supply_changed(&chip->batt_psy);
2029 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002030 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 return IRQ_HANDLED;
2033}
2034
2035static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2036{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002037 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 return IRQ_HANDLED;
2039}
2040
2041static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2042{
2043 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2044 return IRQ_HANDLED;
2045}
2046
2047static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2048{
2049 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2050 return IRQ_HANDLED;
2051}
2052
2053static irqreturn_t vcp_irq_handler(int irq, void *data)
2054{
David Keitel8c5201a2012-02-24 16:08:54 -08002055 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 return IRQ_HANDLED;
2057}
2058
2059static irqreturn_t atcdone_irq_handler(int irq, void *data)
2060{
2061 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2062 return IRQ_HANDLED;
2063}
2064
2065static irqreturn_t atcfail_irq_handler(int irq, void *data)
2066{
2067 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2068 return IRQ_HANDLED;
2069}
2070
2071static irqreturn_t chgdone_irq_handler(int irq, void *data)
2072{
2073 struct pm8921_chg_chip *chip = data;
2074
2075 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002076
2077 handle_stop_ext_chg(chip);
2078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 power_supply_changed(&chip->batt_psy);
2080 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002081 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002082
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002083 bms_notify_check(chip);
2084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 return IRQ_HANDLED;
2086}
2087
2088static irqreturn_t chgfail_irq_handler(int irq, void *data)
2089{
2090 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002091 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092
David Keitel753ec8d2011-11-02 10:56:37 -07002093 ret = pm_chg_failed_clear(chip, 1);
2094 if (ret)
2095 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2096
2097 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2098 get_prop_batt_present(chip),
2099 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2100 pm_chg_get_fsm_state(data));
2101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 power_supply_changed(&chip->batt_psy);
2103 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002104 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 return IRQ_HANDLED;
2106}
2107
2108static irqreturn_t chgstate_irq_handler(int irq, void *data)
2109{
2110 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111
2112 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2113 power_supply_changed(&chip->batt_psy);
2114 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002115 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002116
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002117 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 return IRQ_HANDLED;
2120}
2121
David Keitel8c5201a2012-02-24 16:08:54 -08002122static int param_vin_disable_counter = 5;
2123module_param(param_vin_disable_counter, int, 0644);
2124
2125static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2126 int count, int usb_ma)
2127{
David Keitelacf57c82012-03-07 18:48:50 -08002128 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002129 pr_debug("count = %d iusb=500mA\n", count);
2130 disable_input_voltage_regulation(chip);
2131 pr_debug("count = %d disable_input_regulation\n", count);
2132
2133 msleep(20);
2134
2135 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2136 count,
2137 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2138 is_usb_chg_plugged_in(chip));
2139 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2140 count, usb_ma);
2141 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002142 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002143}
2144
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002145#define VIN_ACTIVE_BIT BIT(0)
2146#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2147#define VIN_MIN_INCREASE_MV 100
2148static void unplug_check_worker(struct work_struct *work)
2149{
2150 struct delayed_work *dwork = to_delayed_work(work);
2151 struct pm8921_chg_chip *chip = container_of(dwork,
2152 struct pm8921_chg_chip, unplug_check_work);
2153 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002154 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002155 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002156
David Keitelacf57c82012-03-07 18:48:50 -08002157 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002158 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2159 if (!usb_chg_plugged_in) {
2160 pr_debug("Stopping Unplug Check Worker since USB is removed"
2161 "reg_loop = %d, fsm = %d ibat = %d\n",
2162 pm_chg_get_regulation_loop(chip),
2163 pm_chg_get_fsm_state(chip),
2164 get_prop_batt_current(chip)
2165 );
2166 return;
2167 }
David Keitel8c5201a2012-02-24 16:08:54 -08002168
2169 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002170 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002171 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2172 disable_input_voltage_regulation(chip);
2173 return;
2174 }
2175
2176 if (usb_ma <= 100) {
2177 pr_debug(
2178 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2179 usb_ma);
2180 goto check_again_later;
2181 }
2182 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2183 pr_debug("chg gone irq is enabled\n");
2184
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002185 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002186 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002187
2188 if (reg_loop & VIN_ACTIVE_BIT) {
David Keitelacf57c82012-03-07 18:48:50 -08002189 decrease_usb_ma_value(&usb_ma);
2190 usb_target_ma = usb_ma;
2191 /* end AICL here */
2192 __pm8921_charger_vbus_draw(usb_ma);
2193 pr_debug("usb_now=%d, usb_target = %d\n",
2194 usb_ma, usb_target_ma);
2195 }
2196
2197 reg_loop = pm_chg_get_regulation_loop(chip);
2198 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2199
2200 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002201 ibat = get_prop_batt_current(chip);
2202
2203 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2204 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2205 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002206 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002207
David Keitel8c5201a2012-02-24 16:08:54 -08002208 while (count++ < param_vin_disable_counter
2209 && usb_chg_plugged_in == 1) {
2210 attempt_reverse_boost_fix(chip, count, usb_ma);
2211 usb_chg_plugged_in
2212 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002213 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002214 }
2215 }
2216
David Keitel8c5201a2012-02-24 16:08:54 -08002217 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2218 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2219
2220 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2221 /* run the worker directly */
2222 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2223 chg_gone, usb_chg_plugged_in);
2224 schedule_work(&chip->unplug_ovp_fet_open_work);
2225 }
2226
David Keitelacf57c82012-03-07 18:48:50 -08002227 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2228 /* only increase iusb_max if vin loop not active */
2229 if (usb_ma < usb_target_ma) {
2230 increase_usb_ma_value(&usb_ma);
2231 __pm8921_charger_vbus_draw(usb_ma);
2232 pr_debug("usb_now=%d, usb_target = %d\n",
2233 usb_ma, usb_target_ma);
2234 } else {
2235 usb_target_ma = usb_ma;
2236 }
2237 }
David Keitel8c5201a2012-02-24 16:08:54 -08002238check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002239 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002240 schedule_delayed_work(&chip->unplug_check_work,
2241 round_jiffies_relative(msecs_to_jiffies
2242 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2243}
2244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245static irqreturn_t loop_change_irq_handler(int irq, void *data)
2246{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002247 struct pm8921_chg_chip *chip = data;
2248
2249 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2250 pm_chg_get_fsm_state(data),
2251 pm_chg_get_regulation_loop(data));
2252 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 return IRQ_HANDLED;
2254}
2255
2256static irqreturn_t fastchg_irq_handler(int irq, void *data)
2257{
2258 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002259 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002261 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2262 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2263 wake_lock(&chip->eoc_wake_lock);
2264 schedule_delayed_work(&chip->eoc_work,
2265 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002266 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002267 }
2268 power_supply_changed(&chip->batt_psy);
2269 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 return IRQ_HANDLED;
2271}
2272
2273static irqreturn_t trklchg_irq_handler(int irq, void *data)
2274{
2275 struct pm8921_chg_chip *chip = data;
2276
2277 power_supply_changed(&chip->batt_psy);
2278 return IRQ_HANDLED;
2279}
2280
2281static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2282{
2283 struct pm8921_chg_chip *chip = data;
2284 int status;
2285
2286 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2287 pr_debug("battery present=%d state=%d", !status,
2288 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002289 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 power_supply_changed(&chip->batt_psy);
2291 return IRQ_HANDLED;
2292}
2293
2294static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2295{
2296 struct pm8921_chg_chip *chip = data;
2297
Amir Samuelovd31ef502011-10-26 14:41:36 +02002298 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 power_supply_changed(&chip->batt_psy);
2300 return IRQ_HANDLED;
2301}
2302
2303static irqreturn_t chghot_irq_handler(int irq, void *data)
2304{
2305 struct pm8921_chg_chip *chip = data;
2306
2307 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2308 power_supply_changed(&chip->batt_psy);
2309 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002310 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002311 return IRQ_HANDLED;
2312}
2313
2314static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2315{
2316 struct pm8921_chg_chip *chip = data;
2317
2318 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002319 handle_stop_ext_chg(chip);
2320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 power_supply_changed(&chip->batt_psy);
2322 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323 return IRQ_HANDLED;
2324}
2325
2326static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2327{
2328 struct pm8921_chg_chip *chip = data;
David Keitel8c5201a2012-02-24 16:08:54 -08002329 int chg_gone, usb_chg_plugged_in;
2330
2331 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2332 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2333
2334 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2335 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336
2337 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2338 power_supply_changed(&chip->batt_psy);
2339 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 return IRQ_HANDLED;
2341}
David Keitel52fda532011-11-10 10:43:44 -08002342/*
2343 *
2344 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2345 * fire for two cases:
2346 *
2347 * If the interrupt line switches to high temperature is okay
2348 * and thus charging begins.
2349 * If bat_temp_ok is low this means the temperature is now
2350 * too hot or cold, so charging is stopped.
2351 *
2352 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2354{
David Keitel52fda532011-11-10 10:43:44 -08002355 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002356 struct pm8921_chg_chip *chip = data;
2357
David Keitel52fda532011-11-10 10:43:44 -08002358 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2359
2360 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2361 bat_temp_ok, pm_chg_get_fsm_state(data));
2362
2363 if (bat_temp_ok)
2364 handle_start_ext_chg(chip);
2365 else
2366 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 power_supply_changed(&chip->batt_psy);
2369 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002370 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371 return IRQ_HANDLED;
2372}
2373
2374static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2375{
2376 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2377 return IRQ_HANDLED;
2378}
2379
2380static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2381{
2382 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2383 return IRQ_HANDLED;
2384}
2385
2386static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2387{
2388 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2389 return IRQ_HANDLED;
2390}
2391
2392static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2393{
2394 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2395 return IRQ_HANDLED;
2396}
2397
2398static irqreturn_t batfet_irq_handler(int irq, void *data)
2399{
2400 struct pm8921_chg_chip *chip = data;
2401
2402 pr_debug("vreg ov\n");
2403 power_supply_changed(&chip->batt_psy);
2404 return IRQ_HANDLED;
2405}
2406
2407static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2408{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002409 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002410 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002411
David Keitel88e1b572012-01-11 11:57:14 -08002412 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2413 if (chip->ext_psy)
2414 power_supply_set_online(chip->ext_psy, dc_present);
2415 chip->dc_present = dc_present;
2416 if (dc_present)
2417 handle_start_ext_chg(chip);
2418 else
2419 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002420 return IRQ_HANDLED;
2421}
2422
2423static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2424{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002425 struct pm8921_chg_chip *chip = data;
2426
Amir Samuelovd31ef502011-10-26 14:41:36 +02002427 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 return IRQ_HANDLED;
2429}
2430
2431static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2432{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002433 struct pm8921_chg_chip *chip = data;
2434
Amir Samuelovd31ef502011-10-26 14:41:36 +02002435 handle_stop_ext_chg(chip);
2436
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002437 return IRQ_HANDLED;
2438}
2439
David Keitel88e1b572012-01-11 11:57:14 -08002440static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2441{
2442 struct power_supply *psy = &the_chip->batt_psy;
2443 struct power_supply *epsy = dev_get_drvdata(dev);
2444 int i, dcin_irq;
2445
2446 /* Only search for external supply if none is registered */
2447 if (!the_chip->ext_psy) {
2448 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2449 for (i = 0; i < epsy->num_supplicants; i++) {
2450 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2451 if (!strncmp(epsy->name, "dc", 2)) {
2452 the_chip->ext_psy = epsy;
2453 dcin_valid_irq_handler(dcin_irq,
2454 the_chip);
2455 }
2456 }
2457 }
2458 }
2459 return 0;
2460}
2461
2462static void pm_batt_external_power_changed(struct power_supply *psy)
2463{
2464 /* Only look for an external supply if it hasn't been registered */
2465 if (!the_chip->ext_psy)
2466 class_for_each_device(power_supply_class, NULL, psy,
2467 __pm_batt_external_power_changed_work);
2468}
2469
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002470/**
2471 * update_heartbeat - internal function to update userspace
2472 * per update_time minutes
2473 *
2474 */
2475static void update_heartbeat(struct work_struct *work)
2476{
2477 struct delayed_work *dwork = to_delayed_work(work);
2478 struct pm8921_chg_chip *chip = container_of(dwork,
2479 struct pm8921_chg_chip, update_heartbeat_work);
2480
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002481 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002482 power_supply_changed(&chip->batt_psy);
2483 schedule_delayed_work(&chip->update_heartbeat_work,
2484 round_jiffies_relative(msecs_to_jiffies
2485 (chip->update_time)));
2486}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002487#define VDD_LOOP_ACTIVE_BIT BIT(3)
2488#define VDD_MAX_INCREASE_MV 400
2489static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2490module_param(vdd_max_increase_mv, int, 0644);
2491
2492static int ichg_threshold_ua = -400000;
2493module_param(ichg_threshold_ua, int, 0644);
2494static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2495{
2496 int ichg_meas_ua, vbat_uv;
2497 int ichg_meas_ma;
2498 int adj_vdd_max_mv, programmed_vdd_max;
2499 int vbat_batt_terminal_uv;
2500 int vbat_batt_terminal_mv;
2501 int reg_loop;
2502 int delta_mv = 0;
2503
2504 if (chip->rconn_mohm == 0) {
2505 pr_debug("Exiting as rconn_mohm is 0\n");
2506 return;
2507 }
2508 /* adjust vdd_max only in normal temperature zone */
2509 if (chip->is_bat_cool || chip->is_bat_warm) {
2510 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2511 chip->is_bat_cool, chip->is_bat_warm);
2512 return;
2513 }
2514
2515 reg_loop = pm_chg_get_regulation_loop(chip);
2516 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2517 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2518 reg_loop);
2519 return;
2520 }
2521
2522 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2523 &vbat_uv);
2524 if (ichg_meas_ua >= 0) {
2525 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2526 return;
2527 }
2528 if (ichg_meas_ua <= ichg_threshold_ua) {
2529 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2530 ichg_meas_ua, ichg_threshold_ua);
2531 return;
2532 }
2533 ichg_meas_ma = ichg_meas_ua / 1000;
2534
2535 /* rconn_mohm is in milliOhms */
2536 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2537 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2538 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2539
2540 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2541
2542 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2543 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2544 delta_mv,
2545 programmed_vdd_max,
2546 adj_vdd_max_mv);
2547
2548 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2549 pr_debug("adj vdd_max lower than default max voltage\n");
2550 return;
2551 }
2552
2553 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2554 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2555
2556 pr_debug("adjusting vdd_max_mv to %d to make "
2557 "vbat_batt_termial_uv = %d to %d\n",
2558 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2559 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2560}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002561
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002562enum {
2563 CHG_IN_PROGRESS,
2564 CHG_NOT_IN_PROGRESS,
2565 CHG_FINISHED,
2566};
2567
2568#define VBAT_TOLERANCE_MV 70
2569#define CHG_DISABLE_MSLEEP 100
2570static int is_charging_finished(struct pm8921_chg_chip *chip)
2571{
2572 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2573 int ichg_meas_ma, iterm_programmed;
2574 int regulation_loop, fast_chg, vcp;
2575 int rc;
2576 static int last_vbat_programmed = -EINVAL;
2577
2578 if (!is_ext_charging(chip)) {
2579 /* return if the battery is not being fastcharged */
2580 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2581 pr_debug("fast_chg = %d\n", fast_chg);
2582 if (fast_chg == 0)
2583 return CHG_NOT_IN_PROGRESS;
2584
2585 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2586 pr_debug("vcp = %d\n", vcp);
2587 if (vcp == 1)
2588 return CHG_IN_PROGRESS;
2589
2590 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2591 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2592 if (vbatdet_low == 1)
2593 return CHG_IN_PROGRESS;
2594
2595 /* reset count if battery is hot/cold */
2596 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2597 pr_debug("batt_temp_ok = %d\n", rc);
2598 if (rc == 0)
2599 return CHG_IN_PROGRESS;
2600
2601 /* reset count if battery voltage is less than vddmax */
2602 vbat_meas_uv = get_prop_battery_uvolts(chip);
2603 if (vbat_meas_uv < 0)
2604 return CHG_IN_PROGRESS;
2605 vbat_meas_mv = vbat_meas_uv / 1000;
2606
2607 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2608 if (rc) {
2609 pr_err("couldnt read vddmax rc = %d\n", rc);
2610 return CHG_IN_PROGRESS;
2611 }
2612 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2613 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002614
2615 if (last_vbat_programmed == -EINVAL)
2616 last_vbat_programmed = vbat_programmed;
2617 if (last_vbat_programmed != vbat_programmed) {
2618 /* vddmax changed, reset and check again */
2619 pr_debug("vddmax = %d last_vdd_max=%d\n",
2620 vbat_programmed, last_vbat_programmed);
2621 last_vbat_programmed = vbat_programmed;
2622 return CHG_IN_PROGRESS;
2623 }
2624
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002625 regulation_loop = pm_chg_get_regulation_loop(chip);
2626 if (regulation_loop < 0) {
2627 pr_err("couldnt read the regulation loop err=%d\n",
2628 regulation_loop);
2629 return CHG_IN_PROGRESS;
2630 }
2631 pr_debug("regulation_loop=%d\n", regulation_loop);
2632
2633 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2634 return CHG_IN_PROGRESS;
2635 } /* !is_ext_charging */
2636
2637 /* reset count if battery chg current is more than iterm */
2638 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2639 if (rc) {
2640 pr_err("couldnt read iterm rc = %d\n", rc);
2641 return CHG_IN_PROGRESS;
2642 }
2643
2644 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2645 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2646 iterm_programmed, ichg_meas_ma);
2647 /*
2648 * ichg_meas_ma < 0 means battery is drawing current
2649 * ichg_meas_ma > 0 means battery is providing current
2650 */
2651 if (ichg_meas_ma > 0)
2652 return CHG_IN_PROGRESS;
2653
2654 if (ichg_meas_ma * -1 > iterm_programmed)
2655 return CHG_IN_PROGRESS;
2656
2657 return CHG_FINISHED;
2658}
2659
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002660/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002661 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002662 * has happened
2663 *
2664 * If all conditions favouring, if the charge current is
2665 * less than the term current for three consecutive times
2666 * an EOC has happened.
2667 * The wakelock is released if there is no need to reshedule
2668 * - this happens when the battery is removed or EOC has
2669 * happened
2670 */
2671#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002672static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002673{
2674 struct delayed_work *dwork = to_delayed_work(work);
2675 struct pm8921_chg_chip *chip = container_of(dwork,
2676 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002677 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002678 int end;
2679
2680 pm_chg_failed_clear(chip, 1);
2681 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002682
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002683 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002684 count = 0;
2685 wake_unlock(&chip->eoc_wake_lock);
2686 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002687 }
2688
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002689 if (end == CHG_FINISHED) {
2690 count++;
2691 } else {
2692 count = 0;
2693 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002694
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002695 if (count == CONSECUTIVE_COUNT) {
2696 count = 0;
2697 pr_info("End of Charging\n");
2698
2699 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002700
Amir Samuelovd31ef502011-10-26 14:41:36 +02002701 if (is_ext_charging(chip))
2702 chip->ext_charge_done = true;
2703
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002704 if (chip->is_bat_warm || chip->is_bat_cool)
2705 chip->bms_notify.is_battery_full = 0;
2706 else
2707 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002708 /* declare end of charging by invoking chgdone interrupt */
2709 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2710 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002711 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002712 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002713 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002714 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002715 round_jiffies_relative(msecs_to_jiffies
2716 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002717 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002718}
2719
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002720static void btm_configure_work(struct work_struct *work)
2721{
2722 int rc;
2723
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002724 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002725 if (rc)
2726 pr_err("failed to configure btm rc=%d", rc);
2727}
2728
2729DECLARE_WORK(btm_config_work, btm_configure_work);
2730
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002731static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2732{
2733 unsigned int chg_current = chip->max_bat_chg_current;
2734
2735 if (chip->is_bat_cool)
2736 chg_current = min(chg_current, chip->cool_bat_chg_current);
2737
2738 if (chip->is_bat_warm)
2739 chg_current = min(chg_current, chip->warm_bat_chg_current);
2740
David Keitelfdef3a42011-12-14 19:02:54 -08002741 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002742 chg_current = min(chg_current,
2743 chip->thermal_mitigation[thermal_mitigation]);
2744
2745 pm_chg_ibatmax_set(the_chip, chg_current);
2746}
2747
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002748#define TEMP_HYSTERISIS_DEGC 2
2749static void battery_cool(bool enter)
2750{
2751 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002752 if (enter == the_chip->is_bat_cool)
2753 return;
2754 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002755 if (enter) {
2756 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002757 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002758 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002759 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002760 pm_chg_vbatdet_set(the_chip,
2761 the_chip->cool_bat_voltage
2762 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002763 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002764 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002765 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002766 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002767 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002768 the_chip->max_voltage_mv
2769 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002770 }
2771 schedule_work(&btm_config_work);
2772}
2773
2774static void battery_warm(bool enter)
2775{
2776 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002777 if (enter == the_chip->is_bat_warm)
2778 return;
2779 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002780 if (enter) {
2781 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002782 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002783 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002784 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002785 pm_chg_vbatdet_set(the_chip,
2786 the_chip->warm_bat_voltage
2787 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002788 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002789 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002790 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002791 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002792 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002793 the_chip->max_voltage_mv
2794 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002795 }
2796 schedule_work(&btm_config_work);
2797}
2798
2799static int configure_btm(struct pm8921_chg_chip *chip)
2800{
2801 int rc;
2802
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002803 if (chip->warm_temp_dc != INT_MIN)
2804 btm_config.btm_warm_fn = battery_warm;
2805 else
2806 btm_config.btm_warm_fn = NULL;
2807
2808 if (chip->cool_temp_dc != INT_MIN)
2809 btm_config.btm_cool_fn = battery_cool;
2810 else
2811 btm_config.btm_cool_fn = NULL;
2812
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002813 btm_config.low_thr_temp = chip->cool_temp_dc;
2814 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002815 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002816 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002817 if (rc)
2818 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002819 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002820 if (rc)
2821 pr_err("failed to start btm rc = %d\n", rc);
2822
2823 return rc;
2824}
2825
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002826/**
2827 * set_disable_status_param -
2828 *
2829 * Internal function to disable battery charging and also disable drawing
2830 * any current from the source. The device is forced to run on a battery
2831 * after this.
2832 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833static int set_disable_status_param(const char *val, struct kernel_param *kp)
2834{
2835 int ret;
2836 struct pm8921_chg_chip *chip = the_chip;
2837
2838 ret = param_set_int(val, kp);
2839 if (ret) {
2840 pr_err("error setting value %d\n", ret);
2841 return ret;
2842 }
2843 pr_info("factory set disable param to %d\n", charging_disabled);
2844 if (chip) {
2845 pm_chg_auto_enable(chip, !charging_disabled);
2846 pm_chg_charge_dis(chip, charging_disabled);
2847 }
2848 return 0;
2849}
2850module_param_call(disabled, set_disable_status_param, param_get_uint,
2851 &charging_disabled, 0644);
2852
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002853static int rconn_mohm;
2854static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2855{
2856 int ret;
2857 struct pm8921_chg_chip *chip = the_chip;
2858
2859 ret = param_set_int(val, kp);
2860 if (ret) {
2861 pr_err("error setting value %d\n", ret);
2862 return ret;
2863 }
2864 if (chip)
2865 chip->rconn_mohm = rconn_mohm;
2866 return 0;
2867}
2868module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2869 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002870/**
2871 * set_thermal_mitigation_level -
2872 *
2873 * Internal function to control battery charging current to reduce
2874 * temperature
2875 */
2876static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2877{
2878 int ret;
2879 struct pm8921_chg_chip *chip = the_chip;
2880
2881 ret = param_set_int(val, kp);
2882 if (ret) {
2883 pr_err("error setting value %d\n", ret);
2884 return ret;
2885 }
2886
2887 if (!chip) {
2888 pr_err("called before init\n");
2889 return -EINVAL;
2890 }
2891
2892 if (!chip->thermal_mitigation) {
2893 pr_err("no thermal mitigation\n");
2894 return -EINVAL;
2895 }
2896
2897 if (thermal_mitigation < 0
2898 || thermal_mitigation >= chip->thermal_levels) {
2899 pr_err("out of bound level selected\n");
2900 return -EINVAL;
2901 }
2902
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002903 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002904 return ret;
2905}
2906module_param_call(thermal_mitigation, set_therm_mitigation_level,
2907 param_get_uint,
2908 &thermal_mitigation, 0644);
2909
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002910static int set_usb_max_current(const char *val, struct kernel_param *kp)
2911{
2912 int ret, mA;
2913 struct pm8921_chg_chip *chip = the_chip;
2914
2915 ret = param_set_int(val, kp);
2916 if (ret) {
2917 pr_err("error setting value %d\n", ret);
2918 return ret;
2919 }
2920 if (chip) {
2921 pr_warn("setting current max to %d\n", usb_max_current);
2922 pm_chg_iusbmax_get(chip, &mA);
2923 if (mA > usb_max_current)
2924 pm8921_charger_vbus_draw(usb_max_current);
2925 return 0;
2926 }
2927 return -EINVAL;
2928}
David Keitelacf57c82012-03-07 18:48:50 -08002929module_param_call(usb_max_current, set_usb_max_current,
2930 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932static void free_irqs(struct pm8921_chg_chip *chip)
2933{
2934 int i;
2935
2936 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2937 if (chip->pmic_chg_irq[i]) {
2938 free_irq(chip->pmic_chg_irq[i], chip);
2939 chip->pmic_chg_irq[i] = 0;
2940 }
2941}
2942
David Keitel88e1b572012-01-11 11:57:14 -08002943/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2945{
2946 unsigned long flags;
2947 int fsm_state;
2948
2949 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2950 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2951
2952 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002953 if (chip->usb_present) {
2954 schedule_delayed_work(&chip->unplug_check_work,
2955 round_jiffies_relative(msecs_to_jiffies
2956 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002957 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002958 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959
2960 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2961 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2962 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002963 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2964 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2965 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2966 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2967 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002968 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002969 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2970 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002971 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972
2973 spin_lock_irqsave(&vbus_lock, flags);
2974 if (usb_chg_current) {
2975 /* reissue a vbus draw call */
2976 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002977 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978 }
2979 spin_unlock_irqrestore(&vbus_lock, flags);
2980
2981 fsm_state = pm_chg_get_fsm_state(chip);
2982 if (is_battery_charging(fsm_state)) {
2983 chip->bms_notify.is_charging = 1;
2984 pm8921_bms_charging_began();
2985 }
2986
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002987 check_battery_valid(chip);
2988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2990 chip->usb_present,
2991 chip->dc_present,
2992 get_prop_batt_present(chip),
2993 fsm_state);
2994}
2995
2996struct pm_chg_irq_init_data {
2997 unsigned int irq_id;
2998 char *name;
2999 unsigned long flags;
3000 irqreturn_t (*handler)(int, void *);
3001};
3002
3003#define CHG_IRQ(_id, _flags, _handler) \
3004{ \
3005 .irq_id = _id, \
3006 .name = #_id, \
3007 .flags = _flags, \
3008 .handler = _handler, \
3009}
3010struct pm_chg_irq_init_data chg_irq_data[] = {
3011 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3012 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003013 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3015 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003016 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3017 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3019 usbin_uv_irq_handler),
3020 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3021 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3022 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3023 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3024 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3025 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3026 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3027 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3028 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003029 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3030 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3032 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3033 batt_removed_irq_handler),
3034 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3035 batttemp_hot_irq_handler),
3036 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3037 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3038 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003039 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3040 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003041 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3042 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003043 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3044 coarse_det_low_irq_handler),
3045 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3046 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3047 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3048 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3049 batfet_irq_handler),
3050 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3051 dcin_valid_irq_handler),
3052 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3053 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003054 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055};
3056
3057static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3058 struct platform_device *pdev)
3059{
3060 struct resource *res;
3061 int ret, i;
3062
3063 ret = 0;
3064 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3065
3066 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3067 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3068 chg_irq_data[i].name);
3069 if (res == NULL) {
3070 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3071 goto err_out;
3072 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003073 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074 ret = request_irq(res->start, chg_irq_data[i].handler,
3075 chg_irq_data[i].flags,
3076 chg_irq_data[i].name, chip);
3077 if (ret < 0) {
3078 pr_err("couldn't request %d (%s) %d\n", res->start,
3079 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003080 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 goto err_out;
3082 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3084 }
3085 return 0;
3086
3087err_out:
3088 free_irqs(chip);
3089 return -EINVAL;
3090}
3091
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003092static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3093{
3094 int err;
3095 u8 temp;
3096
3097 temp = 0xD1;
3098 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3099 if (err) {
3100 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3101 return;
3102 }
3103
3104 temp = 0xD3;
3105 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3106 if (err) {
3107 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3108 return;
3109 }
3110
3111 temp = 0xD1;
3112 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3113 if (err) {
3114 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3115 return;
3116 }
3117
3118 temp = 0xD5;
3119 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3120 if (err) {
3121 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3122 return;
3123 }
3124
3125 udelay(183);
3126
3127 temp = 0xD1;
3128 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3129 if (err) {
3130 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3131 return;
3132 }
3133
3134 temp = 0xD0;
3135 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3136 if (err) {
3137 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3138 return;
3139 }
3140 udelay(32);
3141
3142 temp = 0xD1;
3143 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3144 if (err) {
3145 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3146 return;
3147 }
3148
3149 temp = 0xD3;
3150 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3151 if (err) {
3152 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3153 return;
3154 }
3155}
3156
3157static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3158{
3159 int err;
3160 u8 temp;
3161
3162 temp = 0xD1;
3163 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3164 if (err) {
3165 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3166 return;
3167 }
3168
3169 temp = 0xD0;
3170 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3171 if (err) {
3172 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3173 return;
3174 }
3175}
3176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177#define ENUM_TIMER_STOP_BIT BIT(1)
3178#define BOOT_DONE_BIT BIT(6)
3179#define CHG_BATFET_ON_BIT BIT(3)
3180#define CHG_VCP_EN BIT(0)
3181#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3182#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003183#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3185{
3186 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003187 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003188
3189 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3190 BOOT_DONE_BIT, BOOT_DONE_BIT);
3191 if (rc) {
3192 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3193 return rc;
3194 }
3195
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003196 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3197
3198 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3199 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3200
3201 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203 if (rc) {
3204 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003205 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206 return rc;
3207 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003208 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003209 chip->max_voltage_mv
3210 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 if (rc) {
3212 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003213 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 return rc;
3215 }
3216
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003217 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 if (rc) {
3219 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003220 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 return rc;
3222 }
3223 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3224 if (rc) {
3225 pr_err("Failed to set max voltage to %d rc=%d\n",
3226 SAFE_CURRENT_MA, rc);
3227 return rc;
3228 }
3229
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003230 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003231 if (rc) {
3232 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3233 return rc;
3234 }
3235
3236 rc = pm_chg_iterm_set(chip, chip->term_current);
3237 if (rc) {
3238 pr_err("Failed to set term current to %d rc=%d\n",
3239 chip->term_current, rc);
3240 return rc;
3241 }
3242
3243 /* Disable the ENUM TIMER */
3244 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3245 ENUM_TIMER_STOP_BIT);
3246 if (rc) {
3247 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3248 return rc;
3249 }
3250
3251 /* init with the lowest USB current */
David Keitelacf57c82012-03-07 18:48:50 -08003252 rc = pm_chg_iusbmax_set(chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003253 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08003254 pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 return rc;
3256 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003257
3258 if (chip->safety_time != 0) {
3259 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3260 if (rc) {
3261 pr_err("Failed to set max time to %d minutes rc=%d\n",
3262 chip->safety_time, rc);
3263 return rc;
3264 }
3265 }
3266
3267 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003268 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003269 if (rc) {
3270 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3271 chip->safety_time, rc);
3272 return rc;
3273 }
3274 }
3275
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003276 if (chip->vin_min != 0) {
3277 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3278 if (rc) {
3279 pr_err("Failed to set vin min to %d mV rc=%d\n",
3280 chip->vin_min, rc);
3281 return rc;
3282 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003283 } else {
3284 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003285 }
3286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287 rc = pm_chg_disable_wd(chip);
3288 if (rc) {
3289 pr_err("Failed to disable wd rc=%d\n", rc);
3290 return rc;
3291 }
3292
3293 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3294 CHG_BAT_TEMP_DIS_BIT, 0);
3295 if (rc) {
3296 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3297 return rc;
3298 }
3299 /* switch to a 3.2Mhz for the buck */
3300 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3301 if (rc) {
3302 pr_err("Failed to switch buck clk rc=%d\n", rc);
3303 return rc;
3304 }
3305
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003306 if (chip->trkl_voltage != 0) {
3307 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3308 if (rc) {
3309 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3310 chip->trkl_voltage, rc);
3311 return rc;
3312 }
3313 }
3314
3315 if (chip->weak_voltage != 0) {
3316 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3317 if (rc) {
3318 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3319 chip->weak_voltage, rc);
3320 return rc;
3321 }
3322 }
3323
3324 if (chip->trkl_current != 0) {
3325 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3326 if (rc) {
3327 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3328 chip->trkl_voltage, rc);
3329 return rc;
3330 }
3331 }
3332
3333 if (chip->weak_current != 0) {
3334 rc = pm_chg_iweak_set(chip, chip->weak_current);
3335 if (rc) {
3336 pr_err("Failed to set weak current to %dmA rc=%d\n",
3337 chip->weak_current, rc);
3338 return rc;
3339 }
3340 }
3341
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003342 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3343 if (rc) {
3344 pr_err("Failed to set cold config %d rc=%d\n",
3345 chip->cold_thr, rc);
3346 }
3347
3348 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3349 if (rc) {
3350 pr_err("Failed to set hot config %d rc=%d\n",
3351 chip->hot_thr, rc);
3352 }
3353
Jay Chokshid674a512012-03-15 14:06:04 -07003354 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3355 if (rc) {
3356 pr_err("Failed to set charger LED src config %d rc=%d\n",
3357 chip->led_src_config, rc);
3358 }
3359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003360 /* Workarounds for die 1.1 and 1.0 */
3361 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3362 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003363 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3364 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003365
3366 /* software workaround for correct battery_id detection */
3367 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3368 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3369 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3370 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3371 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3372 udelay(100);
3373 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 }
3375
David Keitelb51995e2011-11-18 17:03:31 -08003376 /* Workarounds for die 3.0 */
3377 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3378 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3379
3380 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3381
David Keitela3c0d822011-11-03 14:18:52 -07003382 /* Disable EOC FSM processing */
3383 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3384
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003385 pm8921_chg_force_19p2mhz_clk(chip);
3386
3387 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3388 VREF_BATT_THERM_FORCE_ON);
3389 if (rc)
3390 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003392 rc = pm_chg_charge_dis(chip, charging_disabled);
3393 if (rc) {
3394 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3395 return rc;
3396 }
3397
3398 rc = pm_chg_auto_enable(chip, !charging_disabled);
3399 if (rc) {
3400 pr_err("Failed to enable charging rc=%d\n", rc);
3401 return rc;
3402 }
3403
3404 return 0;
3405}
3406
3407static int get_rt_status(void *data, u64 * val)
3408{
3409 int i = (int)data;
3410 int ret;
3411
3412 /* global irq number is passed in via data */
3413 ret = pm_chg_get_rt_status(the_chip, i);
3414 *val = ret;
3415 return 0;
3416}
3417DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3418
3419static int get_fsm_status(void *data, u64 * val)
3420{
3421 u8 temp;
3422
3423 temp = pm_chg_get_fsm_state(the_chip);
3424 *val = temp;
3425 return 0;
3426}
3427DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3428
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003429static int get_reg_loop(void *data, u64 * val)
3430{
3431 u8 temp;
3432
3433 if (!the_chip) {
3434 pr_err("%s called before init\n", __func__);
3435 return -EINVAL;
3436 }
3437 temp = pm_chg_get_regulation_loop(the_chip);
3438 *val = temp;
3439 return 0;
3440}
3441DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003443static int get_reg(void *data, u64 * val)
3444{
3445 int addr = (int)data;
3446 int ret;
3447 u8 temp;
3448
3449 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3450 if (ret) {
3451 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3452 addr, temp, ret);
3453 return -EAGAIN;
3454 }
3455 *val = temp;
3456 return 0;
3457}
3458
3459static int set_reg(void *data, u64 val)
3460{
3461 int addr = (int)data;
3462 int ret;
3463 u8 temp;
3464
3465 temp = (u8) val;
3466 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3467 if (ret) {
3468 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3469 addr, temp, ret);
3470 return -EAGAIN;
3471 }
3472 return 0;
3473}
3474DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3475
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003476enum {
3477 BAT_WARM_ZONE,
3478 BAT_COOL_ZONE,
3479};
3480static int get_warm_cool(void *data, u64 * val)
3481{
3482 if (!the_chip) {
3483 pr_err("%s called before init\n", __func__);
3484 return -EINVAL;
3485 }
3486 if ((int)data == BAT_WARM_ZONE)
3487 *val = the_chip->is_bat_warm;
3488 if ((int)data == BAT_COOL_ZONE)
3489 *val = the_chip->is_bat_cool;
3490 return 0;
3491}
3492DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003494static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3495{
3496 int i;
3497
3498 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3499
3500 if (IS_ERR(chip->dent)) {
3501 pr_err("pmic charger couldnt create debugfs dir\n");
3502 return;
3503 }
3504
3505 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3506 (void *)CHG_CNTRL, &reg_fops);
3507 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3508 (void *)CHG_CNTRL_2, &reg_fops);
3509 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3510 (void *)CHG_CNTRL_3, &reg_fops);
3511 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3512 (void *)PBL_ACCESS1, &reg_fops);
3513 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3514 (void *)PBL_ACCESS2, &reg_fops);
3515 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3516 (void *)SYS_CONFIG_1, &reg_fops);
3517 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3518 (void *)SYS_CONFIG_2, &reg_fops);
3519 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3520 (void *)CHG_VDD_MAX, &reg_fops);
3521 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3522 (void *)CHG_VDD_SAFE, &reg_fops);
3523 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3524 (void *)CHG_VBAT_DET, &reg_fops);
3525 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3526 (void *)CHG_IBAT_MAX, &reg_fops);
3527 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3528 (void *)CHG_IBAT_SAFE, &reg_fops);
3529 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3530 (void *)CHG_VIN_MIN, &reg_fops);
3531 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3532 (void *)CHG_VTRICKLE, &reg_fops);
3533 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3534 (void *)CHG_ITRICKLE, &reg_fops);
3535 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3536 (void *)CHG_ITERM, &reg_fops);
3537 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3538 (void *)CHG_TCHG_MAX, &reg_fops);
3539 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3540 (void *)CHG_TWDOG, &reg_fops);
3541 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3542 (void *)CHG_TEMP_THRESH, &reg_fops);
3543 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3544 (void *)CHG_COMP_OVR, &reg_fops);
3545 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3546 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3547 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3548 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3549 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3550 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3551 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3552 (void *)CHG_TEST, &reg_fops);
3553
3554 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3555 &fsm_fops);
3556
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003557 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3558 &reg_loop_fops);
3559
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003560 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3561 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3562 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3563 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003565 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3566 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3567 debugfs_create_file(chg_irq_data[i].name, 0444,
3568 chip->dent,
3569 (void *)chg_irq_data[i].irq_id,
3570 &rt_fops);
3571 }
3572}
3573
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003574static int pm8921_charger_suspend_noirq(struct device *dev)
3575{
3576 int rc;
3577 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3578
3579 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3580 if (rc)
3581 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3582 pm8921_chg_set_hw_clk_switching(chip);
3583 return 0;
3584}
3585
3586static int pm8921_charger_resume_noirq(struct device *dev)
3587{
3588 int rc;
3589 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3590
3591 pm8921_chg_force_19p2mhz_clk(chip);
3592
3593 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3594 VREF_BATT_THERM_FORCE_ON);
3595 if (rc)
3596 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3597 return 0;
3598}
3599
David Keitelf2226022011-12-13 15:55:50 -08003600static int pm8921_charger_resume(struct device *dev)
3601{
3602 int rc;
3603 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3604
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003605 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003606 && !(chip->keep_btm_on_suspend)) {
3607 rc = pm8xxx_adc_btm_configure(&btm_config);
3608 if (rc)
3609 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3610
3611 rc = pm8xxx_adc_btm_start();
3612 if (rc)
3613 pr_err("couldn't restart btm rc=%d\n", rc);
3614 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003615 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3616 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3617 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3618 }
David Keitelf2226022011-12-13 15:55:50 -08003619 return 0;
3620}
3621
3622static int pm8921_charger_suspend(struct device *dev)
3623{
3624 int rc;
3625 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3626
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003627 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003628 && !(chip->keep_btm_on_suspend)) {
3629 rc = pm8xxx_adc_btm_end();
3630 if (rc)
3631 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3632 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003633
3634 if (is_usb_chg_plugged_in(chip)) {
3635 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3636 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3637 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003638
David Keitelf2226022011-12-13 15:55:50 -08003639 return 0;
3640}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003641static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3642{
3643 int rc = 0;
3644 struct pm8921_chg_chip *chip;
3645 const struct pm8921_charger_platform_data *pdata
3646 = pdev->dev.platform_data;
3647
3648 if (!pdata) {
3649 pr_err("missing platform data\n");
3650 return -EINVAL;
3651 }
3652
3653 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3654 GFP_KERNEL);
3655 if (!chip) {
3656 pr_err("Cannot allocate pm_chg_chip\n");
3657 return -ENOMEM;
3658 }
3659
3660 chip->dev = &pdev->dev;
3661 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003662 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003664 chip->max_voltage_mv = pdata->max_voltage;
3665 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003666 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667 chip->term_current = pdata->term_current;
3668 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003669 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003670 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3671 chip->batt_id_min = pdata->batt_id_min;
3672 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003673 if (pdata->cool_temp != INT_MIN)
3674 chip->cool_temp_dc = pdata->cool_temp * 10;
3675 else
3676 chip->cool_temp_dc = INT_MIN;
3677
3678 if (pdata->warm_temp != INT_MIN)
3679 chip->warm_temp_dc = pdata->warm_temp * 10;
3680 else
3681 chip->warm_temp_dc = INT_MIN;
3682
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003683 chip->temp_check_period = pdata->temp_check_period;
3684 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3685 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3686 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3687 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3688 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003689 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003690 chip->trkl_voltage = pdata->trkl_voltage;
3691 chip->weak_voltage = pdata->weak_voltage;
3692 chip->trkl_current = pdata->trkl_current;
3693 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003694 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003695 chip->thermal_mitigation = pdata->thermal_mitigation;
3696 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003698 chip->cold_thr = pdata->cold_thr;
3699 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003700 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003701 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 rc = pm8921_chg_hw_init(chip);
3704 if (rc) {
3705 pr_err("couldn't init hardware rc=%d\n", rc);
3706 goto free_chip;
3707 }
3708
3709 chip->usb_psy.name = "usb",
3710 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3711 chip->usb_psy.supplied_to = pm_power_supplied_to,
3712 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003713 chip->usb_psy.properties = pm_power_props_usb,
3714 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3715 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716
David Keitel6ed71a52012-01-30 12:42:18 -08003717 chip->dc_psy.name = "pm8921-dc",
3718 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3719 chip->dc_psy.supplied_to = pm_power_supplied_to,
3720 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003721 chip->dc_psy.properties = pm_power_props_mains,
3722 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3723 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 chip->batt_psy.name = "battery",
3726 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3727 chip->batt_psy.properties = msm_batt_power_props,
3728 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3729 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003730 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731 rc = power_supply_register(chip->dev, &chip->usb_psy);
3732 if (rc < 0) {
3733 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003734 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003735 }
3736
David Keitel6ed71a52012-01-30 12:42:18 -08003737 rc = power_supply_register(chip->dev, &chip->dc_psy);
3738 if (rc < 0) {
3739 pr_err("power_supply_register usb failed rc = %d\n", rc);
3740 goto unregister_usb;
3741 }
3742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003743 rc = power_supply_register(chip->dev, &chip->batt_psy);
3744 if (rc < 0) {
3745 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003746 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003747 }
3748
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003749 platform_set_drvdata(pdev, chip);
3750 the_chip = chip;
3751
3752 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003753 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003754 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3755 vin_collapse_check_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003756 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3757 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003758 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003759
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003760 rc = request_irqs(chip, pdev);
3761 if (rc) {
3762 pr_err("couldn't register interrupts rc=%d\n", rc);
3763 goto unregister_batt;
3764 }
3765
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003766 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3767 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3768 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003769 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3770 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003771 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003772 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003773 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003774 * care for jeita compliance
3775 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003776 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003777 rc = configure_btm(chip);
3778 if (rc) {
3779 pr_err("couldn't register with btm rc=%d\n", rc);
3780 goto free_irq;
3781 }
3782 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003784 create_debugfs_entries(chip);
3785
3786 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003787 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003788
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789 /* determine what state the charger is in */
3790 determine_initial_state(chip);
3791
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003792 if (chip->update_time) {
3793 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3794 update_heartbeat);
3795 schedule_delayed_work(&chip->update_heartbeat_work,
3796 round_jiffies_relative(msecs_to_jiffies
3797 (chip->update_time)));
3798 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799 return 0;
3800
3801free_irq:
3802 free_irqs(chip);
3803unregister_batt:
3804 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003805unregister_dc:
3806 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807unregister_usb:
3808 power_supply_unregister(&chip->usb_psy);
3809free_chip:
3810 kfree(chip);
3811 return rc;
3812}
3813
3814static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3815{
3816 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3817
3818 free_irqs(chip);
3819 platform_set_drvdata(pdev, NULL);
3820 the_chip = NULL;
3821 kfree(chip);
3822 return 0;
3823}
David Keitelf2226022011-12-13 15:55:50 -08003824static const struct dev_pm_ops pm8921_pm_ops = {
3825 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003826 .suspend_noirq = pm8921_charger_suspend_noirq,
3827 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003828 .resume = pm8921_charger_resume,
3829};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003831 .probe = pm8921_charger_probe,
3832 .remove = __devexit_p(pm8921_charger_remove),
3833 .driver = {
3834 .name = PM8921_CHARGER_DEV_NAME,
3835 .owner = THIS_MODULE,
3836 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837 },
3838};
3839
3840static int __init pm8921_charger_init(void)
3841{
3842 return platform_driver_register(&pm8921_charger_driver);
3843}
3844
3845static void __exit pm8921_charger_exit(void)
3846{
3847 platform_driver_unregister(&pm8921_charger_driver);
3848}
3849
3850late_initcall(pm8921_charger_init);
3851module_exit(pm8921_charger_exit);
3852
3853MODULE_LICENSE("GPL v2");
3854MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3855MODULE_VERSION("1.0");
3856MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);