blob: 8e9d7532e76870487ebccfb9ea13a637314a4183 [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 Keitelaf515712012-04-13 17:25:31 -07001171 if (usb_target_ma < USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001172 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001173 else
1174 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 break;
1176 default:
1177 return -EINVAL;
1178 }
1179 return 0;
1180}
1181
1182static enum power_supply_property msm_batt_power_props[] = {
1183 POWER_SUPPLY_PROP_STATUS,
1184 POWER_SUPPLY_PROP_CHARGE_TYPE,
1185 POWER_SUPPLY_PROP_HEALTH,
1186 POWER_SUPPLY_PROP_PRESENT,
1187 POWER_SUPPLY_PROP_TECHNOLOGY,
1188 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1189 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1190 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1191 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001192 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001193 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001194 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195};
1196
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001197static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198{
1199 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001200 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001202 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 if (rc) {
1204 pr_err("error reading adc channel = %d, rc = %d\n",
1205 chip->vbat_channel, rc);
1206 return rc;
1207 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001208 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209 result.measurement);
1210 return (int)result.physical;
1211}
1212
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001213static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1214{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001215 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1216 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1217 unsigned int low_voltage = chip->min_voltage_mv;
1218 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001219
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001220 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001221 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001222 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001223 return 100;
1224 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001225 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001226 / (high_voltage - low_voltage);
1227}
1228
David Keitel4f9397b2012-04-16 11:46:16 -07001229static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1230{
1231 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1232}
1233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1235{
David Keitel4f9397b2012-04-16 11:46:16 -07001236 int percent_soc;
1237
1238 if (!get_prop_batt_present(chip))
1239 percent_soc = voltage_based_capacity(chip);
1240 else
1241 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001242
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001243 if (percent_soc == -ENXIO)
1244 percent_soc = voltage_based_capacity(chip);
1245
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001246 if (percent_soc <= 10)
1247 pr_warn("low battery charge = %d%%\n", percent_soc);
1248
1249 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250}
1251
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001252static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1253{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001254 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001255
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001256 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001257 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001258 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001259 }
1260
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001261 if (rc) {
1262 pr_err("unable to get batt current rc = %d\n", rc);
1263 return rc;
1264 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001265 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001266 }
1267}
1268
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001269static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1270{
1271 int rc;
1272
1273 rc = pm8921_bms_get_fcc();
1274 if (rc < 0)
1275 pr_err("unable to get batt fcc rc = %d\n", rc);
1276 return rc;
1277}
1278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1280{
1281 int temp;
1282
1283 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1284 if (temp)
1285 return POWER_SUPPLY_HEALTH_OVERHEAT;
1286
1287 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1288 if (temp)
1289 return POWER_SUPPLY_HEALTH_COLD;
1290
1291 return POWER_SUPPLY_HEALTH_GOOD;
1292}
1293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1295{
1296 int temp;
1297
Amir Samuelovd31ef502011-10-26 14:41:36 +02001298 if (!get_prop_batt_present(chip))
1299 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1300
1301 if (is_ext_trickle_charging(chip))
1302 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1303
1304 if (is_ext_charging(chip))
1305 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1308 if (temp)
1309 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1310
1311 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1312 if (temp)
1313 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1314
1315 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1316}
1317
1318static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1319{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001320 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1321 int fsm_state = pm_chg_get_fsm_state(chip);
1322 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323
David Keitel88e1b572012-01-11 11:57:14 -08001324 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001325 if (chip->ext_charge_done)
1326 return POWER_SUPPLY_STATUS_FULL;
1327 if (chip->ext_charging)
1328 return POWER_SUPPLY_STATUS_CHARGING;
1329 }
1330
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001331 for (i = 0; i < ARRAY_SIZE(map); i++)
1332 if (map[i].fsm_state == fsm_state)
1333 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001334
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001335 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1336 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1337 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001338 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1339 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001340
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001341 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001342 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001343 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344}
1345
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001346#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001347static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1348{
1349 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001350 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001351
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001352 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001353 if (rc) {
1354 pr_err("error reading adc channel = %d, rc = %d\n",
1355 chip->vbat_channel, rc);
1356 return rc;
1357 }
1358 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1359 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001360 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1361 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1362 (int) result.physical);
1363
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001364 return (int)result.physical;
1365}
1366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367static int pm_batt_power_get_property(struct power_supply *psy,
1368 enum power_supply_property psp,
1369 union power_supply_propval *val)
1370{
1371 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1372 batt_psy);
1373
1374 switch (psp) {
1375 case POWER_SUPPLY_PROP_STATUS:
1376 val->intval = get_prop_batt_status(chip);
1377 break;
1378 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1379 val->intval = get_prop_charge_type(chip);
1380 break;
1381 case POWER_SUPPLY_PROP_HEALTH:
1382 val->intval = get_prop_batt_health(chip);
1383 break;
1384 case POWER_SUPPLY_PROP_PRESENT:
1385 val->intval = get_prop_batt_present(chip);
1386 break;
1387 case POWER_SUPPLY_PROP_TECHNOLOGY:
1388 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1389 break;
1390 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001391 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 break;
1393 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001394 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 break;
1396 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001397 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 break;
1399 case POWER_SUPPLY_PROP_CAPACITY:
1400 val->intval = get_prop_batt_capacity(chip);
1401 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001402 case POWER_SUPPLY_PROP_CURRENT_NOW:
1403 val->intval = get_prop_batt_current(chip);
1404 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001405 case POWER_SUPPLY_PROP_TEMP:
1406 val->intval = get_prop_batt_temp(chip);
1407 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001408 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001409 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001410 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 default:
1412 return -EINVAL;
1413 }
1414
1415 return 0;
1416}
1417
1418static void (*notify_vbus_state_func_ptr)(int);
1419static int usb_chg_current;
1420static DEFINE_SPINLOCK(vbus_lock);
1421
1422int pm8921_charger_register_vbus_sn(void (*callback)(int))
1423{
1424 pr_debug("%p\n", callback);
1425 notify_vbus_state_func_ptr = callback;
1426 return 0;
1427}
1428EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1429
1430/* this is passed to the hsusb via platform_data msm_otg_pdata */
1431void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1432{
1433 pr_debug("%p\n", callback);
1434 notify_vbus_state_func_ptr = NULL;
1435}
1436EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1437
1438static void notify_usb_of_the_plugin_event(int plugin)
1439{
1440 plugin = !!plugin;
1441 if (notify_vbus_state_func_ptr) {
1442 pr_debug("notifying plugin\n");
1443 (*notify_vbus_state_func_ptr) (plugin);
1444 } else {
1445 pr_debug("unable to notify plugin\n");
1446 }
1447}
1448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449/* assumes vbus_lock is held */
1450static void __pm8921_charger_vbus_draw(unsigned int mA)
1451{
1452 int i, rc;
1453
1454 if (mA > 0 && mA <= 2) {
1455 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001456 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001458 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459 }
1460 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1461 if (rc)
1462 pr_err("fail to set suspend bit rc=%d\n", rc);
1463 } else {
1464 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1465 if (rc)
1466 pr_err("fail to reset suspend bit rc=%d\n", rc);
1467 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1468 if (usb_ma_table[i].usb_ma <= mA)
1469 break;
1470 }
1471 if (i < 0)
1472 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001473 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001475 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 }
1477 }
1478}
1479
1480/* USB calls these to tell us how much max usb current the system can draw */
1481void pm8921_charger_vbus_draw(unsigned int mA)
1482{
1483 unsigned long flags;
1484
1485 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001486
1487 if (usb_max_current && mA > usb_max_current) {
1488 pr_warn("restricting usb current to %d instead of %d\n",
1489 usb_max_current, mA);
1490 mA = usb_max_current;
1491 }
1492 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1493 usb_target_ma = mA;
1494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 spin_lock_irqsave(&vbus_lock, flags);
1496 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001497 if (mA > USB_WALL_THRESHOLD_MA)
1498 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1499 else
1500 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 } else {
1502 /*
1503 * called before pmic initialized,
1504 * save this value and use it at probe
1505 */
David Keitelacf57c82012-03-07 18:48:50 -08001506 if (mA > USB_WALL_THRESHOLD_MA)
1507 usb_chg_current = USB_WALL_THRESHOLD_MA;
1508 else
1509 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 }
1511 spin_unlock_irqrestore(&vbus_lock, flags);
1512}
1513EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1514
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001515int pm8921_charger_enable(bool enable)
1516{
1517 int rc;
1518
1519 if (!the_chip) {
1520 pr_err("called before init\n");
1521 return -EINVAL;
1522 }
1523 enable = !!enable;
1524 rc = pm_chg_auto_enable(the_chip, enable);
1525 if (rc)
1526 pr_err("Failed rc=%d\n", rc);
1527 return rc;
1528}
1529EXPORT_SYMBOL(pm8921_charger_enable);
1530
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001531int pm8921_is_usb_chg_plugged_in(void)
1532{
1533 if (!the_chip) {
1534 pr_err("called before init\n");
1535 return -EINVAL;
1536 }
1537 return is_usb_chg_plugged_in(the_chip);
1538}
1539EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1540
1541int pm8921_is_dc_chg_plugged_in(void)
1542{
1543 if (!the_chip) {
1544 pr_err("called before init\n");
1545 return -EINVAL;
1546 }
1547 return is_dc_chg_plugged_in(the_chip);
1548}
1549EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1550
1551int pm8921_is_battery_present(void)
1552{
1553 if (!the_chip) {
1554 pr_err("called before init\n");
1555 return -EINVAL;
1556 }
1557 return get_prop_batt_present(the_chip);
1558}
1559EXPORT_SYMBOL(pm8921_is_battery_present);
1560
David Keitel012deef2011-12-02 11:49:33 -08001561/*
1562 * Disabling the charge current limit causes current
1563 * current limits to have no monitoring. An adequate charger
1564 * capable of supplying high current while sustaining VIN_MIN
1565 * is required if the limiting is disabled.
1566 */
1567int pm8921_disable_input_current_limit(bool disable)
1568{
1569 if (!the_chip) {
1570 pr_err("called before init\n");
1571 return -EINVAL;
1572 }
1573 if (disable) {
1574 pr_warn("Disabling input current limit!\n");
1575
1576 return pm8xxx_writeb(the_chip->dev->parent,
1577 CHG_BUCK_CTRL_TEST3, 0xF2);
1578 }
1579 return 0;
1580}
1581EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1582
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001583int pm8921_set_max_battery_charge_current(int ma)
1584{
1585 if (!the_chip) {
1586 pr_err("called before init\n");
1587 return -EINVAL;
1588 }
1589 return pm_chg_ibatmax_set(the_chip, ma);
1590}
1591EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1592
1593int pm8921_disable_source_current(bool disable)
1594{
1595 if (!the_chip) {
1596 pr_err("called before init\n");
1597 return -EINVAL;
1598 }
1599 if (disable)
1600 pr_warn("current drawn from chg=0, battery provides current\n");
1601 return pm_chg_charge_dis(the_chip, disable);
1602}
1603EXPORT_SYMBOL(pm8921_disable_source_current);
1604
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001605int pm8921_regulate_input_voltage(int voltage)
1606{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001607 int rc;
1608
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001609 if (!the_chip) {
1610 pr_err("called before init\n");
1611 return -EINVAL;
1612 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001613 rc = pm_chg_vinmin_set(the_chip, voltage);
1614
1615 if (rc == 0)
1616 the_chip->vin_min = voltage;
1617
1618 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001619}
1620
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001621#define USB_OV_THRESHOLD_MASK 0x60
1622#define USB_OV_THRESHOLD_SHIFT 5
1623int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1624{
1625 u8 temp;
1626
1627 if (!the_chip) {
1628 pr_err("called before init\n");
1629 return -EINVAL;
1630 }
1631
1632 if (ov > PM_USB_OV_7V) {
1633 pr_err("limiting to over voltage threshold to 7volts\n");
1634 ov = PM_USB_OV_7V;
1635 }
1636
1637 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1638
1639 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1640 USB_OV_THRESHOLD_MASK, temp);
1641}
1642EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1643
1644#define USB_DEBOUNCE_TIME_MASK 0x06
1645#define USB_DEBOUNCE_TIME_SHIFT 1
1646int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1647{
1648 u8 temp;
1649
1650 if (!the_chip) {
1651 pr_err("called before init\n");
1652 return -EINVAL;
1653 }
1654
1655 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1656 pr_err("limiting debounce to 80.5ms\n");
1657 ms = PM_USB_DEBOUNCE_80P5MS;
1658 }
1659
1660 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1661
1662 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1663 USB_DEBOUNCE_TIME_MASK, temp);
1664}
1665EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1666
1667#define USB_OVP_DISABLE_MASK 0x80
1668int pm8921_usb_ovp_disable(int disable)
1669{
1670 u8 temp = 0;
1671
1672 if (!the_chip) {
1673 pr_err("called before init\n");
1674 return -EINVAL;
1675 }
1676
1677 if (disable)
1678 temp = USB_OVP_DISABLE_MASK;
1679
1680 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1681 USB_OVP_DISABLE_MASK, temp);
1682}
1683
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001684bool pm8921_is_battery_charging(int *source)
1685{
1686 int fsm_state, is_charging, dc_present, usb_present;
1687
1688 if (!the_chip) {
1689 pr_err("called before init\n");
1690 return -EINVAL;
1691 }
1692 fsm_state = pm_chg_get_fsm_state(the_chip);
1693 is_charging = is_battery_charging(fsm_state);
1694 if (is_charging == 0) {
1695 *source = PM8921_CHG_SRC_NONE;
1696 return is_charging;
1697 }
1698
1699 if (source == NULL)
1700 return is_charging;
1701
1702 /* the battery is charging, the source is requested, find it */
1703 dc_present = is_dc_chg_plugged_in(the_chip);
1704 usb_present = is_usb_chg_plugged_in(the_chip);
1705
1706 if (dc_present && !usb_present)
1707 *source = PM8921_CHG_SRC_DC;
1708
1709 if (usb_present && !dc_present)
1710 *source = PM8921_CHG_SRC_USB;
1711
1712 if (usb_present && dc_present)
1713 /*
1714 * The system always chooses dc for charging since it has
1715 * higher priority.
1716 */
1717 *source = PM8921_CHG_SRC_DC;
1718
1719 return is_charging;
1720}
1721EXPORT_SYMBOL(pm8921_is_battery_charging);
1722
David Keitel86034022012-04-18 12:33:58 -07001723int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1724{
1725 if (!the_chip) {
1726 pr_err("called before init\n");
1727 return -EINVAL;
1728 }
1729
1730 if (type < POWER_SUPPLY_TYPE_USB)
1731 return -EINVAL;
1732
1733 the_chip->usb_psy.type = type;
1734 power_supply_changed(&the_chip->usb_psy);
1735 power_supply_changed(&the_chip->dc_psy);
1736 return 0;
1737}
1738EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1739
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001740int pm8921_batt_temperature(void)
1741{
1742 if (!the_chip) {
1743 pr_err("called before init\n");
1744 return -EINVAL;
1745 }
1746 return get_prop_batt_temp(the_chip);
1747}
1748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1750{
1751 int usb_present;
1752
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001753 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 usb_present = is_usb_chg_plugged_in(chip);
1755 if (chip->usb_present ^ usb_present) {
1756 notify_usb_of_the_plugin_event(usb_present);
1757 chip->usb_present = usb_present;
1758 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001759 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001760 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001762 if (usb_present) {
1763 schedule_delayed_work(&chip->unplug_check_work,
1764 round_jiffies_relative(msecs_to_jiffies
1765 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001766 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1767 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001768 /* USB unplugged reset target current */
1769 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001770 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001771 }
David Keitel8c5201a2012-02-24 16:08:54 -08001772 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001773 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774}
1775
Amir Samuelovd31ef502011-10-26 14:41:36 +02001776static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1777{
David Keitel88e1b572012-01-11 11:57:14 -08001778 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001779 pr_debug("external charger not registered.\n");
1780 return;
1781 }
1782
1783 if (!chip->ext_charging) {
1784 pr_debug("already not charging.\n");
1785 return;
1786 }
1787
David Keitel88e1b572012-01-11 11:57:14 -08001788 power_supply_set_charge_type(chip->ext_psy,
1789 POWER_SUPPLY_CHARGE_TYPE_NONE);
1790 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001791 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001792 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001793 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001794 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001795}
1796
1797static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1798{
1799 int dc_present;
1800 int batt_present;
1801 int batt_temp_ok;
1802 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001803 unsigned long delay =
1804 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1805
David Keitel88e1b572012-01-11 11:57:14 -08001806 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001807 pr_debug("external charger not registered.\n");
1808 return;
1809 }
1810
1811 if (chip->ext_charging) {
1812 pr_debug("already charging.\n");
1813 return;
1814 }
1815
David Keitel88e1b572012-01-11 11:57:14 -08001816 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001817 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1818 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001819
1820 if (!dc_present) {
1821 pr_warn("%s. dc not present.\n", __func__);
1822 return;
1823 }
1824 if (!batt_present) {
1825 pr_warn("%s. battery not present.\n", __func__);
1826 return;
1827 }
1828 if (!batt_temp_ok) {
1829 pr_warn("%s. battery temperature not ok.\n", __func__);
1830 return;
1831 }
David Keitel88e1b572012-01-11 11:57:14 -08001832 pm8921_disable_source_current(true); /* Force BATFET=ON */
1833 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001834 if (vbat_ov) {
1835 pr_warn("%s. battery over voltage.\n", __func__);
1836 return;
1837 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001838
David Keitel63f71662012-02-08 20:30:00 -08001839 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001840 power_supply_set_charge_type(chip->ext_psy,
1841 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001842 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001843 chip->ext_charging = true;
1844 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001845 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001846 /* Start BMS */
1847 schedule_delayed_work(&chip->eoc_work, delay);
1848 wake_lock(&chip->eoc_wake_lock);
1849}
1850
David Keitel8c5201a2012-02-24 16:08:54 -08001851static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001852{
1853 u8 temp;
1854 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001855
David Keitel8c5201a2012-02-24 16:08:54 -08001856 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001857 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001858 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1859 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001860 }
David Keitel8c5201a2012-02-24 16:08:54 -08001861 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1862 if (rc) {
1863 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1864 return;
1865 }
1866 /* set ovp fet disable bit and the write bit */
1867 temp |= 0x81;
1868 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1869 if (rc) {
1870 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1871 return;
1872 }
1873}
1874
1875static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1876{
1877 u8 temp;
1878 int rc;
1879
1880 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1881 if (rc) {
1882 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1883 return;
1884 }
1885 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1886 if (rc) {
1887 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1888 return;
1889 }
1890 /* unset ovp fet disable bit and set the write bit */
1891 temp &= 0xFE;
1892 temp |= 0x80;
1893 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1894 if (rc) {
1895 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1896 temp, rc);
1897 return;
1898 }
1899}
1900
1901static int param_open_ovp_counter = 10;
1902module_param(param_open_ovp_counter, int, 0644);
1903
1904#define WRITE_BANK_4 0xC0
1905#define USB_OVP_DEBOUNCE_TIME 0x06
1906static void unplug_ovp_fet_open_worker(struct work_struct *work)
1907{
1908 struct pm8921_chg_chip *chip = container_of(work,
1909 struct pm8921_chg_chip,
1910 unplug_ovp_fet_open_work);
1911 int chg_gone, usb_chg_plugged_in;
1912 int count = 0;
1913
1914 while (count++ < param_open_ovp_counter) {
1915 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1916 USB_OVP_DEBOUNCE_TIME, 0x0);
1917 usleep(10);
1918 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1919 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1920 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1921 count, chg_gone, usb_chg_plugged_in);
1922
1923 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1924 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1925 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1926 turn_off_usb_ovp_fet(chip);
1927
1928 msleep(20);
1929
1930 turn_on_usb_ovp_fet(chip);
1931 } else {
David Keitel712782e2012-03-29 14:11:47 -07001932 break;
David Keitel8c5201a2012-02-24 16:08:54 -08001933 }
1934 }
David Keitel712782e2012-03-29 14:11:47 -07001935 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1936 USB_OVP_DEBOUNCE_TIME, 0x2);
1937 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1938 count, chg_gone, usb_chg_plugged_in);
1939 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001940}
David Keitelacf57c82012-03-07 18:48:50 -08001941
1942static int find_usb_ma_value(int value)
1943{
1944 int i;
1945
1946 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1947 if (value >= usb_ma_table[i].usb_ma)
1948 break;
1949 }
1950
1951 return i;
1952}
1953
1954static void decrease_usb_ma_value(int *value)
1955{
1956 int i;
1957
1958 if (value) {
1959 i = find_usb_ma_value(*value);
1960 if (i > 0)
1961 i--;
1962 *value = usb_ma_table[i].usb_ma;
1963 }
1964}
1965
1966static void increase_usb_ma_value(int *value)
1967{
1968 int i;
1969
1970 if (value) {
1971 i = find_usb_ma_value(*value);
1972
1973 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
1974 i++;
1975 *value = usb_ma_table[i].usb_ma;
1976 }
1977}
1978
1979static void vin_collapse_check_worker(struct work_struct *work)
1980{
1981 struct delayed_work *dwork = to_delayed_work(work);
1982 struct pm8921_chg_chip *chip = container_of(dwork,
1983 struct pm8921_chg_chip, vin_collapse_check_work);
1984
1985 /* AICL only for wall-chargers */
1986 if (is_usb_chg_plugged_in(chip) &&
1987 usb_target_ma > USB_WALL_THRESHOLD_MA) {
1988 /* decrease usb_target_ma */
1989 decrease_usb_ma_value(&usb_target_ma);
1990 /* reset here, increase in unplug_check_worker */
1991 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1992 pr_debug("usb_now=%d, usb_target = %d\n",
1993 USB_WALL_THRESHOLD_MA, usb_target_ma);
1994 } else {
1995 handle_usb_insertion_removal(chip);
1996 }
1997}
1998
1999#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2001{
David Keitelacf57c82012-03-07 18:48:50 -08002002 if (usb_target_ma)
2003 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2004 round_jiffies_relative(msecs_to_jiffies
2005 (VIN_MIN_COLLAPSE_CHECK_MS)));
2006 else
2007 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 return IRQ_HANDLED;
2009}
2010
2011static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
2012{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002013 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014 return IRQ_HANDLED;
2015}
2016
2017static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2018{
2019 struct pm8921_chg_chip *chip = data;
2020 int status;
2021
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002022 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2023 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002024 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 pr_debug("battery present=%d", status);
2026 power_supply_changed(&chip->batt_psy);
2027 return IRQ_HANDLED;
2028}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002029
2030/*
2031 * this interrupt used to restart charging a battery.
2032 *
2033 * Note: When DC-inserted the VBAT can't go low.
2034 * VPH_PWR is provided by the ext-charger.
2035 * After End-Of-Charging from DC, charging can be resumed only
2036 * if DC is removed and then inserted after the battery was in use.
2037 * Therefore the handle_start_ext_chg() is not called.
2038 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2040{
2041 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002042 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002044 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002045
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002046 if (high_transition) {
2047 /* enable auto charging */
2048 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002049 pr_info("batt fell below resume voltage %s\n",
2050 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 power_supply_changed(&chip->batt_psy);
2055 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002056 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 return IRQ_HANDLED;
2059}
2060
2061static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2062{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002063 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 return IRQ_HANDLED;
2065}
2066
2067static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2068{
2069 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2070 return IRQ_HANDLED;
2071}
2072
2073static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2074{
2075 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2076 return IRQ_HANDLED;
2077}
2078
2079static irqreturn_t vcp_irq_handler(int irq, void *data)
2080{
David Keitel8c5201a2012-02-24 16:08:54 -08002081 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 return IRQ_HANDLED;
2083}
2084
2085static irqreturn_t atcdone_irq_handler(int irq, void *data)
2086{
2087 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2088 return IRQ_HANDLED;
2089}
2090
2091static irqreturn_t atcfail_irq_handler(int irq, void *data)
2092{
2093 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2094 return IRQ_HANDLED;
2095}
2096
2097static irqreturn_t chgdone_irq_handler(int irq, void *data)
2098{
2099 struct pm8921_chg_chip *chip = data;
2100
2101 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002102
2103 handle_stop_ext_chg(chip);
2104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 power_supply_changed(&chip->batt_psy);
2106 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002107 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002108
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002109 bms_notify_check(chip);
2110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 return IRQ_HANDLED;
2112}
2113
2114static irqreturn_t chgfail_irq_handler(int irq, void *data)
2115{
2116 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002117 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118
David Keitel753ec8d2011-11-02 10:56:37 -07002119 ret = pm_chg_failed_clear(chip, 1);
2120 if (ret)
2121 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2122
2123 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2124 get_prop_batt_present(chip),
2125 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2126 pm_chg_get_fsm_state(data));
2127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128 power_supply_changed(&chip->batt_psy);
2129 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002130 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 return IRQ_HANDLED;
2132}
2133
2134static irqreturn_t chgstate_irq_handler(int irq, void *data)
2135{
2136 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137
2138 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2139 power_supply_changed(&chip->batt_psy);
2140 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002141 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002143 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145 return IRQ_HANDLED;
2146}
2147
David Keitel8c5201a2012-02-24 16:08:54 -08002148static int param_vin_disable_counter = 5;
2149module_param(param_vin_disable_counter, int, 0644);
2150
2151static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2152 int count, int usb_ma)
2153{
David Keitelacf57c82012-03-07 18:48:50 -08002154 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002155 pr_debug("count = %d iusb=500mA\n", count);
2156 disable_input_voltage_regulation(chip);
2157 pr_debug("count = %d disable_input_regulation\n", count);
2158
2159 msleep(20);
2160
2161 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2162 count,
2163 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2164 is_usb_chg_plugged_in(chip));
2165 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2166 count, usb_ma);
2167 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002168 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002169}
2170
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002171#define VIN_ACTIVE_BIT BIT(0)
2172#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2173#define VIN_MIN_INCREASE_MV 100
2174static void unplug_check_worker(struct work_struct *work)
2175{
2176 struct delayed_work *dwork = to_delayed_work(work);
2177 struct pm8921_chg_chip *chip = container_of(dwork,
2178 struct pm8921_chg_chip, unplug_check_work);
2179 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002180 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002181 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002182
David Keitelacf57c82012-03-07 18:48:50 -08002183 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002184 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2185 if (!usb_chg_plugged_in) {
2186 pr_debug("Stopping Unplug Check Worker since USB is removed"
2187 "reg_loop = %d, fsm = %d ibat = %d\n",
2188 pm_chg_get_regulation_loop(chip),
2189 pm_chg_get_fsm_state(chip),
2190 get_prop_batt_current(chip)
2191 );
2192 return;
2193 }
David Keitel8c5201a2012-02-24 16:08:54 -08002194
2195 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002196 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002197 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2198 disable_input_voltage_regulation(chip);
2199 return;
2200 }
2201
2202 if (usb_ma <= 100) {
2203 pr_debug(
2204 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2205 usb_ma);
2206 goto check_again_later;
2207 }
2208 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2209 pr_debug("chg gone irq is enabled\n");
2210
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002211 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002212 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002213
David Keitel21b7dfb2012-03-31 13:57:14 -07002214 if ((reg_loop & VIN_ACTIVE_BIT) && (usb_ma > USB_WALL_THRESHOLD_MA)) {
David Keitelacf57c82012-03-07 18:48:50 -08002215 decrease_usb_ma_value(&usb_ma);
2216 usb_target_ma = usb_ma;
2217 /* end AICL here */
2218 __pm8921_charger_vbus_draw(usb_ma);
2219 pr_debug("usb_now=%d, usb_target = %d\n",
2220 usb_ma, usb_target_ma);
2221 }
2222
2223 reg_loop = pm_chg_get_regulation_loop(chip);
2224 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2225
2226 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002227 ibat = get_prop_batt_current(chip);
2228
2229 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2230 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2231 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002232 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002233
David Keitel8c5201a2012-02-24 16:08:54 -08002234 while (count++ < param_vin_disable_counter
2235 && usb_chg_plugged_in == 1) {
2236 attempt_reverse_boost_fix(chip, count, usb_ma);
2237 usb_chg_plugged_in
2238 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002239 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002240 }
2241 }
2242
David Keitel8c5201a2012-02-24 16:08:54 -08002243 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2244 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2245
2246 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2247 /* run the worker directly */
2248 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2249 chg_gone, usb_chg_plugged_in);
2250 schedule_work(&chip->unplug_ovp_fet_open_work);
2251 }
2252
David Keitelacf57c82012-03-07 18:48:50 -08002253 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2254 /* only increase iusb_max if vin loop not active */
2255 if (usb_ma < usb_target_ma) {
2256 increase_usb_ma_value(&usb_ma);
2257 __pm8921_charger_vbus_draw(usb_ma);
2258 pr_debug("usb_now=%d, usb_target = %d\n",
2259 usb_ma, usb_target_ma);
2260 } else {
2261 usb_target_ma = usb_ma;
2262 }
2263 }
David Keitel8c5201a2012-02-24 16:08:54 -08002264check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002265 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002266 schedule_delayed_work(&chip->unplug_check_work,
2267 round_jiffies_relative(msecs_to_jiffies
2268 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2269}
2270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271static irqreturn_t loop_change_irq_handler(int irq, void *data)
2272{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002273 struct pm8921_chg_chip *chip = data;
2274
2275 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2276 pm_chg_get_fsm_state(data),
2277 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002278 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 return IRQ_HANDLED;
2280}
2281
2282static irqreturn_t fastchg_irq_handler(int irq, void *data)
2283{
2284 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002285 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002287 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2288 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2289 wake_lock(&chip->eoc_wake_lock);
2290 schedule_delayed_work(&chip->eoc_work,
2291 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002292 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002293 }
2294 power_supply_changed(&chip->batt_psy);
2295 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 return IRQ_HANDLED;
2297}
2298
2299static irqreturn_t trklchg_irq_handler(int irq, void *data)
2300{
2301 struct pm8921_chg_chip *chip = data;
2302
2303 power_supply_changed(&chip->batt_psy);
2304 return IRQ_HANDLED;
2305}
2306
2307static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2308{
2309 struct pm8921_chg_chip *chip = data;
2310 int status;
2311
2312 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2313 pr_debug("battery present=%d state=%d", !status,
2314 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002315 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 power_supply_changed(&chip->batt_psy);
2317 return IRQ_HANDLED;
2318}
2319
2320static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2321{
2322 struct pm8921_chg_chip *chip = data;
2323
Amir Samuelovd31ef502011-10-26 14:41:36 +02002324 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 power_supply_changed(&chip->batt_psy);
2326 return IRQ_HANDLED;
2327}
2328
2329static irqreturn_t chghot_irq_handler(int irq, void *data)
2330{
2331 struct pm8921_chg_chip *chip = data;
2332
2333 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2334 power_supply_changed(&chip->batt_psy);
2335 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002336 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 return IRQ_HANDLED;
2338}
2339
2340static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2341{
2342 struct pm8921_chg_chip *chip = data;
2343
2344 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002345 handle_stop_ext_chg(chip);
2346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 power_supply_changed(&chip->batt_psy);
2348 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 return IRQ_HANDLED;
2350}
2351
2352static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2353{
2354 struct pm8921_chg_chip *chip = data;
David Keitel0873d0f2012-03-29 11:44:49 -07002355 u8 reg;
2356 int rc, chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002357
2358 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2359 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2360
2361 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002362 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2363
2364 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, &reg);
2365 if (rc)
2366 pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
2367
2368 if (reg & CHG_USB_SUSPEND_BIT)
2369 return IRQ_HANDLED;
David Keitel8c5201a2012-02-24 16:08:54 -08002370 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 power_supply_changed(&chip->batt_psy);
2373 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374 return IRQ_HANDLED;
2375}
David Keitel52fda532011-11-10 10:43:44 -08002376/*
2377 *
2378 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2379 * fire for two cases:
2380 *
2381 * If the interrupt line switches to high temperature is okay
2382 * and thus charging begins.
2383 * If bat_temp_ok is low this means the temperature is now
2384 * too hot or cold, so charging is stopped.
2385 *
2386 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2388{
David Keitel52fda532011-11-10 10:43:44 -08002389 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390 struct pm8921_chg_chip *chip = data;
2391
David Keitel52fda532011-11-10 10:43:44 -08002392 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2393
2394 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2395 bat_temp_ok, pm_chg_get_fsm_state(data));
2396
2397 if (bat_temp_ok)
2398 handle_start_ext_chg(chip);
2399 else
2400 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 power_supply_changed(&chip->batt_psy);
2403 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002404 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 return IRQ_HANDLED;
2406}
2407
2408static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2409{
2410 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2411 return IRQ_HANDLED;
2412}
2413
2414static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2415{
2416 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2417 return IRQ_HANDLED;
2418}
2419
2420static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2421{
2422 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2423 return IRQ_HANDLED;
2424}
2425
2426static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2427{
2428 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2429 return IRQ_HANDLED;
2430}
2431
2432static irqreturn_t batfet_irq_handler(int irq, void *data)
2433{
2434 struct pm8921_chg_chip *chip = data;
2435
2436 pr_debug("vreg ov\n");
2437 power_supply_changed(&chip->batt_psy);
2438 return IRQ_HANDLED;
2439}
2440
2441static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2442{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002443 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002444 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002445
David Keitel88e1b572012-01-11 11:57:14 -08002446 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2447 if (chip->ext_psy)
2448 power_supply_set_online(chip->ext_psy, dc_present);
2449 chip->dc_present = dc_present;
2450 if (dc_present)
2451 handle_start_ext_chg(chip);
2452 else
2453 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 return IRQ_HANDLED;
2455}
2456
2457static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2458{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002459 struct pm8921_chg_chip *chip = data;
2460
Amir Samuelovd31ef502011-10-26 14:41:36 +02002461 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 return IRQ_HANDLED;
2463}
2464
2465static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2466{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002467 struct pm8921_chg_chip *chip = data;
2468
Amir Samuelovd31ef502011-10-26 14:41:36 +02002469 handle_stop_ext_chg(chip);
2470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 return IRQ_HANDLED;
2472}
2473
David Keitel88e1b572012-01-11 11:57:14 -08002474static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2475{
2476 struct power_supply *psy = &the_chip->batt_psy;
2477 struct power_supply *epsy = dev_get_drvdata(dev);
2478 int i, dcin_irq;
2479
2480 /* Only search for external supply if none is registered */
2481 if (!the_chip->ext_psy) {
2482 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2483 for (i = 0; i < epsy->num_supplicants; i++) {
2484 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2485 if (!strncmp(epsy->name, "dc", 2)) {
2486 the_chip->ext_psy = epsy;
2487 dcin_valid_irq_handler(dcin_irq,
2488 the_chip);
2489 }
2490 }
2491 }
2492 }
2493 return 0;
2494}
2495
2496static void pm_batt_external_power_changed(struct power_supply *psy)
2497{
2498 /* Only look for an external supply if it hasn't been registered */
2499 if (!the_chip->ext_psy)
2500 class_for_each_device(power_supply_class, NULL, psy,
2501 __pm_batt_external_power_changed_work);
2502}
2503
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002504/**
2505 * update_heartbeat - internal function to update userspace
2506 * per update_time minutes
2507 *
2508 */
2509static void update_heartbeat(struct work_struct *work)
2510{
2511 struct delayed_work *dwork = to_delayed_work(work);
2512 struct pm8921_chg_chip *chip = container_of(dwork,
2513 struct pm8921_chg_chip, update_heartbeat_work);
2514
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002515 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002516 power_supply_changed(&chip->batt_psy);
2517 schedule_delayed_work(&chip->update_heartbeat_work,
2518 round_jiffies_relative(msecs_to_jiffies
2519 (chip->update_time)));
2520}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002521#define VDD_LOOP_ACTIVE_BIT BIT(3)
2522#define VDD_MAX_INCREASE_MV 400
2523static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2524module_param(vdd_max_increase_mv, int, 0644);
2525
2526static int ichg_threshold_ua = -400000;
2527module_param(ichg_threshold_ua, int, 0644);
2528static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2529{
2530 int ichg_meas_ua, vbat_uv;
2531 int ichg_meas_ma;
2532 int adj_vdd_max_mv, programmed_vdd_max;
2533 int vbat_batt_terminal_uv;
2534 int vbat_batt_terminal_mv;
2535 int reg_loop;
2536 int delta_mv = 0;
2537
2538 if (chip->rconn_mohm == 0) {
2539 pr_debug("Exiting as rconn_mohm is 0\n");
2540 return;
2541 }
2542 /* adjust vdd_max only in normal temperature zone */
2543 if (chip->is_bat_cool || chip->is_bat_warm) {
2544 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2545 chip->is_bat_cool, chip->is_bat_warm);
2546 return;
2547 }
2548
2549 reg_loop = pm_chg_get_regulation_loop(chip);
2550 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2551 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2552 reg_loop);
2553 return;
2554 }
2555
2556 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2557 &vbat_uv);
2558 if (ichg_meas_ua >= 0) {
2559 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2560 return;
2561 }
2562 if (ichg_meas_ua <= ichg_threshold_ua) {
2563 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2564 ichg_meas_ua, ichg_threshold_ua);
2565 return;
2566 }
2567 ichg_meas_ma = ichg_meas_ua / 1000;
2568
2569 /* rconn_mohm is in milliOhms */
2570 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2571 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2572 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2573
2574 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2575
2576 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2577 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2578 delta_mv,
2579 programmed_vdd_max,
2580 adj_vdd_max_mv);
2581
2582 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2583 pr_debug("adj vdd_max lower than default max voltage\n");
2584 return;
2585 }
2586
2587 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2588 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2589
2590 pr_debug("adjusting vdd_max_mv to %d to make "
2591 "vbat_batt_termial_uv = %d to %d\n",
2592 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2593 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2594}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002595
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002596enum {
2597 CHG_IN_PROGRESS,
2598 CHG_NOT_IN_PROGRESS,
2599 CHG_FINISHED,
2600};
2601
2602#define VBAT_TOLERANCE_MV 70
2603#define CHG_DISABLE_MSLEEP 100
2604static int is_charging_finished(struct pm8921_chg_chip *chip)
2605{
2606 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2607 int ichg_meas_ma, iterm_programmed;
2608 int regulation_loop, fast_chg, vcp;
2609 int rc;
2610 static int last_vbat_programmed = -EINVAL;
2611
2612 if (!is_ext_charging(chip)) {
2613 /* return if the battery is not being fastcharged */
2614 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2615 pr_debug("fast_chg = %d\n", fast_chg);
2616 if (fast_chg == 0)
2617 return CHG_NOT_IN_PROGRESS;
2618
2619 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2620 pr_debug("vcp = %d\n", vcp);
2621 if (vcp == 1)
2622 return CHG_IN_PROGRESS;
2623
2624 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2625 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2626 if (vbatdet_low == 1)
2627 return CHG_IN_PROGRESS;
2628
2629 /* reset count if battery is hot/cold */
2630 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2631 pr_debug("batt_temp_ok = %d\n", rc);
2632 if (rc == 0)
2633 return CHG_IN_PROGRESS;
2634
2635 /* reset count if battery voltage is less than vddmax */
2636 vbat_meas_uv = get_prop_battery_uvolts(chip);
2637 if (vbat_meas_uv < 0)
2638 return CHG_IN_PROGRESS;
2639 vbat_meas_mv = vbat_meas_uv / 1000;
2640
2641 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2642 if (rc) {
2643 pr_err("couldnt read vddmax rc = %d\n", rc);
2644 return CHG_IN_PROGRESS;
2645 }
2646 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2647 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002648
2649 if (last_vbat_programmed == -EINVAL)
2650 last_vbat_programmed = vbat_programmed;
2651 if (last_vbat_programmed != vbat_programmed) {
2652 /* vddmax changed, reset and check again */
2653 pr_debug("vddmax = %d last_vdd_max=%d\n",
2654 vbat_programmed, last_vbat_programmed);
2655 last_vbat_programmed = vbat_programmed;
2656 return CHG_IN_PROGRESS;
2657 }
2658
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002659 regulation_loop = pm_chg_get_regulation_loop(chip);
2660 if (regulation_loop < 0) {
2661 pr_err("couldnt read the regulation loop err=%d\n",
2662 regulation_loop);
2663 return CHG_IN_PROGRESS;
2664 }
2665 pr_debug("regulation_loop=%d\n", regulation_loop);
2666
2667 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2668 return CHG_IN_PROGRESS;
2669 } /* !is_ext_charging */
2670
2671 /* reset count if battery chg current is more than iterm */
2672 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2673 if (rc) {
2674 pr_err("couldnt read iterm rc = %d\n", rc);
2675 return CHG_IN_PROGRESS;
2676 }
2677
2678 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2679 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2680 iterm_programmed, ichg_meas_ma);
2681 /*
2682 * ichg_meas_ma < 0 means battery is drawing current
2683 * ichg_meas_ma > 0 means battery is providing current
2684 */
2685 if (ichg_meas_ma > 0)
2686 return CHG_IN_PROGRESS;
2687
2688 if (ichg_meas_ma * -1 > iterm_programmed)
2689 return CHG_IN_PROGRESS;
2690
2691 return CHG_FINISHED;
2692}
2693
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002694/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002695 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002696 * has happened
2697 *
2698 * If all conditions favouring, if the charge current is
2699 * less than the term current for three consecutive times
2700 * an EOC has happened.
2701 * The wakelock is released if there is no need to reshedule
2702 * - this happens when the battery is removed or EOC has
2703 * happened
2704 */
2705#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002706static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002707{
2708 struct delayed_work *dwork = to_delayed_work(work);
2709 struct pm8921_chg_chip *chip = container_of(dwork,
2710 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002711 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002712 int end;
2713
2714 pm_chg_failed_clear(chip, 1);
2715 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002716
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002717 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002718 count = 0;
2719 wake_unlock(&chip->eoc_wake_lock);
2720 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002721 }
2722
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002723 if (end == CHG_FINISHED) {
2724 count++;
2725 } else {
2726 count = 0;
2727 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002728
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002729 if (count == CONSECUTIVE_COUNT) {
2730 count = 0;
2731 pr_info("End of Charging\n");
2732
2733 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002734
Amir Samuelovd31ef502011-10-26 14:41:36 +02002735 if (is_ext_charging(chip))
2736 chip->ext_charge_done = true;
2737
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002738 if (chip->is_bat_warm || chip->is_bat_cool)
2739 chip->bms_notify.is_battery_full = 0;
2740 else
2741 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002742 /* declare end of charging by invoking chgdone interrupt */
2743 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2744 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002745 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002746 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002747 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002748 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002749 round_jiffies_relative(msecs_to_jiffies
2750 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002751 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002752}
2753
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002754static void btm_configure_work(struct work_struct *work)
2755{
2756 int rc;
2757
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002758 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002759 if (rc)
2760 pr_err("failed to configure btm rc=%d", rc);
2761}
2762
2763DECLARE_WORK(btm_config_work, btm_configure_work);
2764
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002765static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2766{
2767 unsigned int chg_current = chip->max_bat_chg_current;
2768
2769 if (chip->is_bat_cool)
2770 chg_current = min(chg_current, chip->cool_bat_chg_current);
2771
2772 if (chip->is_bat_warm)
2773 chg_current = min(chg_current, chip->warm_bat_chg_current);
2774
David Keitelfdef3a42011-12-14 19:02:54 -08002775 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002776 chg_current = min(chg_current,
2777 chip->thermal_mitigation[thermal_mitigation]);
2778
2779 pm_chg_ibatmax_set(the_chip, chg_current);
2780}
2781
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002782#define TEMP_HYSTERISIS_DEGC 2
2783static void battery_cool(bool enter)
2784{
2785 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002786 if (enter == the_chip->is_bat_cool)
2787 return;
2788 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002789 if (enter) {
2790 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002791 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002792 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002793 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002794 pm_chg_vbatdet_set(the_chip,
2795 the_chip->cool_bat_voltage
2796 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002797 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002798 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002799 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002800 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002801 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002802 the_chip->max_voltage_mv
2803 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002804 }
2805 schedule_work(&btm_config_work);
2806}
2807
2808static void battery_warm(bool enter)
2809{
2810 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002811 if (enter == the_chip->is_bat_warm)
2812 return;
2813 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002814 if (enter) {
2815 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002816 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002817 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002818 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002819 pm_chg_vbatdet_set(the_chip,
2820 the_chip->warm_bat_voltage
2821 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002822 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002823 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002824 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002825 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002826 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002827 the_chip->max_voltage_mv
2828 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002829 }
2830 schedule_work(&btm_config_work);
2831}
2832
2833static int configure_btm(struct pm8921_chg_chip *chip)
2834{
2835 int rc;
2836
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002837 if (chip->warm_temp_dc != INT_MIN)
2838 btm_config.btm_warm_fn = battery_warm;
2839 else
2840 btm_config.btm_warm_fn = NULL;
2841
2842 if (chip->cool_temp_dc != INT_MIN)
2843 btm_config.btm_cool_fn = battery_cool;
2844 else
2845 btm_config.btm_cool_fn = NULL;
2846
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002847 btm_config.low_thr_temp = chip->cool_temp_dc;
2848 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002849 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002850 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002851 if (rc)
2852 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002853 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002854 if (rc)
2855 pr_err("failed to start btm rc = %d\n", rc);
2856
2857 return rc;
2858}
2859
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002860/**
2861 * set_disable_status_param -
2862 *
2863 * Internal function to disable battery charging and also disable drawing
2864 * any current from the source. The device is forced to run on a battery
2865 * after this.
2866 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867static int set_disable_status_param(const char *val, struct kernel_param *kp)
2868{
2869 int ret;
2870 struct pm8921_chg_chip *chip = the_chip;
2871
2872 ret = param_set_int(val, kp);
2873 if (ret) {
2874 pr_err("error setting value %d\n", ret);
2875 return ret;
2876 }
2877 pr_info("factory set disable param to %d\n", charging_disabled);
2878 if (chip) {
2879 pm_chg_auto_enable(chip, !charging_disabled);
2880 pm_chg_charge_dis(chip, charging_disabled);
2881 }
2882 return 0;
2883}
2884module_param_call(disabled, set_disable_status_param, param_get_uint,
2885 &charging_disabled, 0644);
2886
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002887static int rconn_mohm;
2888static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2889{
2890 int ret;
2891 struct pm8921_chg_chip *chip = the_chip;
2892
2893 ret = param_set_int(val, kp);
2894 if (ret) {
2895 pr_err("error setting value %d\n", ret);
2896 return ret;
2897 }
2898 if (chip)
2899 chip->rconn_mohm = rconn_mohm;
2900 return 0;
2901}
2902module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2903 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002904/**
2905 * set_thermal_mitigation_level -
2906 *
2907 * Internal function to control battery charging current to reduce
2908 * temperature
2909 */
2910static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2911{
2912 int ret;
2913 struct pm8921_chg_chip *chip = the_chip;
2914
2915 ret = param_set_int(val, kp);
2916 if (ret) {
2917 pr_err("error setting value %d\n", ret);
2918 return ret;
2919 }
2920
2921 if (!chip) {
2922 pr_err("called before init\n");
2923 return -EINVAL;
2924 }
2925
2926 if (!chip->thermal_mitigation) {
2927 pr_err("no thermal mitigation\n");
2928 return -EINVAL;
2929 }
2930
2931 if (thermal_mitigation < 0
2932 || thermal_mitigation >= chip->thermal_levels) {
2933 pr_err("out of bound level selected\n");
2934 return -EINVAL;
2935 }
2936
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002937 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002938 return ret;
2939}
2940module_param_call(thermal_mitigation, set_therm_mitigation_level,
2941 param_get_uint,
2942 &thermal_mitigation, 0644);
2943
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002944static int set_usb_max_current(const char *val, struct kernel_param *kp)
2945{
2946 int ret, mA;
2947 struct pm8921_chg_chip *chip = the_chip;
2948
2949 ret = param_set_int(val, kp);
2950 if (ret) {
2951 pr_err("error setting value %d\n", ret);
2952 return ret;
2953 }
2954 if (chip) {
2955 pr_warn("setting current max to %d\n", usb_max_current);
2956 pm_chg_iusbmax_get(chip, &mA);
2957 if (mA > usb_max_current)
2958 pm8921_charger_vbus_draw(usb_max_current);
2959 return 0;
2960 }
2961 return -EINVAL;
2962}
David Keitelacf57c82012-03-07 18:48:50 -08002963module_param_call(usb_max_current, set_usb_max_current,
2964 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966static void free_irqs(struct pm8921_chg_chip *chip)
2967{
2968 int i;
2969
2970 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2971 if (chip->pmic_chg_irq[i]) {
2972 free_irq(chip->pmic_chg_irq[i], chip);
2973 chip->pmic_chg_irq[i] = 0;
2974 }
2975}
2976
David Keitel88e1b572012-01-11 11:57:14 -08002977/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2979{
2980 unsigned long flags;
2981 int fsm_state;
2982
2983 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2984 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2985
2986 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002987 if (chip->usb_present) {
2988 schedule_delayed_work(&chip->unplug_check_work,
2989 round_jiffies_relative(msecs_to_jiffies
2990 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002991 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002992 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993
2994 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2995 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2996 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002997 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2998 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2999 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
3000 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3001 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003002 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003003 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3004 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08003005 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006
3007 spin_lock_irqsave(&vbus_lock, flags);
3008 if (usb_chg_current) {
3009 /* reissue a vbus draw call */
3010 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003011 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012 }
3013 spin_unlock_irqrestore(&vbus_lock, flags);
3014
3015 fsm_state = pm_chg_get_fsm_state(chip);
3016 if (is_battery_charging(fsm_state)) {
3017 chip->bms_notify.is_charging = 1;
3018 pm8921_bms_charging_began();
3019 }
3020
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003021 check_battery_valid(chip);
3022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3024 chip->usb_present,
3025 chip->dc_present,
3026 get_prop_batt_present(chip),
3027 fsm_state);
3028}
3029
3030struct pm_chg_irq_init_data {
3031 unsigned int irq_id;
3032 char *name;
3033 unsigned long flags;
3034 irqreturn_t (*handler)(int, void *);
3035};
3036
3037#define CHG_IRQ(_id, _flags, _handler) \
3038{ \
3039 .irq_id = _id, \
3040 .name = #_id, \
3041 .flags = _flags, \
3042 .handler = _handler, \
3043}
3044struct pm_chg_irq_init_data chg_irq_data[] = {
3045 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3046 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003047 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3049 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003050 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3051 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3053 usbin_uv_irq_handler),
3054 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3055 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3056 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3057 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3058 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3059 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3060 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3061 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3062 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003063 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3064 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3066 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3067 batt_removed_irq_handler),
3068 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3069 batttemp_hot_irq_handler),
3070 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3071 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3072 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003073 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3074 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003075 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3076 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003077 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3078 coarse_det_low_irq_handler),
3079 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3080 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3081 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3082 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3083 batfet_irq_handler),
3084 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3085 dcin_valid_irq_handler),
3086 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3087 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003088 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089};
3090
3091static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3092 struct platform_device *pdev)
3093{
3094 struct resource *res;
3095 int ret, i;
3096
3097 ret = 0;
3098 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3099
3100 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3101 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3102 chg_irq_data[i].name);
3103 if (res == NULL) {
3104 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3105 goto err_out;
3106 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003107 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108 ret = request_irq(res->start, chg_irq_data[i].handler,
3109 chg_irq_data[i].flags,
3110 chg_irq_data[i].name, chip);
3111 if (ret < 0) {
3112 pr_err("couldn't request %d (%s) %d\n", res->start,
3113 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003114 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 goto err_out;
3116 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3118 }
3119 return 0;
3120
3121err_out:
3122 free_irqs(chip);
3123 return -EINVAL;
3124}
3125
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003126static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3127{
3128 int err;
3129 u8 temp;
3130
3131 temp = 0xD1;
3132 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3133 if (err) {
3134 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3135 return;
3136 }
3137
3138 temp = 0xD3;
3139 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3140 if (err) {
3141 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3142 return;
3143 }
3144
3145 temp = 0xD1;
3146 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3147 if (err) {
3148 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3149 return;
3150 }
3151
3152 temp = 0xD5;
3153 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3154 if (err) {
3155 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3156 return;
3157 }
3158
3159 udelay(183);
3160
3161 temp = 0xD1;
3162 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3163 if (err) {
3164 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3165 return;
3166 }
3167
3168 temp = 0xD0;
3169 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3170 if (err) {
3171 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3172 return;
3173 }
3174 udelay(32);
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 = 0xD3;
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
3191static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3192{
3193 int err;
3194 u8 temp;
3195
3196 temp = 0xD1;
3197 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3198 if (err) {
3199 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3200 return;
3201 }
3202
3203 temp = 0xD0;
3204 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3205 if (err) {
3206 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3207 return;
3208 }
3209}
3210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211#define ENUM_TIMER_STOP_BIT BIT(1)
3212#define BOOT_DONE_BIT BIT(6)
3213#define CHG_BATFET_ON_BIT BIT(3)
3214#define CHG_VCP_EN BIT(0)
3215#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3216#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003217#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3219{
3220 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003221 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222
3223 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3224 BOOT_DONE_BIT, BOOT_DONE_BIT);
3225 if (rc) {
3226 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3227 return rc;
3228 }
3229
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003230 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3231
3232 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3233 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3234
3235 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003237 if (rc) {
3238 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003239 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 return rc;
3241 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003242 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003243 chip->max_voltage_mv
3244 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003245 if (rc) {
3246 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003247 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003248 return rc;
3249 }
3250
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003251 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 if (rc) {
3253 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003254 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003255 return rc;
3256 }
3257 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3258 if (rc) {
3259 pr_err("Failed to set max voltage to %d rc=%d\n",
3260 SAFE_CURRENT_MA, rc);
3261 return rc;
3262 }
3263
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003264 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265 if (rc) {
3266 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3267 return rc;
3268 }
3269
3270 rc = pm_chg_iterm_set(chip, chip->term_current);
3271 if (rc) {
3272 pr_err("Failed to set term current to %d rc=%d\n",
3273 chip->term_current, rc);
3274 return rc;
3275 }
3276
3277 /* Disable the ENUM TIMER */
3278 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3279 ENUM_TIMER_STOP_BIT);
3280 if (rc) {
3281 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3282 return rc;
3283 }
3284
3285 /* init with the lowest USB current */
David Keitelacf57c82012-03-07 18:48:50 -08003286 rc = pm_chg_iusbmax_set(chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08003288 pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 return rc;
3290 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003291
3292 if (chip->safety_time != 0) {
3293 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3294 if (rc) {
3295 pr_err("Failed to set max time to %d minutes rc=%d\n",
3296 chip->safety_time, rc);
3297 return rc;
3298 }
3299 }
3300
3301 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003302 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003303 if (rc) {
3304 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3305 chip->safety_time, rc);
3306 return rc;
3307 }
3308 }
3309
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003310 if (chip->vin_min != 0) {
3311 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3312 if (rc) {
3313 pr_err("Failed to set vin min to %d mV rc=%d\n",
3314 chip->vin_min, rc);
3315 return rc;
3316 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003317 } else {
3318 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003319 }
3320
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003321 rc = pm_chg_disable_wd(chip);
3322 if (rc) {
3323 pr_err("Failed to disable wd rc=%d\n", rc);
3324 return rc;
3325 }
3326
3327 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3328 CHG_BAT_TEMP_DIS_BIT, 0);
3329 if (rc) {
3330 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3331 return rc;
3332 }
3333 /* switch to a 3.2Mhz for the buck */
3334 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3335 if (rc) {
3336 pr_err("Failed to switch buck clk rc=%d\n", rc);
3337 return rc;
3338 }
3339
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003340 if (chip->trkl_voltage != 0) {
3341 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3342 if (rc) {
3343 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3344 chip->trkl_voltage, rc);
3345 return rc;
3346 }
3347 }
3348
3349 if (chip->weak_voltage != 0) {
3350 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3351 if (rc) {
3352 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3353 chip->weak_voltage, rc);
3354 return rc;
3355 }
3356 }
3357
3358 if (chip->trkl_current != 0) {
3359 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3360 if (rc) {
3361 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3362 chip->trkl_voltage, rc);
3363 return rc;
3364 }
3365 }
3366
3367 if (chip->weak_current != 0) {
3368 rc = pm_chg_iweak_set(chip, chip->weak_current);
3369 if (rc) {
3370 pr_err("Failed to set weak current to %dmA rc=%d\n",
3371 chip->weak_current, rc);
3372 return rc;
3373 }
3374 }
3375
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003376 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3377 if (rc) {
3378 pr_err("Failed to set cold config %d rc=%d\n",
3379 chip->cold_thr, rc);
3380 }
3381
3382 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3383 if (rc) {
3384 pr_err("Failed to set hot config %d rc=%d\n",
3385 chip->hot_thr, rc);
3386 }
3387
Jay Chokshid674a512012-03-15 14:06:04 -07003388 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3389 if (rc) {
3390 pr_err("Failed to set charger LED src config %d rc=%d\n",
3391 chip->led_src_config, rc);
3392 }
3393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394 /* Workarounds for die 1.1 and 1.0 */
3395 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3396 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3398 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003399
3400 /* software workaround for correct battery_id detection */
3401 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3402 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3403 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3404 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3405 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3406 udelay(100);
3407 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408 }
3409
David Keitelb51995e2011-11-18 17:03:31 -08003410 /* Workarounds for die 3.0 */
3411 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3412 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3413
3414 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3415
David Keitela3c0d822011-11-03 14:18:52 -07003416 /* Disable EOC FSM processing */
3417 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3418
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003419 pm8921_chg_force_19p2mhz_clk(chip);
3420
3421 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3422 VREF_BATT_THERM_FORCE_ON);
3423 if (rc)
3424 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003426 rc = pm_chg_charge_dis(chip, charging_disabled);
3427 if (rc) {
3428 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3429 return rc;
3430 }
3431
3432 rc = pm_chg_auto_enable(chip, !charging_disabled);
3433 if (rc) {
3434 pr_err("Failed to enable charging rc=%d\n", rc);
3435 return rc;
3436 }
3437
3438 return 0;
3439}
3440
3441static int get_rt_status(void *data, u64 * val)
3442{
3443 int i = (int)data;
3444 int ret;
3445
3446 /* global irq number is passed in via data */
3447 ret = pm_chg_get_rt_status(the_chip, i);
3448 *val = ret;
3449 return 0;
3450}
3451DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3452
3453static int get_fsm_status(void *data, u64 * val)
3454{
3455 u8 temp;
3456
3457 temp = pm_chg_get_fsm_state(the_chip);
3458 *val = temp;
3459 return 0;
3460}
3461DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3462
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003463static int get_reg_loop(void *data, u64 * val)
3464{
3465 u8 temp;
3466
3467 if (!the_chip) {
3468 pr_err("%s called before init\n", __func__);
3469 return -EINVAL;
3470 }
3471 temp = pm_chg_get_regulation_loop(the_chip);
3472 *val = temp;
3473 return 0;
3474}
3475DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477static int get_reg(void *data, u64 * val)
3478{
3479 int addr = (int)data;
3480 int ret;
3481 u8 temp;
3482
3483 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3484 if (ret) {
3485 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3486 addr, temp, ret);
3487 return -EAGAIN;
3488 }
3489 *val = temp;
3490 return 0;
3491}
3492
3493static int set_reg(void *data, u64 val)
3494{
3495 int addr = (int)data;
3496 int ret;
3497 u8 temp;
3498
3499 temp = (u8) val;
3500 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3501 if (ret) {
3502 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3503 addr, temp, ret);
3504 return -EAGAIN;
3505 }
3506 return 0;
3507}
3508DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3509
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003510enum {
3511 BAT_WARM_ZONE,
3512 BAT_COOL_ZONE,
3513};
3514static int get_warm_cool(void *data, u64 * val)
3515{
3516 if (!the_chip) {
3517 pr_err("%s called before init\n", __func__);
3518 return -EINVAL;
3519 }
3520 if ((int)data == BAT_WARM_ZONE)
3521 *val = the_chip->is_bat_warm;
3522 if ((int)data == BAT_COOL_ZONE)
3523 *val = the_chip->is_bat_cool;
3524 return 0;
3525}
3526DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003528static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3529{
3530 int i;
3531
3532 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3533
3534 if (IS_ERR(chip->dent)) {
3535 pr_err("pmic charger couldnt create debugfs dir\n");
3536 return;
3537 }
3538
3539 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3540 (void *)CHG_CNTRL, &reg_fops);
3541 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3542 (void *)CHG_CNTRL_2, &reg_fops);
3543 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3544 (void *)CHG_CNTRL_3, &reg_fops);
3545 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3546 (void *)PBL_ACCESS1, &reg_fops);
3547 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3548 (void *)PBL_ACCESS2, &reg_fops);
3549 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3550 (void *)SYS_CONFIG_1, &reg_fops);
3551 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3552 (void *)SYS_CONFIG_2, &reg_fops);
3553 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3554 (void *)CHG_VDD_MAX, &reg_fops);
3555 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3556 (void *)CHG_VDD_SAFE, &reg_fops);
3557 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3558 (void *)CHG_VBAT_DET, &reg_fops);
3559 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3560 (void *)CHG_IBAT_MAX, &reg_fops);
3561 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3562 (void *)CHG_IBAT_SAFE, &reg_fops);
3563 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3564 (void *)CHG_VIN_MIN, &reg_fops);
3565 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3566 (void *)CHG_VTRICKLE, &reg_fops);
3567 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3568 (void *)CHG_ITRICKLE, &reg_fops);
3569 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3570 (void *)CHG_ITERM, &reg_fops);
3571 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3572 (void *)CHG_TCHG_MAX, &reg_fops);
3573 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3574 (void *)CHG_TWDOG, &reg_fops);
3575 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3576 (void *)CHG_TEMP_THRESH, &reg_fops);
3577 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3578 (void *)CHG_COMP_OVR, &reg_fops);
3579 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3580 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3581 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3582 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3583 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3584 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3585 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3586 (void *)CHG_TEST, &reg_fops);
3587
3588 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3589 &fsm_fops);
3590
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003591 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3592 &reg_loop_fops);
3593
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003594 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3595 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3596 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3597 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003599 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3600 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3601 debugfs_create_file(chg_irq_data[i].name, 0444,
3602 chip->dent,
3603 (void *)chg_irq_data[i].irq_id,
3604 &rt_fops);
3605 }
3606}
3607
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003608static int pm8921_charger_suspend_noirq(struct device *dev)
3609{
3610 int rc;
3611 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3612
3613 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3614 if (rc)
3615 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3616 pm8921_chg_set_hw_clk_switching(chip);
3617 return 0;
3618}
3619
3620static int pm8921_charger_resume_noirq(struct device *dev)
3621{
3622 int rc;
3623 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3624
3625 pm8921_chg_force_19p2mhz_clk(chip);
3626
3627 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3628 VREF_BATT_THERM_FORCE_ON);
3629 if (rc)
3630 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3631 return 0;
3632}
3633
David Keitelf2226022011-12-13 15:55:50 -08003634static int pm8921_charger_resume(struct device *dev)
3635{
3636 int rc;
3637 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3638
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003639 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003640 && !(chip->keep_btm_on_suspend)) {
3641 rc = pm8xxx_adc_btm_configure(&btm_config);
3642 if (rc)
3643 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3644
3645 rc = pm8xxx_adc_btm_start();
3646 if (rc)
3647 pr_err("couldn't restart btm rc=%d\n", rc);
3648 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003649 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3650 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3651 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3652 }
David Keitelf2226022011-12-13 15:55:50 -08003653 return 0;
3654}
3655
3656static int pm8921_charger_suspend(struct device *dev)
3657{
3658 int rc;
3659 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3660
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003661 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003662 && !(chip->keep_btm_on_suspend)) {
3663 rc = pm8xxx_adc_btm_end();
3664 if (rc)
3665 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3666 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003667
3668 if (is_usb_chg_plugged_in(chip)) {
3669 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3670 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3671 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003672
David Keitelf2226022011-12-13 15:55:50 -08003673 return 0;
3674}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3676{
3677 int rc = 0;
3678 struct pm8921_chg_chip *chip;
3679 const struct pm8921_charger_platform_data *pdata
3680 = pdev->dev.platform_data;
3681
3682 if (!pdata) {
3683 pr_err("missing platform data\n");
3684 return -EINVAL;
3685 }
3686
3687 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3688 GFP_KERNEL);
3689 if (!chip) {
3690 pr_err("Cannot allocate pm_chg_chip\n");
3691 return -ENOMEM;
3692 }
3693
3694 chip->dev = &pdev->dev;
3695 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003696 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003698 chip->max_voltage_mv = pdata->max_voltage;
3699 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003700 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 chip->term_current = pdata->term_current;
3702 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003703 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003704 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3705 chip->batt_id_min = pdata->batt_id_min;
3706 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003707 if (pdata->cool_temp != INT_MIN)
3708 chip->cool_temp_dc = pdata->cool_temp * 10;
3709 else
3710 chip->cool_temp_dc = INT_MIN;
3711
3712 if (pdata->warm_temp != INT_MIN)
3713 chip->warm_temp_dc = pdata->warm_temp * 10;
3714 else
3715 chip->warm_temp_dc = INT_MIN;
3716
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003717 chip->temp_check_period = pdata->temp_check_period;
3718 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3719 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3720 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3721 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3722 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003723 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003724 chip->trkl_voltage = pdata->trkl_voltage;
3725 chip->weak_voltage = pdata->weak_voltage;
3726 chip->trkl_current = pdata->trkl_current;
3727 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003728 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003729 chip->thermal_mitigation = pdata->thermal_mitigation;
3730 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003731
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003732 chip->cold_thr = pdata->cold_thr;
3733 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003734 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003735 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737 rc = pm8921_chg_hw_init(chip);
3738 if (rc) {
3739 pr_err("couldn't init hardware rc=%d\n", rc);
3740 goto free_chip;
3741 }
3742
3743 chip->usb_psy.name = "usb",
3744 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3745 chip->usb_psy.supplied_to = pm_power_supplied_to,
3746 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003747 chip->usb_psy.properties = pm_power_props_usb,
3748 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3749 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750
David Keitel6ed71a52012-01-30 12:42:18 -08003751 chip->dc_psy.name = "pm8921-dc",
3752 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3753 chip->dc_psy.supplied_to = pm_power_supplied_to,
3754 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003755 chip->dc_psy.properties = pm_power_props_mains,
3756 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3757 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 chip->batt_psy.name = "battery",
3760 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3761 chip->batt_psy.properties = msm_batt_power_props,
3762 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3763 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003764 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003765 rc = power_supply_register(chip->dev, &chip->usb_psy);
3766 if (rc < 0) {
3767 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003768 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 }
3770
David Keitel6ed71a52012-01-30 12:42:18 -08003771 rc = power_supply_register(chip->dev, &chip->dc_psy);
3772 if (rc < 0) {
3773 pr_err("power_supply_register usb failed rc = %d\n", rc);
3774 goto unregister_usb;
3775 }
3776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777 rc = power_supply_register(chip->dev, &chip->batt_psy);
3778 if (rc < 0) {
3779 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003780 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003781 }
3782
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003783 platform_set_drvdata(pdev, chip);
3784 the_chip = chip;
3785
3786 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003787 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003788 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3789 vin_collapse_check_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003790 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3791 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003792 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003794 rc = request_irqs(chip, pdev);
3795 if (rc) {
3796 pr_err("couldn't register interrupts rc=%d\n", rc);
3797 goto unregister_batt;
3798 }
3799
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003800 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3801 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3802 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003803 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3804 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003805 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003806 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003807 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003808 * care for jeita compliance
3809 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003810 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003811 rc = configure_btm(chip);
3812 if (rc) {
3813 pr_err("couldn't register with btm rc=%d\n", rc);
3814 goto free_irq;
3815 }
3816 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 create_debugfs_entries(chip);
3819
3820 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003821 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823 /* determine what state the charger is in */
3824 determine_initial_state(chip);
3825
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003826 if (chip->update_time) {
3827 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3828 update_heartbeat);
3829 schedule_delayed_work(&chip->update_heartbeat_work,
3830 round_jiffies_relative(msecs_to_jiffies
3831 (chip->update_time)));
3832 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 return 0;
3834
3835free_irq:
3836 free_irqs(chip);
3837unregister_batt:
3838 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003839unregister_dc:
3840 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841unregister_usb:
3842 power_supply_unregister(&chip->usb_psy);
3843free_chip:
3844 kfree(chip);
3845 return rc;
3846}
3847
3848static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3849{
3850 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3851
3852 free_irqs(chip);
3853 platform_set_drvdata(pdev, NULL);
3854 the_chip = NULL;
3855 kfree(chip);
3856 return 0;
3857}
David Keitelf2226022011-12-13 15:55:50 -08003858static const struct dev_pm_ops pm8921_pm_ops = {
3859 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003860 .suspend_noirq = pm8921_charger_suspend_noirq,
3861 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003862 .resume = pm8921_charger_resume,
3863};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003865 .probe = pm8921_charger_probe,
3866 .remove = __devexit_p(pm8921_charger_remove),
3867 .driver = {
3868 .name = PM8921_CHARGER_DEV_NAME,
3869 .owner = THIS_MODULE,
3870 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003871 },
3872};
3873
3874static int __init pm8921_charger_init(void)
3875{
3876 return platform_driver_register(&pm8921_charger_driver);
3877}
3878
3879static void __exit pm8921_charger_exit(void)
3880{
3881 platform_driver_unregister(&pm8921_charger_driver);
3882}
3883
3884late_initcall(pm8921_charger_init);
3885module_exit(pm8921_charger_exit);
3886
3887MODULE_LICENSE("GPL v2");
3888MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3889MODULE_VERSION("1.0");
3890MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);