blob: d24ce3fd907413659154dcca319bba3a8aa315bd [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
David Keitel4f9397b2012-04-16 11:46:16 -07001226static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1227{
1228 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1229}
1230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1232{
David Keitel4f9397b2012-04-16 11:46:16 -07001233 int percent_soc;
1234
1235 if (!get_prop_batt_present(chip))
1236 percent_soc = voltage_based_capacity(chip);
1237 else
1238 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001239
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001240 if (percent_soc == -ENXIO)
1241 percent_soc = voltage_based_capacity(chip);
1242
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001243 if (percent_soc <= 10)
1244 pr_warn("low battery charge = %d%%\n", percent_soc);
1245
1246 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247}
1248
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001249static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1250{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001251 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001252
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001253 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001254 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001255 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001256 }
1257
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001258 if (rc) {
1259 pr_err("unable to get batt current rc = %d\n", rc);
1260 return rc;
1261 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001262 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001263 }
1264}
1265
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001266static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1267{
1268 int rc;
1269
1270 rc = pm8921_bms_get_fcc();
1271 if (rc < 0)
1272 pr_err("unable to get batt fcc rc = %d\n", rc);
1273 return rc;
1274}
1275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1277{
1278 int temp;
1279
1280 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1281 if (temp)
1282 return POWER_SUPPLY_HEALTH_OVERHEAT;
1283
1284 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1285 if (temp)
1286 return POWER_SUPPLY_HEALTH_COLD;
1287
1288 return POWER_SUPPLY_HEALTH_GOOD;
1289}
1290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1292{
1293 int temp;
1294
Amir Samuelovd31ef502011-10-26 14:41:36 +02001295 if (!get_prop_batt_present(chip))
1296 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1297
1298 if (is_ext_trickle_charging(chip))
1299 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1300
1301 if (is_ext_charging(chip))
1302 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1305 if (temp)
1306 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1307
1308 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1309 if (temp)
1310 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1311
1312 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1313}
1314
1315static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1316{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001317 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1318 int fsm_state = pm_chg_get_fsm_state(chip);
1319 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320
David Keitel88e1b572012-01-11 11:57:14 -08001321 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001322 if (chip->ext_charge_done)
1323 return POWER_SUPPLY_STATUS_FULL;
1324 if (chip->ext_charging)
1325 return POWER_SUPPLY_STATUS_CHARGING;
1326 }
1327
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001328 for (i = 0; i < ARRAY_SIZE(map); i++)
1329 if (map[i].fsm_state == fsm_state)
1330 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001331
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001332 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1333 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1334 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001335 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1336 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001337
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001338 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001339 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001340 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341}
1342
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001343#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001344static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1345{
1346 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001347 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001348
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001349 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001350 if (rc) {
1351 pr_err("error reading adc channel = %d, rc = %d\n",
1352 chip->vbat_channel, rc);
1353 return rc;
1354 }
1355 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1356 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001357 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1358 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1359 (int) result.physical);
1360
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001361 return (int)result.physical;
1362}
1363
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364static int pm_batt_power_get_property(struct power_supply *psy,
1365 enum power_supply_property psp,
1366 union power_supply_propval *val)
1367{
1368 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1369 batt_psy);
1370
1371 switch (psp) {
1372 case POWER_SUPPLY_PROP_STATUS:
1373 val->intval = get_prop_batt_status(chip);
1374 break;
1375 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1376 val->intval = get_prop_charge_type(chip);
1377 break;
1378 case POWER_SUPPLY_PROP_HEALTH:
1379 val->intval = get_prop_batt_health(chip);
1380 break;
1381 case POWER_SUPPLY_PROP_PRESENT:
1382 val->intval = get_prop_batt_present(chip);
1383 break;
1384 case POWER_SUPPLY_PROP_TECHNOLOGY:
1385 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1386 break;
1387 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001388 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389 break;
1390 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001391 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 break;
1393 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001394 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 break;
1396 case POWER_SUPPLY_PROP_CAPACITY:
1397 val->intval = get_prop_batt_capacity(chip);
1398 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001399 case POWER_SUPPLY_PROP_CURRENT_NOW:
1400 val->intval = get_prop_batt_current(chip);
1401 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001402 case POWER_SUPPLY_PROP_TEMP:
1403 val->intval = get_prop_batt_temp(chip);
1404 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001405 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001406 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001407 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 default:
1409 return -EINVAL;
1410 }
1411
1412 return 0;
1413}
1414
1415static void (*notify_vbus_state_func_ptr)(int);
1416static int usb_chg_current;
1417static DEFINE_SPINLOCK(vbus_lock);
1418
1419int pm8921_charger_register_vbus_sn(void (*callback)(int))
1420{
1421 pr_debug("%p\n", callback);
1422 notify_vbus_state_func_ptr = callback;
1423 return 0;
1424}
1425EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1426
1427/* this is passed to the hsusb via platform_data msm_otg_pdata */
1428void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1429{
1430 pr_debug("%p\n", callback);
1431 notify_vbus_state_func_ptr = NULL;
1432}
1433EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1434
1435static void notify_usb_of_the_plugin_event(int plugin)
1436{
1437 plugin = !!plugin;
1438 if (notify_vbus_state_func_ptr) {
1439 pr_debug("notifying plugin\n");
1440 (*notify_vbus_state_func_ptr) (plugin);
1441 } else {
1442 pr_debug("unable to notify plugin\n");
1443 }
1444}
1445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446/* assumes vbus_lock is held */
1447static void __pm8921_charger_vbus_draw(unsigned int mA)
1448{
1449 int i, rc;
1450
1451 if (mA > 0 && mA <= 2) {
1452 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001453 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001455 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 }
1457 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1458 if (rc)
1459 pr_err("fail to set suspend bit rc=%d\n", rc);
1460 } else {
1461 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1462 if (rc)
1463 pr_err("fail to reset suspend bit rc=%d\n", rc);
1464 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1465 if (usb_ma_table[i].usb_ma <= mA)
1466 break;
1467 }
1468 if (i < 0)
1469 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001470 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001472 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 }
1474 }
1475}
1476
1477/* USB calls these to tell us how much max usb current the system can draw */
1478void pm8921_charger_vbus_draw(unsigned int mA)
1479{
1480 unsigned long flags;
1481
1482 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001483
1484 if (usb_max_current && mA > usb_max_current) {
1485 pr_warn("restricting usb current to %d instead of %d\n",
1486 usb_max_current, mA);
1487 mA = usb_max_current;
1488 }
1489 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1490 usb_target_ma = mA;
1491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 spin_lock_irqsave(&vbus_lock, flags);
1493 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001494 if (mA > USB_WALL_THRESHOLD_MA)
1495 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1496 else
1497 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 } else {
1499 /*
1500 * called before pmic initialized,
1501 * save this value and use it at probe
1502 */
David Keitelacf57c82012-03-07 18:48:50 -08001503 if (mA > USB_WALL_THRESHOLD_MA)
1504 usb_chg_current = USB_WALL_THRESHOLD_MA;
1505 else
1506 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 }
1508 spin_unlock_irqrestore(&vbus_lock, flags);
1509}
1510EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1511
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001512int pm8921_charger_enable(bool enable)
1513{
1514 int rc;
1515
1516 if (!the_chip) {
1517 pr_err("called before init\n");
1518 return -EINVAL;
1519 }
1520 enable = !!enable;
1521 rc = pm_chg_auto_enable(the_chip, enable);
1522 if (rc)
1523 pr_err("Failed rc=%d\n", rc);
1524 return rc;
1525}
1526EXPORT_SYMBOL(pm8921_charger_enable);
1527
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001528int pm8921_is_usb_chg_plugged_in(void)
1529{
1530 if (!the_chip) {
1531 pr_err("called before init\n");
1532 return -EINVAL;
1533 }
1534 return is_usb_chg_plugged_in(the_chip);
1535}
1536EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1537
1538int pm8921_is_dc_chg_plugged_in(void)
1539{
1540 if (!the_chip) {
1541 pr_err("called before init\n");
1542 return -EINVAL;
1543 }
1544 return is_dc_chg_plugged_in(the_chip);
1545}
1546EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1547
1548int pm8921_is_battery_present(void)
1549{
1550 if (!the_chip) {
1551 pr_err("called before init\n");
1552 return -EINVAL;
1553 }
1554 return get_prop_batt_present(the_chip);
1555}
1556EXPORT_SYMBOL(pm8921_is_battery_present);
1557
David Keitel012deef2011-12-02 11:49:33 -08001558/*
1559 * Disabling the charge current limit causes current
1560 * current limits to have no monitoring. An adequate charger
1561 * capable of supplying high current while sustaining VIN_MIN
1562 * is required if the limiting is disabled.
1563 */
1564int pm8921_disable_input_current_limit(bool disable)
1565{
1566 if (!the_chip) {
1567 pr_err("called before init\n");
1568 return -EINVAL;
1569 }
1570 if (disable) {
1571 pr_warn("Disabling input current limit!\n");
1572
1573 return pm8xxx_writeb(the_chip->dev->parent,
1574 CHG_BUCK_CTRL_TEST3, 0xF2);
1575 }
1576 return 0;
1577}
1578EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1579
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001580int pm8921_set_max_battery_charge_current(int ma)
1581{
1582 if (!the_chip) {
1583 pr_err("called before init\n");
1584 return -EINVAL;
1585 }
1586 return pm_chg_ibatmax_set(the_chip, ma);
1587}
1588EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1589
1590int pm8921_disable_source_current(bool disable)
1591{
1592 if (!the_chip) {
1593 pr_err("called before init\n");
1594 return -EINVAL;
1595 }
1596 if (disable)
1597 pr_warn("current drawn from chg=0, battery provides current\n");
1598 return pm_chg_charge_dis(the_chip, disable);
1599}
1600EXPORT_SYMBOL(pm8921_disable_source_current);
1601
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001602int pm8921_regulate_input_voltage(int voltage)
1603{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001604 int rc;
1605
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001606 if (!the_chip) {
1607 pr_err("called before init\n");
1608 return -EINVAL;
1609 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001610 rc = pm_chg_vinmin_set(the_chip, voltage);
1611
1612 if (rc == 0)
1613 the_chip->vin_min = voltage;
1614
1615 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001616}
1617
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001618#define USB_OV_THRESHOLD_MASK 0x60
1619#define USB_OV_THRESHOLD_SHIFT 5
1620int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1621{
1622 u8 temp;
1623
1624 if (!the_chip) {
1625 pr_err("called before init\n");
1626 return -EINVAL;
1627 }
1628
1629 if (ov > PM_USB_OV_7V) {
1630 pr_err("limiting to over voltage threshold to 7volts\n");
1631 ov = PM_USB_OV_7V;
1632 }
1633
1634 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1635
1636 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1637 USB_OV_THRESHOLD_MASK, temp);
1638}
1639EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1640
1641#define USB_DEBOUNCE_TIME_MASK 0x06
1642#define USB_DEBOUNCE_TIME_SHIFT 1
1643int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1644{
1645 u8 temp;
1646
1647 if (!the_chip) {
1648 pr_err("called before init\n");
1649 return -EINVAL;
1650 }
1651
1652 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1653 pr_err("limiting debounce to 80.5ms\n");
1654 ms = PM_USB_DEBOUNCE_80P5MS;
1655 }
1656
1657 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1658
1659 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1660 USB_DEBOUNCE_TIME_MASK, temp);
1661}
1662EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1663
1664#define USB_OVP_DISABLE_MASK 0x80
1665int pm8921_usb_ovp_disable(int disable)
1666{
1667 u8 temp = 0;
1668
1669 if (!the_chip) {
1670 pr_err("called before init\n");
1671 return -EINVAL;
1672 }
1673
1674 if (disable)
1675 temp = USB_OVP_DISABLE_MASK;
1676
1677 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1678 USB_OVP_DISABLE_MASK, temp);
1679}
1680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001681bool pm8921_is_battery_charging(int *source)
1682{
1683 int fsm_state, is_charging, dc_present, usb_present;
1684
1685 if (!the_chip) {
1686 pr_err("called before init\n");
1687 return -EINVAL;
1688 }
1689 fsm_state = pm_chg_get_fsm_state(the_chip);
1690 is_charging = is_battery_charging(fsm_state);
1691 if (is_charging == 0) {
1692 *source = PM8921_CHG_SRC_NONE;
1693 return is_charging;
1694 }
1695
1696 if (source == NULL)
1697 return is_charging;
1698
1699 /* the battery is charging, the source is requested, find it */
1700 dc_present = is_dc_chg_plugged_in(the_chip);
1701 usb_present = is_usb_chg_plugged_in(the_chip);
1702
1703 if (dc_present && !usb_present)
1704 *source = PM8921_CHG_SRC_DC;
1705
1706 if (usb_present && !dc_present)
1707 *source = PM8921_CHG_SRC_USB;
1708
1709 if (usb_present && dc_present)
1710 /*
1711 * The system always chooses dc for charging since it has
1712 * higher priority.
1713 */
1714 *source = PM8921_CHG_SRC_DC;
1715
1716 return is_charging;
1717}
1718EXPORT_SYMBOL(pm8921_is_battery_charging);
1719
1720int pm8921_batt_temperature(void)
1721{
1722 if (!the_chip) {
1723 pr_err("called before init\n");
1724 return -EINVAL;
1725 }
1726 return get_prop_batt_temp(the_chip);
1727}
1728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1730{
1731 int usb_present;
1732
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001733 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 usb_present = is_usb_chg_plugged_in(chip);
1735 if (chip->usb_present ^ usb_present) {
1736 notify_usb_of_the_plugin_event(usb_present);
1737 chip->usb_present = usb_present;
1738 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001739 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001740 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001742 if (usb_present) {
1743 schedule_delayed_work(&chip->unplug_check_work,
1744 round_jiffies_relative(msecs_to_jiffies
1745 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001746 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1747 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001748 /* USB unplugged reset target current */
1749 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001750 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001751 }
David Keitel8c5201a2012-02-24 16:08:54 -08001752 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001753 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754}
1755
Amir Samuelovd31ef502011-10-26 14:41:36 +02001756static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1757{
David Keitel88e1b572012-01-11 11:57:14 -08001758 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001759 pr_debug("external charger not registered.\n");
1760 return;
1761 }
1762
1763 if (!chip->ext_charging) {
1764 pr_debug("already not charging.\n");
1765 return;
1766 }
1767
David Keitel88e1b572012-01-11 11:57:14 -08001768 power_supply_set_charge_type(chip->ext_psy,
1769 POWER_SUPPLY_CHARGE_TYPE_NONE);
1770 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001771 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001772 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001773 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001774 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001775}
1776
1777static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1778{
1779 int dc_present;
1780 int batt_present;
1781 int batt_temp_ok;
1782 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001783 unsigned long delay =
1784 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1785
David Keitel88e1b572012-01-11 11:57:14 -08001786 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001787 pr_debug("external charger not registered.\n");
1788 return;
1789 }
1790
1791 if (chip->ext_charging) {
1792 pr_debug("already charging.\n");
1793 return;
1794 }
1795
David Keitel88e1b572012-01-11 11:57:14 -08001796 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001797 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1798 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001799
1800 if (!dc_present) {
1801 pr_warn("%s. dc not present.\n", __func__);
1802 return;
1803 }
1804 if (!batt_present) {
1805 pr_warn("%s. battery not present.\n", __func__);
1806 return;
1807 }
1808 if (!batt_temp_ok) {
1809 pr_warn("%s. battery temperature not ok.\n", __func__);
1810 return;
1811 }
David Keitel88e1b572012-01-11 11:57:14 -08001812 pm8921_disable_source_current(true); /* Force BATFET=ON */
1813 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001814 if (vbat_ov) {
1815 pr_warn("%s. battery over voltage.\n", __func__);
1816 return;
1817 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001818
David Keitel63f71662012-02-08 20:30:00 -08001819 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001820 power_supply_set_charge_type(chip->ext_psy,
1821 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001822 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001823 chip->ext_charging = true;
1824 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001825 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001826 /* Start BMS */
1827 schedule_delayed_work(&chip->eoc_work, delay);
1828 wake_lock(&chip->eoc_wake_lock);
1829}
1830
David Keitel8c5201a2012-02-24 16:08:54 -08001831static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001832{
1833 u8 temp;
1834 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001835
David Keitel8c5201a2012-02-24 16:08:54 -08001836 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001837 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001838 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1839 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001840 }
David Keitel8c5201a2012-02-24 16:08:54 -08001841 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1842 if (rc) {
1843 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1844 return;
1845 }
1846 /* set ovp fet disable bit and the write bit */
1847 temp |= 0x81;
1848 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1849 if (rc) {
1850 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1851 return;
1852 }
1853}
1854
1855static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1856{
1857 u8 temp;
1858 int rc;
1859
1860 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1861 if (rc) {
1862 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1863 return;
1864 }
1865 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1866 if (rc) {
1867 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1868 return;
1869 }
1870 /* unset ovp fet disable bit and set the write bit */
1871 temp &= 0xFE;
1872 temp |= 0x80;
1873 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1874 if (rc) {
1875 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1876 temp, rc);
1877 return;
1878 }
1879}
1880
1881static int param_open_ovp_counter = 10;
1882module_param(param_open_ovp_counter, int, 0644);
1883
1884#define WRITE_BANK_4 0xC0
1885#define USB_OVP_DEBOUNCE_TIME 0x06
1886static void unplug_ovp_fet_open_worker(struct work_struct *work)
1887{
1888 struct pm8921_chg_chip *chip = container_of(work,
1889 struct pm8921_chg_chip,
1890 unplug_ovp_fet_open_work);
1891 int chg_gone, usb_chg_plugged_in;
1892 int count = 0;
1893
1894 while (count++ < param_open_ovp_counter) {
1895 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1896 USB_OVP_DEBOUNCE_TIME, 0x0);
1897 usleep(10);
1898 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1899 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1900 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1901 count, chg_gone, usb_chg_plugged_in);
1902
1903 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1904 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1905 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1906 turn_off_usb_ovp_fet(chip);
1907
1908 msleep(20);
1909
1910 turn_on_usb_ovp_fet(chip);
1911 } else {
David Keitel712782e2012-03-29 14:11:47 -07001912 break;
David Keitel8c5201a2012-02-24 16:08:54 -08001913 }
1914 }
David Keitel712782e2012-03-29 14:11:47 -07001915 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1916 USB_OVP_DEBOUNCE_TIME, 0x2);
1917 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1918 count, chg_gone, usb_chg_plugged_in);
1919 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001920}
David Keitelacf57c82012-03-07 18:48:50 -08001921
1922static int find_usb_ma_value(int value)
1923{
1924 int i;
1925
1926 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1927 if (value >= usb_ma_table[i].usb_ma)
1928 break;
1929 }
1930
1931 return i;
1932}
1933
1934static void decrease_usb_ma_value(int *value)
1935{
1936 int i;
1937
1938 if (value) {
1939 i = find_usb_ma_value(*value);
1940 if (i > 0)
1941 i--;
1942 *value = usb_ma_table[i].usb_ma;
1943 }
1944}
1945
1946static void increase_usb_ma_value(int *value)
1947{
1948 int i;
1949
1950 if (value) {
1951 i = find_usb_ma_value(*value);
1952
1953 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
1954 i++;
1955 *value = usb_ma_table[i].usb_ma;
1956 }
1957}
1958
1959static void vin_collapse_check_worker(struct work_struct *work)
1960{
1961 struct delayed_work *dwork = to_delayed_work(work);
1962 struct pm8921_chg_chip *chip = container_of(dwork,
1963 struct pm8921_chg_chip, vin_collapse_check_work);
1964
1965 /* AICL only for wall-chargers */
1966 if (is_usb_chg_plugged_in(chip) &&
1967 usb_target_ma > USB_WALL_THRESHOLD_MA) {
1968 /* decrease usb_target_ma */
1969 decrease_usb_ma_value(&usb_target_ma);
1970 /* reset here, increase in unplug_check_worker */
1971 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1972 pr_debug("usb_now=%d, usb_target = %d\n",
1973 USB_WALL_THRESHOLD_MA, usb_target_ma);
1974 } else {
1975 handle_usb_insertion_removal(chip);
1976 }
1977}
1978
1979#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1981{
David Keitelacf57c82012-03-07 18:48:50 -08001982 if (usb_target_ma)
1983 schedule_delayed_work(&the_chip->vin_collapse_check_work,
1984 round_jiffies_relative(msecs_to_jiffies
1985 (VIN_MIN_COLLAPSE_CHECK_MS)));
1986 else
1987 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 return IRQ_HANDLED;
1989}
1990
1991static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1992{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001993 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 return IRQ_HANDLED;
1995}
1996
1997static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1998{
1999 struct pm8921_chg_chip *chip = data;
2000 int status;
2001
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002002 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2003 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002004 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 pr_debug("battery present=%d", status);
2006 power_supply_changed(&chip->batt_psy);
2007 return IRQ_HANDLED;
2008}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002009
2010/*
2011 * this interrupt used to restart charging a battery.
2012 *
2013 * Note: When DC-inserted the VBAT can't go low.
2014 * VPH_PWR is provided by the ext-charger.
2015 * After End-Of-Charging from DC, charging can be resumed only
2016 * if DC is removed and then inserted after the battery was in use.
2017 * Therefore the handle_start_ext_chg() is not called.
2018 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2020{
2021 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002022 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002024 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002025
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002026 if (high_transition) {
2027 /* enable auto charging */
2028 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002029 pr_info("batt fell below resume voltage %s\n",
2030 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002031 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002034 power_supply_changed(&chip->batt_psy);
2035 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002036 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 return IRQ_HANDLED;
2039}
2040
2041static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2042{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002043 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 return IRQ_HANDLED;
2045}
2046
2047static irqreturn_t vbat_ov_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 chgwdog_irq_handler(int irq, void *data)
2054{
2055 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2056 return IRQ_HANDLED;
2057}
2058
2059static irqreturn_t vcp_irq_handler(int irq, void *data)
2060{
David Keitel8c5201a2012-02-24 16:08:54 -08002061 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002062 return IRQ_HANDLED;
2063}
2064
2065static irqreturn_t atcdone_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 atcfail_irq_handler(int irq, void *data)
2072{
2073 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2074 return IRQ_HANDLED;
2075}
2076
2077static irqreturn_t chgdone_irq_handler(int irq, void *data)
2078{
2079 struct pm8921_chg_chip *chip = data;
2080
2081 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002082
2083 handle_stop_ext_chg(chip);
2084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 power_supply_changed(&chip->batt_psy);
2086 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002087 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002088
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002089 bms_notify_check(chip);
2090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 return IRQ_HANDLED;
2092}
2093
2094static irqreturn_t chgfail_irq_handler(int irq, void *data)
2095{
2096 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002097 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098
David Keitel753ec8d2011-11-02 10:56:37 -07002099 ret = pm_chg_failed_clear(chip, 1);
2100 if (ret)
2101 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2102
2103 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2104 get_prop_batt_present(chip),
2105 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2106 pm_chg_get_fsm_state(data));
2107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 power_supply_changed(&chip->batt_psy);
2109 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002110 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 return IRQ_HANDLED;
2112}
2113
2114static irqreturn_t chgstate_irq_handler(int irq, void *data)
2115{
2116 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117
2118 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2119 power_supply_changed(&chip->batt_psy);
2120 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002121 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002123 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125 return IRQ_HANDLED;
2126}
2127
David Keitel8c5201a2012-02-24 16:08:54 -08002128static int param_vin_disable_counter = 5;
2129module_param(param_vin_disable_counter, int, 0644);
2130
2131static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2132 int count, int usb_ma)
2133{
David Keitelacf57c82012-03-07 18:48:50 -08002134 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002135 pr_debug("count = %d iusb=500mA\n", count);
2136 disable_input_voltage_regulation(chip);
2137 pr_debug("count = %d disable_input_regulation\n", count);
2138
2139 msleep(20);
2140
2141 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2142 count,
2143 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2144 is_usb_chg_plugged_in(chip));
2145 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2146 count, usb_ma);
2147 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002148 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002149}
2150
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002151#define VIN_ACTIVE_BIT BIT(0)
2152#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2153#define VIN_MIN_INCREASE_MV 100
2154static void unplug_check_worker(struct work_struct *work)
2155{
2156 struct delayed_work *dwork = to_delayed_work(work);
2157 struct pm8921_chg_chip *chip = container_of(dwork,
2158 struct pm8921_chg_chip, unplug_check_work);
2159 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002160 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002161 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002162
David Keitelacf57c82012-03-07 18:48:50 -08002163 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002164 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2165 if (!usb_chg_plugged_in) {
2166 pr_debug("Stopping Unplug Check Worker since USB is removed"
2167 "reg_loop = %d, fsm = %d ibat = %d\n",
2168 pm_chg_get_regulation_loop(chip),
2169 pm_chg_get_fsm_state(chip),
2170 get_prop_batt_current(chip)
2171 );
2172 return;
2173 }
David Keitel8c5201a2012-02-24 16:08:54 -08002174
2175 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002176 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002177 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2178 disable_input_voltage_regulation(chip);
2179 return;
2180 }
2181
2182 if (usb_ma <= 100) {
2183 pr_debug(
2184 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2185 usb_ma);
2186 goto check_again_later;
2187 }
2188 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2189 pr_debug("chg gone irq is enabled\n");
2190
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002191 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002192 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002193
2194 if (reg_loop & VIN_ACTIVE_BIT) {
David Keitelacf57c82012-03-07 18:48:50 -08002195 decrease_usb_ma_value(&usb_ma);
2196 usb_target_ma = usb_ma;
2197 /* end AICL here */
2198 __pm8921_charger_vbus_draw(usb_ma);
2199 pr_debug("usb_now=%d, usb_target = %d\n",
2200 usb_ma, usb_target_ma);
2201 }
2202
2203 reg_loop = pm_chg_get_regulation_loop(chip);
2204 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2205
2206 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002207 ibat = get_prop_batt_current(chip);
2208
2209 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2210 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2211 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002212 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002213
David Keitel8c5201a2012-02-24 16:08:54 -08002214 while (count++ < param_vin_disable_counter
2215 && usb_chg_plugged_in == 1) {
2216 attempt_reverse_boost_fix(chip, count, usb_ma);
2217 usb_chg_plugged_in
2218 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002219 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002220 }
2221 }
2222
David Keitel8c5201a2012-02-24 16:08:54 -08002223 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2224 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2225
2226 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2227 /* run the worker directly */
2228 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2229 chg_gone, usb_chg_plugged_in);
2230 schedule_work(&chip->unplug_ovp_fet_open_work);
2231 }
2232
David Keitelacf57c82012-03-07 18:48:50 -08002233 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2234 /* only increase iusb_max if vin loop not active */
2235 if (usb_ma < usb_target_ma) {
2236 increase_usb_ma_value(&usb_ma);
2237 __pm8921_charger_vbus_draw(usb_ma);
2238 pr_debug("usb_now=%d, usb_target = %d\n",
2239 usb_ma, usb_target_ma);
2240 } else {
2241 usb_target_ma = usb_ma;
2242 }
2243 }
David Keitel8c5201a2012-02-24 16:08:54 -08002244check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002245 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002246 schedule_delayed_work(&chip->unplug_check_work,
2247 round_jiffies_relative(msecs_to_jiffies
2248 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2249}
2250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251static irqreturn_t loop_change_irq_handler(int irq, void *data)
2252{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002253 struct pm8921_chg_chip *chip = data;
2254
2255 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2256 pm_chg_get_fsm_state(data),
2257 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002258 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 return IRQ_HANDLED;
2260}
2261
2262static irqreturn_t fastchg_irq_handler(int irq, void *data)
2263{
2264 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002265 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002266
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002267 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2268 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2269 wake_lock(&chip->eoc_wake_lock);
2270 schedule_delayed_work(&chip->eoc_work,
2271 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002272 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002273 }
2274 power_supply_changed(&chip->batt_psy);
2275 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276 return IRQ_HANDLED;
2277}
2278
2279static irqreturn_t trklchg_irq_handler(int irq, void *data)
2280{
2281 struct pm8921_chg_chip *chip = data;
2282
2283 power_supply_changed(&chip->batt_psy);
2284 return IRQ_HANDLED;
2285}
2286
2287static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2288{
2289 struct pm8921_chg_chip *chip = data;
2290 int status;
2291
2292 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2293 pr_debug("battery present=%d state=%d", !status,
2294 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002295 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 power_supply_changed(&chip->batt_psy);
2297 return IRQ_HANDLED;
2298}
2299
2300static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2301{
2302 struct pm8921_chg_chip *chip = data;
2303
Amir Samuelovd31ef502011-10-26 14:41:36 +02002304 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002305 power_supply_changed(&chip->batt_psy);
2306 return IRQ_HANDLED;
2307}
2308
2309static irqreturn_t chghot_irq_handler(int irq, void *data)
2310{
2311 struct pm8921_chg_chip *chip = data;
2312
2313 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2314 power_supply_changed(&chip->batt_psy);
2315 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002316 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 return IRQ_HANDLED;
2318}
2319
2320static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2321{
2322 struct pm8921_chg_chip *chip = data;
2323
2324 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002325 handle_stop_ext_chg(chip);
2326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327 power_supply_changed(&chip->batt_psy);
2328 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 return IRQ_HANDLED;
2330}
2331
2332static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2333{
2334 struct pm8921_chg_chip *chip = data;
David Keitel0873d0f2012-03-29 11:44:49 -07002335 u8 reg;
2336 int rc, chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002337
2338 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2339 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2340
2341 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002342 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2343
2344 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, &reg);
2345 if (rc)
2346 pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
2347
2348 if (reg & CHG_USB_SUSPEND_BIT)
2349 return IRQ_HANDLED;
David Keitel8c5201a2012-02-24 16:08:54 -08002350 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 power_supply_changed(&chip->batt_psy);
2353 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354 return IRQ_HANDLED;
2355}
David Keitel52fda532011-11-10 10:43:44 -08002356/*
2357 *
2358 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2359 * fire for two cases:
2360 *
2361 * If the interrupt line switches to high temperature is okay
2362 * and thus charging begins.
2363 * If bat_temp_ok is low this means the temperature is now
2364 * too hot or cold, so charging is stopped.
2365 *
2366 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2368{
David Keitel52fda532011-11-10 10:43:44 -08002369 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 struct pm8921_chg_chip *chip = data;
2371
David Keitel52fda532011-11-10 10:43:44 -08002372 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2373
2374 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2375 bat_temp_ok, pm_chg_get_fsm_state(data));
2376
2377 if (bat_temp_ok)
2378 handle_start_ext_chg(chip);
2379 else
2380 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 power_supply_changed(&chip->batt_psy);
2383 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002384 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385 return IRQ_HANDLED;
2386}
2387
2388static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2389{
2390 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2391 return IRQ_HANDLED;
2392}
2393
2394static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2395{
2396 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2397 return IRQ_HANDLED;
2398}
2399
2400static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2401{
2402 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2403 return IRQ_HANDLED;
2404}
2405
2406static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2407{
2408 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2409 return IRQ_HANDLED;
2410}
2411
2412static irqreturn_t batfet_irq_handler(int irq, void *data)
2413{
2414 struct pm8921_chg_chip *chip = data;
2415
2416 pr_debug("vreg ov\n");
2417 power_supply_changed(&chip->batt_psy);
2418 return IRQ_HANDLED;
2419}
2420
2421static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2422{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002423 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002424 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002425
David Keitel88e1b572012-01-11 11:57:14 -08002426 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2427 if (chip->ext_psy)
2428 power_supply_set_online(chip->ext_psy, dc_present);
2429 chip->dc_present = dc_present;
2430 if (dc_present)
2431 handle_start_ext_chg(chip);
2432 else
2433 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434 return IRQ_HANDLED;
2435}
2436
2437static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2438{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002439 struct pm8921_chg_chip *chip = data;
2440
Amir Samuelovd31ef502011-10-26 14:41:36 +02002441 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 return IRQ_HANDLED;
2443}
2444
2445static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2446{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002447 struct pm8921_chg_chip *chip = data;
2448
Amir Samuelovd31ef502011-10-26 14:41:36 +02002449 handle_stop_ext_chg(chip);
2450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 return IRQ_HANDLED;
2452}
2453
David Keitel88e1b572012-01-11 11:57:14 -08002454static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2455{
2456 struct power_supply *psy = &the_chip->batt_psy;
2457 struct power_supply *epsy = dev_get_drvdata(dev);
2458 int i, dcin_irq;
2459
2460 /* Only search for external supply if none is registered */
2461 if (!the_chip->ext_psy) {
2462 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2463 for (i = 0; i < epsy->num_supplicants; i++) {
2464 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2465 if (!strncmp(epsy->name, "dc", 2)) {
2466 the_chip->ext_psy = epsy;
2467 dcin_valid_irq_handler(dcin_irq,
2468 the_chip);
2469 }
2470 }
2471 }
2472 }
2473 return 0;
2474}
2475
2476static void pm_batt_external_power_changed(struct power_supply *psy)
2477{
2478 /* Only look for an external supply if it hasn't been registered */
2479 if (!the_chip->ext_psy)
2480 class_for_each_device(power_supply_class, NULL, psy,
2481 __pm_batt_external_power_changed_work);
2482}
2483
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002484/**
2485 * update_heartbeat - internal function to update userspace
2486 * per update_time minutes
2487 *
2488 */
2489static void update_heartbeat(struct work_struct *work)
2490{
2491 struct delayed_work *dwork = to_delayed_work(work);
2492 struct pm8921_chg_chip *chip = container_of(dwork,
2493 struct pm8921_chg_chip, update_heartbeat_work);
2494
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002495 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002496 power_supply_changed(&chip->batt_psy);
2497 schedule_delayed_work(&chip->update_heartbeat_work,
2498 round_jiffies_relative(msecs_to_jiffies
2499 (chip->update_time)));
2500}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002501#define VDD_LOOP_ACTIVE_BIT BIT(3)
2502#define VDD_MAX_INCREASE_MV 400
2503static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2504module_param(vdd_max_increase_mv, int, 0644);
2505
2506static int ichg_threshold_ua = -400000;
2507module_param(ichg_threshold_ua, int, 0644);
2508static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2509{
2510 int ichg_meas_ua, vbat_uv;
2511 int ichg_meas_ma;
2512 int adj_vdd_max_mv, programmed_vdd_max;
2513 int vbat_batt_terminal_uv;
2514 int vbat_batt_terminal_mv;
2515 int reg_loop;
2516 int delta_mv = 0;
2517
2518 if (chip->rconn_mohm == 0) {
2519 pr_debug("Exiting as rconn_mohm is 0\n");
2520 return;
2521 }
2522 /* adjust vdd_max only in normal temperature zone */
2523 if (chip->is_bat_cool || chip->is_bat_warm) {
2524 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2525 chip->is_bat_cool, chip->is_bat_warm);
2526 return;
2527 }
2528
2529 reg_loop = pm_chg_get_regulation_loop(chip);
2530 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2531 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2532 reg_loop);
2533 return;
2534 }
2535
2536 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2537 &vbat_uv);
2538 if (ichg_meas_ua >= 0) {
2539 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2540 return;
2541 }
2542 if (ichg_meas_ua <= ichg_threshold_ua) {
2543 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2544 ichg_meas_ua, ichg_threshold_ua);
2545 return;
2546 }
2547 ichg_meas_ma = ichg_meas_ua / 1000;
2548
2549 /* rconn_mohm is in milliOhms */
2550 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2551 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2552 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2553
2554 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2555
2556 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2557 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2558 delta_mv,
2559 programmed_vdd_max,
2560 adj_vdd_max_mv);
2561
2562 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2563 pr_debug("adj vdd_max lower than default max voltage\n");
2564 return;
2565 }
2566
2567 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2568 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2569
2570 pr_debug("adjusting vdd_max_mv to %d to make "
2571 "vbat_batt_termial_uv = %d to %d\n",
2572 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2573 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2574}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002575
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002576enum {
2577 CHG_IN_PROGRESS,
2578 CHG_NOT_IN_PROGRESS,
2579 CHG_FINISHED,
2580};
2581
2582#define VBAT_TOLERANCE_MV 70
2583#define CHG_DISABLE_MSLEEP 100
2584static int is_charging_finished(struct pm8921_chg_chip *chip)
2585{
2586 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2587 int ichg_meas_ma, iterm_programmed;
2588 int regulation_loop, fast_chg, vcp;
2589 int rc;
2590 static int last_vbat_programmed = -EINVAL;
2591
2592 if (!is_ext_charging(chip)) {
2593 /* return if the battery is not being fastcharged */
2594 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2595 pr_debug("fast_chg = %d\n", fast_chg);
2596 if (fast_chg == 0)
2597 return CHG_NOT_IN_PROGRESS;
2598
2599 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2600 pr_debug("vcp = %d\n", vcp);
2601 if (vcp == 1)
2602 return CHG_IN_PROGRESS;
2603
2604 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2605 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2606 if (vbatdet_low == 1)
2607 return CHG_IN_PROGRESS;
2608
2609 /* reset count if battery is hot/cold */
2610 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2611 pr_debug("batt_temp_ok = %d\n", rc);
2612 if (rc == 0)
2613 return CHG_IN_PROGRESS;
2614
2615 /* reset count if battery voltage is less than vddmax */
2616 vbat_meas_uv = get_prop_battery_uvolts(chip);
2617 if (vbat_meas_uv < 0)
2618 return CHG_IN_PROGRESS;
2619 vbat_meas_mv = vbat_meas_uv / 1000;
2620
2621 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2622 if (rc) {
2623 pr_err("couldnt read vddmax rc = %d\n", rc);
2624 return CHG_IN_PROGRESS;
2625 }
2626 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2627 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002628
2629 if (last_vbat_programmed == -EINVAL)
2630 last_vbat_programmed = vbat_programmed;
2631 if (last_vbat_programmed != vbat_programmed) {
2632 /* vddmax changed, reset and check again */
2633 pr_debug("vddmax = %d last_vdd_max=%d\n",
2634 vbat_programmed, last_vbat_programmed);
2635 last_vbat_programmed = vbat_programmed;
2636 return CHG_IN_PROGRESS;
2637 }
2638
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002639 regulation_loop = pm_chg_get_regulation_loop(chip);
2640 if (regulation_loop < 0) {
2641 pr_err("couldnt read the regulation loop err=%d\n",
2642 regulation_loop);
2643 return CHG_IN_PROGRESS;
2644 }
2645 pr_debug("regulation_loop=%d\n", regulation_loop);
2646
2647 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2648 return CHG_IN_PROGRESS;
2649 } /* !is_ext_charging */
2650
2651 /* reset count if battery chg current is more than iterm */
2652 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2653 if (rc) {
2654 pr_err("couldnt read iterm rc = %d\n", rc);
2655 return CHG_IN_PROGRESS;
2656 }
2657
2658 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2659 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2660 iterm_programmed, ichg_meas_ma);
2661 /*
2662 * ichg_meas_ma < 0 means battery is drawing current
2663 * ichg_meas_ma > 0 means battery is providing current
2664 */
2665 if (ichg_meas_ma > 0)
2666 return CHG_IN_PROGRESS;
2667
2668 if (ichg_meas_ma * -1 > iterm_programmed)
2669 return CHG_IN_PROGRESS;
2670
2671 return CHG_FINISHED;
2672}
2673
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002674/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002675 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002676 * has happened
2677 *
2678 * If all conditions favouring, if the charge current is
2679 * less than the term current for three consecutive times
2680 * an EOC has happened.
2681 * The wakelock is released if there is no need to reshedule
2682 * - this happens when the battery is removed or EOC has
2683 * happened
2684 */
2685#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002686static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002687{
2688 struct delayed_work *dwork = to_delayed_work(work);
2689 struct pm8921_chg_chip *chip = container_of(dwork,
2690 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002691 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002692 int end;
2693
2694 pm_chg_failed_clear(chip, 1);
2695 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002696
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002697 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002698 count = 0;
2699 wake_unlock(&chip->eoc_wake_lock);
2700 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002701 }
2702
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002703 if (end == CHG_FINISHED) {
2704 count++;
2705 } else {
2706 count = 0;
2707 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002708
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002709 if (count == CONSECUTIVE_COUNT) {
2710 count = 0;
2711 pr_info("End of Charging\n");
2712
2713 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002714
Amir Samuelovd31ef502011-10-26 14:41:36 +02002715 if (is_ext_charging(chip))
2716 chip->ext_charge_done = true;
2717
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002718 if (chip->is_bat_warm || chip->is_bat_cool)
2719 chip->bms_notify.is_battery_full = 0;
2720 else
2721 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002722 /* declare end of charging by invoking chgdone interrupt */
2723 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2724 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002725 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002726 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002727 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002728 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002729 round_jiffies_relative(msecs_to_jiffies
2730 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002731 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002732}
2733
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002734static void btm_configure_work(struct work_struct *work)
2735{
2736 int rc;
2737
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002738 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002739 if (rc)
2740 pr_err("failed to configure btm rc=%d", rc);
2741}
2742
2743DECLARE_WORK(btm_config_work, btm_configure_work);
2744
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002745static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2746{
2747 unsigned int chg_current = chip->max_bat_chg_current;
2748
2749 if (chip->is_bat_cool)
2750 chg_current = min(chg_current, chip->cool_bat_chg_current);
2751
2752 if (chip->is_bat_warm)
2753 chg_current = min(chg_current, chip->warm_bat_chg_current);
2754
David Keitelfdef3a42011-12-14 19:02:54 -08002755 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002756 chg_current = min(chg_current,
2757 chip->thermal_mitigation[thermal_mitigation]);
2758
2759 pm_chg_ibatmax_set(the_chip, chg_current);
2760}
2761
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002762#define TEMP_HYSTERISIS_DEGC 2
2763static void battery_cool(bool enter)
2764{
2765 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002766 if (enter == the_chip->is_bat_cool)
2767 return;
2768 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002769 if (enter) {
2770 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002771 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002772 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002773 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002774 pm_chg_vbatdet_set(the_chip,
2775 the_chip->cool_bat_voltage
2776 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002777 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002778 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002779 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002780 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002781 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002782 the_chip->max_voltage_mv
2783 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002784 }
2785 schedule_work(&btm_config_work);
2786}
2787
2788static void battery_warm(bool enter)
2789{
2790 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002791 if (enter == the_chip->is_bat_warm)
2792 return;
2793 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002794 if (enter) {
2795 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002796 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002797 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002798 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002799 pm_chg_vbatdet_set(the_chip,
2800 the_chip->warm_bat_voltage
2801 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002802 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002803 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002804 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002805 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002806 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002807 the_chip->max_voltage_mv
2808 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002809 }
2810 schedule_work(&btm_config_work);
2811}
2812
2813static int configure_btm(struct pm8921_chg_chip *chip)
2814{
2815 int rc;
2816
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002817 if (chip->warm_temp_dc != INT_MIN)
2818 btm_config.btm_warm_fn = battery_warm;
2819 else
2820 btm_config.btm_warm_fn = NULL;
2821
2822 if (chip->cool_temp_dc != INT_MIN)
2823 btm_config.btm_cool_fn = battery_cool;
2824 else
2825 btm_config.btm_cool_fn = NULL;
2826
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002827 btm_config.low_thr_temp = chip->cool_temp_dc;
2828 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002829 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002830 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002831 if (rc)
2832 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002833 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002834 if (rc)
2835 pr_err("failed to start btm rc = %d\n", rc);
2836
2837 return rc;
2838}
2839
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002840/**
2841 * set_disable_status_param -
2842 *
2843 * Internal function to disable battery charging and also disable drawing
2844 * any current from the source. The device is forced to run on a battery
2845 * after this.
2846 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002847static int set_disable_status_param(const char *val, struct kernel_param *kp)
2848{
2849 int ret;
2850 struct pm8921_chg_chip *chip = the_chip;
2851
2852 ret = param_set_int(val, kp);
2853 if (ret) {
2854 pr_err("error setting value %d\n", ret);
2855 return ret;
2856 }
2857 pr_info("factory set disable param to %d\n", charging_disabled);
2858 if (chip) {
2859 pm_chg_auto_enable(chip, !charging_disabled);
2860 pm_chg_charge_dis(chip, charging_disabled);
2861 }
2862 return 0;
2863}
2864module_param_call(disabled, set_disable_status_param, param_get_uint,
2865 &charging_disabled, 0644);
2866
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002867static int rconn_mohm;
2868static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2869{
2870 int ret;
2871 struct pm8921_chg_chip *chip = the_chip;
2872
2873 ret = param_set_int(val, kp);
2874 if (ret) {
2875 pr_err("error setting value %d\n", ret);
2876 return ret;
2877 }
2878 if (chip)
2879 chip->rconn_mohm = rconn_mohm;
2880 return 0;
2881}
2882module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2883 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002884/**
2885 * set_thermal_mitigation_level -
2886 *
2887 * Internal function to control battery charging current to reduce
2888 * temperature
2889 */
2890static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2891{
2892 int ret;
2893 struct pm8921_chg_chip *chip = the_chip;
2894
2895 ret = param_set_int(val, kp);
2896 if (ret) {
2897 pr_err("error setting value %d\n", ret);
2898 return ret;
2899 }
2900
2901 if (!chip) {
2902 pr_err("called before init\n");
2903 return -EINVAL;
2904 }
2905
2906 if (!chip->thermal_mitigation) {
2907 pr_err("no thermal mitigation\n");
2908 return -EINVAL;
2909 }
2910
2911 if (thermal_mitigation < 0
2912 || thermal_mitigation >= chip->thermal_levels) {
2913 pr_err("out of bound level selected\n");
2914 return -EINVAL;
2915 }
2916
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002917 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002918 return ret;
2919}
2920module_param_call(thermal_mitigation, set_therm_mitigation_level,
2921 param_get_uint,
2922 &thermal_mitigation, 0644);
2923
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002924static int set_usb_max_current(const char *val, struct kernel_param *kp)
2925{
2926 int ret, mA;
2927 struct pm8921_chg_chip *chip = the_chip;
2928
2929 ret = param_set_int(val, kp);
2930 if (ret) {
2931 pr_err("error setting value %d\n", ret);
2932 return ret;
2933 }
2934 if (chip) {
2935 pr_warn("setting current max to %d\n", usb_max_current);
2936 pm_chg_iusbmax_get(chip, &mA);
2937 if (mA > usb_max_current)
2938 pm8921_charger_vbus_draw(usb_max_current);
2939 return 0;
2940 }
2941 return -EINVAL;
2942}
David Keitelacf57c82012-03-07 18:48:50 -08002943module_param_call(usb_max_current, set_usb_max_current,
2944 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946static void free_irqs(struct pm8921_chg_chip *chip)
2947{
2948 int i;
2949
2950 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2951 if (chip->pmic_chg_irq[i]) {
2952 free_irq(chip->pmic_chg_irq[i], chip);
2953 chip->pmic_chg_irq[i] = 0;
2954 }
2955}
2956
David Keitel88e1b572012-01-11 11:57:14 -08002957/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2959{
2960 unsigned long flags;
2961 int fsm_state;
2962
2963 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2964 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2965
2966 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002967 if (chip->usb_present) {
2968 schedule_delayed_work(&chip->unplug_check_work,
2969 round_jiffies_relative(msecs_to_jiffies
2970 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002971 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002972 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973
2974 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2975 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2976 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002977 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2978 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2979 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2980 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2981 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002982 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002983 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2984 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002985 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986
2987 spin_lock_irqsave(&vbus_lock, flags);
2988 if (usb_chg_current) {
2989 /* reissue a vbus draw call */
2990 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002991 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992 }
2993 spin_unlock_irqrestore(&vbus_lock, flags);
2994
2995 fsm_state = pm_chg_get_fsm_state(chip);
2996 if (is_battery_charging(fsm_state)) {
2997 chip->bms_notify.is_charging = 1;
2998 pm8921_bms_charging_began();
2999 }
3000
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003001 check_battery_valid(chip);
3002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3004 chip->usb_present,
3005 chip->dc_present,
3006 get_prop_batt_present(chip),
3007 fsm_state);
3008}
3009
3010struct pm_chg_irq_init_data {
3011 unsigned int irq_id;
3012 char *name;
3013 unsigned long flags;
3014 irqreturn_t (*handler)(int, void *);
3015};
3016
3017#define CHG_IRQ(_id, _flags, _handler) \
3018{ \
3019 .irq_id = _id, \
3020 .name = #_id, \
3021 .flags = _flags, \
3022 .handler = _handler, \
3023}
3024struct pm_chg_irq_init_data chg_irq_data[] = {
3025 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3026 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003027 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3029 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003030 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3031 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003032 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3033 usbin_uv_irq_handler),
3034 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3035 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3036 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3037 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3038 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3039 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3040 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3041 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3042 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003043 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3044 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3046 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3047 batt_removed_irq_handler),
3048 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3049 batttemp_hot_irq_handler),
3050 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3051 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3052 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003053 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3054 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003055 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3056 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3058 coarse_det_low_irq_handler),
3059 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3060 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3061 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3062 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3063 batfet_irq_handler),
3064 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3065 dcin_valid_irq_handler),
3066 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3067 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003068 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069};
3070
3071static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3072 struct platform_device *pdev)
3073{
3074 struct resource *res;
3075 int ret, i;
3076
3077 ret = 0;
3078 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3079
3080 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3081 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3082 chg_irq_data[i].name);
3083 if (res == NULL) {
3084 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3085 goto err_out;
3086 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003087 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 ret = request_irq(res->start, chg_irq_data[i].handler,
3089 chg_irq_data[i].flags,
3090 chg_irq_data[i].name, chip);
3091 if (ret < 0) {
3092 pr_err("couldn't request %d (%s) %d\n", res->start,
3093 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003094 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 goto err_out;
3096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3098 }
3099 return 0;
3100
3101err_out:
3102 free_irqs(chip);
3103 return -EINVAL;
3104}
3105
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003106static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3107{
3108 int err;
3109 u8 temp;
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 = 0xD3;
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 temp = 0xD1;
3126 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3127 if (err) {
3128 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3129 return;
3130 }
3131
3132 temp = 0xD5;
3133 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3134 if (err) {
3135 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3136 return;
3137 }
3138
3139 udelay(183);
3140
3141 temp = 0xD1;
3142 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3143 if (err) {
3144 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3145 return;
3146 }
3147
3148 temp = 0xD0;
3149 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3150 if (err) {
3151 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3152 return;
3153 }
3154 udelay(32);
3155
3156 temp = 0xD1;
3157 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3158 if (err) {
3159 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3160 return;
3161 }
3162
3163 temp = 0xD3;
3164 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3165 if (err) {
3166 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3167 return;
3168 }
3169}
3170
3171static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3172{
3173 int err;
3174 u8 temp;
3175
3176 temp = 0xD1;
3177 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3178 if (err) {
3179 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3180 return;
3181 }
3182
3183 temp = 0xD0;
3184 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3185 if (err) {
3186 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3187 return;
3188 }
3189}
3190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003191#define ENUM_TIMER_STOP_BIT BIT(1)
3192#define BOOT_DONE_BIT BIT(6)
3193#define CHG_BATFET_ON_BIT BIT(3)
3194#define CHG_VCP_EN BIT(0)
3195#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3196#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003197#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3199{
3200 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003201 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202
3203 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3204 BOOT_DONE_BIT, BOOT_DONE_BIT);
3205 if (rc) {
3206 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3207 return rc;
3208 }
3209
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003210 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3211
3212 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3213 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3214
3215 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003217 if (rc) {
3218 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003219 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 return rc;
3221 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003222 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003223 chip->max_voltage_mv
3224 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003225 if (rc) {
3226 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003227 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003228 return rc;
3229 }
3230
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003231 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 if (rc) {
3233 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003234 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 return rc;
3236 }
3237 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3238 if (rc) {
3239 pr_err("Failed to set max voltage to %d rc=%d\n",
3240 SAFE_CURRENT_MA, rc);
3241 return rc;
3242 }
3243
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003244 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003245 if (rc) {
3246 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3247 return rc;
3248 }
3249
3250 rc = pm_chg_iterm_set(chip, chip->term_current);
3251 if (rc) {
3252 pr_err("Failed to set term current to %d rc=%d\n",
3253 chip->term_current, rc);
3254 return rc;
3255 }
3256
3257 /* Disable the ENUM TIMER */
3258 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3259 ENUM_TIMER_STOP_BIT);
3260 if (rc) {
3261 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3262 return rc;
3263 }
3264
3265 /* init with the lowest USB current */
David Keitelacf57c82012-03-07 18:48:50 -08003266 rc = pm_chg_iusbmax_set(chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003267 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08003268 pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 return rc;
3270 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003271
3272 if (chip->safety_time != 0) {
3273 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3274 if (rc) {
3275 pr_err("Failed to set max time to %d minutes rc=%d\n",
3276 chip->safety_time, rc);
3277 return rc;
3278 }
3279 }
3280
3281 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003282 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003283 if (rc) {
3284 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3285 chip->safety_time, rc);
3286 return rc;
3287 }
3288 }
3289
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003290 if (chip->vin_min != 0) {
3291 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3292 if (rc) {
3293 pr_err("Failed to set vin min to %d mV rc=%d\n",
3294 chip->vin_min, rc);
3295 return rc;
3296 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003297 } else {
3298 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003299 }
3300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 rc = pm_chg_disable_wd(chip);
3302 if (rc) {
3303 pr_err("Failed to disable wd rc=%d\n", rc);
3304 return rc;
3305 }
3306
3307 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3308 CHG_BAT_TEMP_DIS_BIT, 0);
3309 if (rc) {
3310 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3311 return rc;
3312 }
3313 /* switch to a 3.2Mhz for the buck */
3314 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3315 if (rc) {
3316 pr_err("Failed to switch buck clk rc=%d\n", rc);
3317 return rc;
3318 }
3319
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003320 if (chip->trkl_voltage != 0) {
3321 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3322 if (rc) {
3323 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3324 chip->trkl_voltage, rc);
3325 return rc;
3326 }
3327 }
3328
3329 if (chip->weak_voltage != 0) {
3330 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3331 if (rc) {
3332 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3333 chip->weak_voltage, rc);
3334 return rc;
3335 }
3336 }
3337
3338 if (chip->trkl_current != 0) {
3339 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3340 if (rc) {
3341 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3342 chip->trkl_voltage, rc);
3343 return rc;
3344 }
3345 }
3346
3347 if (chip->weak_current != 0) {
3348 rc = pm_chg_iweak_set(chip, chip->weak_current);
3349 if (rc) {
3350 pr_err("Failed to set weak current to %dmA rc=%d\n",
3351 chip->weak_current, rc);
3352 return rc;
3353 }
3354 }
3355
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003356 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3357 if (rc) {
3358 pr_err("Failed to set cold config %d rc=%d\n",
3359 chip->cold_thr, rc);
3360 }
3361
3362 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3363 if (rc) {
3364 pr_err("Failed to set hot config %d rc=%d\n",
3365 chip->hot_thr, rc);
3366 }
3367
Jay Chokshid674a512012-03-15 14:06:04 -07003368 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3369 if (rc) {
3370 pr_err("Failed to set charger LED src config %d rc=%d\n",
3371 chip->led_src_config, rc);
3372 }
3373
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 /* Workarounds for die 1.1 and 1.0 */
3375 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3376 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3378 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003379
3380 /* software workaround for correct battery_id detection */
3381 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3382 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3383 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3384 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3385 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3386 udelay(100);
3387 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003388 }
3389
David Keitelb51995e2011-11-18 17:03:31 -08003390 /* Workarounds for die 3.0 */
3391 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3392 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3393
3394 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3395
David Keitela3c0d822011-11-03 14:18:52 -07003396 /* Disable EOC FSM processing */
3397 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3398
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003399 pm8921_chg_force_19p2mhz_clk(chip);
3400
3401 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3402 VREF_BATT_THERM_FORCE_ON);
3403 if (rc)
3404 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003406 rc = pm_chg_charge_dis(chip, charging_disabled);
3407 if (rc) {
3408 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3409 return rc;
3410 }
3411
3412 rc = pm_chg_auto_enable(chip, !charging_disabled);
3413 if (rc) {
3414 pr_err("Failed to enable charging rc=%d\n", rc);
3415 return rc;
3416 }
3417
3418 return 0;
3419}
3420
3421static int get_rt_status(void *data, u64 * val)
3422{
3423 int i = (int)data;
3424 int ret;
3425
3426 /* global irq number is passed in via data */
3427 ret = pm_chg_get_rt_status(the_chip, i);
3428 *val = ret;
3429 return 0;
3430}
3431DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3432
3433static int get_fsm_status(void *data, u64 * val)
3434{
3435 u8 temp;
3436
3437 temp = pm_chg_get_fsm_state(the_chip);
3438 *val = temp;
3439 return 0;
3440}
3441DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3442
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003443static int get_reg_loop(void *data, u64 * val)
3444{
3445 u8 temp;
3446
3447 if (!the_chip) {
3448 pr_err("%s called before init\n", __func__);
3449 return -EINVAL;
3450 }
3451 temp = pm_chg_get_regulation_loop(the_chip);
3452 *val = temp;
3453 return 0;
3454}
3455DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457static int get_reg(void *data, u64 * val)
3458{
3459 int addr = (int)data;
3460 int ret;
3461 u8 temp;
3462
3463 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3464 if (ret) {
3465 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3466 addr, temp, ret);
3467 return -EAGAIN;
3468 }
3469 *val = temp;
3470 return 0;
3471}
3472
3473static int set_reg(void *data, u64 val)
3474{
3475 int addr = (int)data;
3476 int ret;
3477 u8 temp;
3478
3479 temp = (u8) val;
3480 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3481 if (ret) {
3482 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3483 addr, temp, ret);
3484 return -EAGAIN;
3485 }
3486 return 0;
3487}
3488DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3489
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003490enum {
3491 BAT_WARM_ZONE,
3492 BAT_COOL_ZONE,
3493};
3494static int get_warm_cool(void *data, u64 * val)
3495{
3496 if (!the_chip) {
3497 pr_err("%s called before init\n", __func__);
3498 return -EINVAL;
3499 }
3500 if ((int)data == BAT_WARM_ZONE)
3501 *val = the_chip->is_bat_warm;
3502 if ((int)data == BAT_COOL_ZONE)
3503 *val = the_chip->is_bat_cool;
3504 return 0;
3505}
3506DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3509{
3510 int i;
3511
3512 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3513
3514 if (IS_ERR(chip->dent)) {
3515 pr_err("pmic charger couldnt create debugfs dir\n");
3516 return;
3517 }
3518
3519 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3520 (void *)CHG_CNTRL, &reg_fops);
3521 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3522 (void *)CHG_CNTRL_2, &reg_fops);
3523 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3524 (void *)CHG_CNTRL_3, &reg_fops);
3525 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3526 (void *)PBL_ACCESS1, &reg_fops);
3527 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3528 (void *)PBL_ACCESS2, &reg_fops);
3529 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3530 (void *)SYS_CONFIG_1, &reg_fops);
3531 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3532 (void *)SYS_CONFIG_2, &reg_fops);
3533 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3534 (void *)CHG_VDD_MAX, &reg_fops);
3535 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3536 (void *)CHG_VDD_SAFE, &reg_fops);
3537 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3538 (void *)CHG_VBAT_DET, &reg_fops);
3539 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3540 (void *)CHG_IBAT_MAX, &reg_fops);
3541 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3542 (void *)CHG_IBAT_SAFE, &reg_fops);
3543 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3544 (void *)CHG_VIN_MIN, &reg_fops);
3545 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3546 (void *)CHG_VTRICKLE, &reg_fops);
3547 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3548 (void *)CHG_ITRICKLE, &reg_fops);
3549 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3550 (void *)CHG_ITERM, &reg_fops);
3551 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3552 (void *)CHG_TCHG_MAX, &reg_fops);
3553 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3554 (void *)CHG_TWDOG, &reg_fops);
3555 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3556 (void *)CHG_TEMP_THRESH, &reg_fops);
3557 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3558 (void *)CHG_COMP_OVR, &reg_fops);
3559 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3560 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3561 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3562 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3563 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3564 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3565 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3566 (void *)CHG_TEST, &reg_fops);
3567
3568 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3569 &fsm_fops);
3570
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003571 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3572 &reg_loop_fops);
3573
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003574 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3575 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3576 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3577 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3580 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3581 debugfs_create_file(chg_irq_data[i].name, 0444,
3582 chip->dent,
3583 (void *)chg_irq_data[i].irq_id,
3584 &rt_fops);
3585 }
3586}
3587
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003588static int pm8921_charger_suspend_noirq(struct device *dev)
3589{
3590 int rc;
3591 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3592
3593 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3594 if (rc)
3595 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3596 pm8921_chg_set_hw_clk_switching(chip);
3597 return 0;
3598}
3599
3600static int pm8921_charger_resume_noirq(struct device *dev)
3601{
3602 int rc;
3603 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3604
3605 pm8921_chg_force_19p2mhz_clk(chip);
3606
3607 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3608 VREF_BATT_THERM_FORCE_ON);
3609 if (rc)
3610 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3611 return 0;
3612}
3613
David Keitelf2226022011-12-13 15:55:50 -08003614static int pm8921_charger_resume(struct device *dev)
3615{
3616 int rc;
3617 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3618
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003619 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003620 && !(chip->keep_btm_on_suspend)) {
3621 rc = pm8xxx_adc_btm_configure(&btm_config);
3622 if (rc)
3623 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3624
3625 rc = pm8xxx_adc_btm_start();
3626 if (rc)
3627 pr_err("couldn't restart btm rc=%d\n", rc);
3628 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003629 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3630 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3631 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3632 }
David Keitelf2226022011-12-13 15:55:50 -08003633 return 0;
3634}
3635
3636static int pm8921_charger_suspend(struct device *dev)
3637{
3638 int rc;
3639 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3640
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003641 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003642 && !(chip->keep_btm_on_suspend)) {
3643 rc = pm8xxx_adc_btm_end();
3644 if (rc)
3645 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3646 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003647
3648 if (is_usb_chg_plugged_in(chip)) {
3649 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3650 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3651 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003652
David Keitelf2226022011-12-13 15:55:50 -08003653 return 0;
3654}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003655static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3656{
3657 int rc = 0;
3658 struct pm8921_chg_chip *chip;
3659 const struct pm8921_charger_platform_data *pdata
3660 = pdev->dev.platform_data;
3661
3662 if (!pdata) {
3663 pr_err("missing platform data\n");
3664 return -EINVAL;
3665 }
3666
3667 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3668 GFP_KERNEL);
3669 if (!chip) {
3670 pr_err("Cannot allocate pm_chg_chip\n");
3671 return -ENOMEM;
3672 }
3673
3674 chip->dev = &pdev->dev;
3675 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003676 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003677 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003678 chip->max_voltage_mv = pdata->max_voltage;
3679 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003680 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003681 chip->term_current = pdata->term_current;
3682 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003683 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003684 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3685 chip->batt_id_min = pdata->batt_id_min;
3686 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003687 if (pdata->cool_temp != INT_MIN)
3688 chip->cool_temp_dc = pdata->cool_temp * 10;
3689 else
3690 chip->cool_temp_dc = INT_MIN;
3691
3692 if (pdata->warm_temp != INT_MIN)
3693 chip->warm_temp_dc = pdata->warm_temp * 10;
3694 else
3695 chip->warm_temp_dc = INT_MIN;
3696
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003697 chip->temp_check_period = pdata->temp_check_period;
3698 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3699 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3700 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3701 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3702 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003703 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003704 chip->trkl_voltage = pdata->trkl_voltage;
3705 chip->weak_voltage = pdata->weak_voltage;
3706 chip->trkl_current = pdata->trkl_current;
3707 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003708 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003709 chip->thermal_mitigation = pdata->thermal_mitigation;
3710 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003712 chip->cold_thr = pdata->cold_thr;
3713 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003714 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003715 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717 rc = pm8921_chg_hw_init(chip);
3718 if (rc) {
3719 pr_err("couldn't init hardware rc=%d\n", rc);
3720 goto free_chip;
3721 }
3722
3723 chip->usb_psy.name = "usb",
3724 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3725 chip->usb_psy.supplied_to = pm_power_supplied_to,
3726 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003727 chip->usb_psy.properties = pm_power_props_usb,
3728 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3729 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730
David Keitel6ed71a52012-01-30 12:42:18 -08003731 chip->dc_psy.name = "pm8921-dc",
3732 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3733 chip->dc_psy.supplied_to = pm_power_supplied_to,
3734 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003735 chip->dc_psy.properties = pm_power_props_mains,
3736 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3737 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003739 chip->batt_psy.name = "battery",
3740 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3741 chip->batt_psy.properties = msm_batt_power_props,
3742 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3743 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003744 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003745 rc = power_supply_register(chip->dev, &chip->usb_psy);
3746 if (rc < 0) {
3747 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003748 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749 }
3750
David Keitel6ed71a52012-01-30 12:42:18 -08003751 rc = power_supply_register(chip->dev, &chip->dc_psy);
3752 if (rc < 0) {
3753 pr_err("power_supply_register usb failed rc = %d\n", rc);
3754 goto unregister_usb;
3755 }
3756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003757 rc = power_supply_register(chip->dev, &chip->batt_psy);
3758 if (rc < 0) {
3759 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003760 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761 }
3762
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003763 platform_set_drvdata(pdev, chip);
3764 the_chip = chip;
3765
3766 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003767 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003768 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3769 vin_collapse_check_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003770 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3771 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003772 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774 rc = request_irqs(chip, pdev);
3775 if (rc) {
3776 pr_err("couldn't register interrupts rc=%d\n", rc);
3777 goto unregister_batt;
3778 }
3779
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003780 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3781 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3782 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003783 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3784 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003785 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003786 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003787 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003788 * care for jeita compliance
3789 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003790 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003791 rc = configure_btm(chip);
3792 if (rc) {
3793 pr_err("couldn't register with btm rc=%d\n", rc);
3794 goto free_irq;
3795 }
3796 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 create_debugfs_entries(chip);
3799
3800 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003801 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 /* determine what state the charger is in */
3804 determine_initial_state(chip);
3805
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003806 if (chip->update_time) {
3807 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3808 update_heartbeat);
3809 schedule_delayed_work(&chip->update_heartbeat_work,
3810 round_jiffies_relative(msecs_to_jiffies
3811 (chip->update_time)));
3812 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813 return 0;
3814
3815free_irq:
3816 free_irqs(chip);
3817unregister_batt:
3818 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003819unregister_dc:
3820 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003821unregister_usb:
3822 power_supply_unregister(&chip->usb_psy);
3823free_chip:
3824 kfree(chip);
3825 return rc;
3826}
3827
3828static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3829{
3830 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3831
3832 free_irqs(chip);
3833 platform_set_drvdata(pdev, NULL);
3834 the_chip = NULL;
3835 kfree(chip);
3836 return 0;
3837}
David Keitelf2226022011-12-13 15:55:50 -08003838static const struct dev_pm_ops pm8921_pm_ops = {
3839 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003840 .suspend_noirq = pm8921_charger_suspend_noirq,
3841 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003842 .resume = pm8921_charger_resume,
3843};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003844static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003845 .probe = pm8921_charger_probe,
3846 .remove = __devexit_p(pm8921_charger_remove),
3847 .driver = {
3848 .name = PM8921_CHARGER_DEV_NAME,
3849 .owner = THIS_MODULE,
3850 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851 },
3852};
3853
3854static int __init pm8921_charger_init(void)
3855{
3856 return platform_driver_register(&pm8921_charger_driver);
3857}
3858
3859static void __exit pm8921_charger_exit(void)
3860{
3861 platform_driver_unregister(&pm8921_charger_driver);
3862}
3863
3864late_initcall(pm8921_charger_init);
3865module_exit(pm8921_charger_exit);
3866
3867MODULE_LICENSE("GPL v2");
3868MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3869MODULE_VERSION("1.0");
3870MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);