blob: 1454ca99e2874f16bcf74453b6eb1bd3a8e11847 [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
80
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070081/* check EOC every 10 seconds */
82#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080083/* check for USB unplug every 200 msecs */
84#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086enum chg_fsm_state {
87 FSM_STATE_OFF_0 = 0,
88 FSM_STATE_BATFETDET_START_12 = 12,
89 FSM_STATE_BATFETDET_END_16 = 16,
90 FSM_STATE_ON_CHG_HIGHI_1 = 1,
91 FSM_STATE_ATC_2A = 2,
92 FSM_STATE_ATC_2B = 18,
93 FSM_STATE_ON_BAT_3 = 3,
94 FSM_STATE_ATC_FAIL_4 = 4 ,
95 FSM_STATE_DELAY_5 = 5,
96 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
97 FSM_STATE_FAST_CHG_7 = 7,
98 FSM_STATE_TRKL_CHG_8 = 8,
99 FSM_STATE_CHG_FAIL_9 = 9,
100 FSM_STATE_EOC_10 = 10,
101 FSM_STATE_ON_CHG_VREGOK_11 = 11,
102 FSM_STATE_ATC_PAUSE_13 = 13,
103 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
104 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
105 FSM_STATE_START_BOOT = 20,
106 FSM_STATE_FLCB_VREGOK = 21,
107 FSM_STATE_FLCB = 22,
108};
109
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700110struct fsm_state_to_batt_status {
111 enum chg_fsm_state fsm_state;
112 int batt_state;
113};
114
115static struct fsm_state_to_batt_status map[] = {
116 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
117 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
118 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
119 /*
120 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
121 * too hot/cold, charger too hot
122 */
123 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
124 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
125 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
126 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
127 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
128 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
129 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
130 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
133 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
134 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
135 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
136 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
141};
142
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700143enum chg_regulation_loop {
144 VDD_LOOP = BIT(3),
145 BAT_CURRENT_LOOP = BIT(2),
146 INPUT_CURRENT_LOOP = BIT(1),
147 INPUT_VOLTAGE_LOOP = BIT(0),
148 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
149 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
150};
151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152enum pmic_chg_interrupts {
153 USBIN_VALID_IRQ = 0,
154 USBIN_OV_IRQ,
155 BATT_INSERTED_IRQ,
156 VBATDET_LOW_IRQ,
157 USBIN_UV_IRQ,
158 VBAT_OV_IRQ,
159 CHGWDOG_IRQ,
160 VCP_IRQ,
161 ATCDONE_IRQ,
162 ATCFAIL_IRQ,
163 CHGDONE_IRQ,
164 CHGFAIL_IRQ,
165 CHGSTATE_IRQ,
166 LOOP_CHANGE_IRQ,
167 FASTCHG_IRQ,
168 TRKLCHG_IRQ,
169 BATT_REMOVED_IRQ,
170 BATTTEMP_HOT_IRQ,
171 CHGHOT_IRQ,
172 BATTTEMP_COLD_IRQ,
173 CHG_GONE_IRQ,
174 BAT_TEMP_OK_IRQ,
175 COARSE_DET_LOW_IRQ,
176 VDD_LOOP_IRQ,
177 VREG_OV_IRQ,
178 VBATDET_IRQ,
179 BATFET_IRQ,
180 PSI_IRQ,
181 DCIN_VALID_IRQ,
182 DCIN_OV_IRQ,
183 DCIN_UV_IRQ,
184 PM_CHG_MAX_INTS,
185};
186
187struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700188 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 int is_charging;
190 struct work_struct work;
191};
192
193/**
194 * struct pm8921_chg_chip -device information
195 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 * @usb_present: present status of usb
197 * @dc_present: present status of dc
198 * @usb_charger_current: usb current to charge the battery with used when
199 * the usb path is enabled or charging is resumed
200 * @safety_time: max time for which charging will happen
201 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800202 * @max_voltage_mv: the max volts the batt should be charged up to
203 * @min_voltage_mv: the min battery voltage before turning the FETon
204 * @cool_temp_dc: the cool temp threshold in deciCelcius
205 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700206 * @resume_voltage_delta: the voltage delta from vdd max at which the
207 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @term_current: The charging based term current
209 *
210 */
211struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700212 struct device *dev;
213 unsigned int usb_present;
214 unsigned int dc_present;
215 unsigned int usb_charger_current;
216 unsigned int max_bat_chg_current;
217 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
218 unsigned int safety_time;
219 unsigned int ttrkl_time;
220 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800221 unsigned int max_voltage_mv;
222 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800223 int cool_temp_dc;
224 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700225 unsigned int temp_check_period;
226 unsigned int cool_bat_chg_current;
227 unsigned int warm_bat_chg_current;
228 unsigned int cool_bat_voltage;
229 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700230 unsigned int is_bat_cool;
231 unsigned int is_bat_warm;
232 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700233 unsigned int term_current;
234 unsigned int vbat_channel;
235 unsigned int batt_temp_channel;
236 unsigned int batt_id_channel;
237 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800238 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800239 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700240 struct power_supply batt_psy;
241 struct dentry *dent;
242 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800243 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200244 bool ext_charging;
245 bool ext_charge_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 struct work_struct battery_id_valid_work;
248 int64_t batt_id_min;
249 int64_t batt_id_max;
250 int trkl_voltage;
251 int weak_voltage;
252 int trkl_current;
253 int weak_current;
254 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800255 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700256 int thermal_levels;
257 struct delayed_work update_heartbeat_work;
258 struct delayed_work eoc_work;
David Keitel8c5201a2012-02-24 16:08:54 -0800259 struct work_struct unplug_ovp_fet_open_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800260 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800261 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct wake_lock eoc_wake_lock;
263 enum pm8921_chg_cold_thr cold_thr;
264 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800265 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700266 enum pm8921_chg_led_src_config led_src_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267};
268
David Keitelacf57c82012-03-07 18:48:50 -0800269/* user space parameter to limit usb current */
270static unsigned int usb_max_current;
271/*
272 * usb_target_ma is used for wall charger
273 * adaptive input current limiting only. Use
274 * pm_iusbmax_get() to get current maximum usb current setting.
275 */
276static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700278static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279
280static struct pm8921_chg_chip *the_chip;
281
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700282static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
285 u8 mask, u8 val)
286{
287 int rc;
288 u8 reg;
289
290 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
291 if (rc) {
292 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
293 return rc;
294 }
295 reg &= ~mask;
296 reg |= val & mask;
297 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
298 if (rc) {
299 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
300 return rc;
301 }
302 return 0;
303}
304
David Keitelcf867232012-01-27 18:40:12 -0800305static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
306{
307 return pm8xxx_read_irq_stat(chip->dev->parent,
308 chip->pmic_chg_irq[irq_id]);
309}
310
311/* Treat OverVoltage/UnderVoltage as source missing */
312static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
313{
314 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
315}
316
317/* Treat OverVoltage/UnderVoltage as source missing */
318static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
319{
320 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
321}
322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323#define CAPTURE_FSM_STATE_CMD 0xC2
324#define READ_BANK_7 0x70
325#define READ_BANK_4 0x40
326static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
327{
328 u8 temp;
329 int err, ret = 0;
330
331 temp = CAPTURE_FSM_STATE_CMD;
332 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
333 if (err) {
334 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
335 return err;
336 }
337
338 temp = READ_BANK_7;
339 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
340 if (err) {
341 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
342 return err;
343 }
344
345 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
346 if (err) {
347 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
348 return err;
349 }
350 /* get the lower 4 bits */
351 ret = temp & 0xF;
352
353 temp = READ_BANK_4;
354 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
355 if (err) {
356 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
357 return err;
358 }
359
360 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
361 if (err) {
362 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
363 return err;
364 }
365 /* get the upper 1 bit */
366 ret |= (temp & 0x1) << 4;
367 return ret;
368}
369
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700370#define READ_BANK_6 0x60
371static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
372{
373 u8 temp;
374 int err;
375
376 temp = READ_BANK_6;
377 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
378 if (err) {
379 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
380 return err;
381 }
382
383 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
384 if (err) {
385 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
386 return err;
387 }
388
389 /* return the lower 4 bits */
390 return temp & CHG_ALL_LOOPS;
391}
392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393#define CHG_USB_SUSPEND_BIT BIT(2)
394static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
395{
396 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
397 enable ? CHG_USB_SUSPEND_BIT : 0);
398}
399
400#define CHG_EN_BIT BIT(7)
401static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
402{
403 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
404 enable ? CHG_EN_BIT : 0);
405}
406
David Keitel753ec8d2011-11-02 10:56:37 -0700407#define CHG_FAILED_CLEAR BIT(0)
408#define ATC_FAILED_CLEAR BIT(1)
409static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
410{
411 int rc;
412
413 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
414 clear ? ATC_FAILED_CLEAR : 0);
415 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
416 clear ? CHG_FAILED_CLEAR : 0);
417 return rc;
418}
419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420#define CHG_CHARGE_DIS_BIT BIT(1)
421static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
422{
423 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
424 disable ? CHG_CHARGE_DIS_BIT : 0);
425}
426
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800427static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
428{
429 u8 temp;
430
431 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
432 return temp & CHG_CHARGE_DIS_BIT;
433}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434#define PM8921_CHG_V_MIN_MV 3240
435#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800436#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437#define PM8921_CHG_VDDMAX_MAX 4500
438#define PM8921_CHG_VDDMAX_MIN 3400
439#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800440static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800442 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800443 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800445 if (voltage < PM8921_CHG_VDDMAX_MIN
446 || voltage > PM8921_CHG_VDDMAX_MAX) {
447 pr_err("bad mV=%d asked to set\n", voltage);
448 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449 }
David Keitelcf867232012-01-27 18:40:12 -0800450
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800451 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
452
453 remainder = voltage % 20;
454 if (remainder >= 10) {
455 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
456 }
457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800459 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460}
461
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700462static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
463{
464 u8 temp;
465 int rc;
466
467 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
468 if (rc) {
469 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700470 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700471 return rc;
472 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800473 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
474 + PM8921_CHG_V_MIN_MV;
475 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
476 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700477 return 0;
478}
479
David Keitelcf867232012-01-27 18:40:12 -0800480static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
481{
482 int current_mv, ret, steps, i;
483 bool increase;
484
485 ret = 0;
486
487 if (voltage < PM8921_CHG_VDDMAX_MIN
488 || voltage > PM8921_CHG_VDDMAX_MAX) {
489 pr_err("bad mV=%d asked to set\n", voltage);
490 return -EINVAL;
491 }
492
493 ret = pm_chg_vddmax_get(chip, &current_mv);
494 if (ret) {
495 pr_err("Failed to read vddmax rc=%d\n", ret);
496 return -EINVAL;
497 }
498 if (current_mv == voltage)
499 return 0;
500
501 /* Only change in increments when USB is present */
502 if (is_usb_chg_plugged_in(chip)) {
503 if (current_mv < voltage) {
504 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
505 increase = true;
506 } else {
507 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
508 increase = false;
509 }
510 for (i = 0; i < steps; i++) {
511 if (increase)
512 current_mv += PM8921_CHG_V_STEP_MV;
513 else
514 current_mv -= PM8921_CHG_V_STEP_MV;
515 ret |= __pm_chg_vddmax_set(chip, current_mv);
516 }
517 }
518 ret |= __pm_chg_vddmax_set(chip, voltage);
519 return ret;
520}
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522#define PM8921_CHG_VDDSAFE_MIN 3400
523#define PM8921_CHG_VDDSAFE_MAX 4500
524static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
525{
526 u8 temp;
527
528 if (voltage < PM8921_CHG_VDDSAFE_MIN
529 || voltage > PM8921_CHG_VDDSAFE_MAX) {
530 pr_err("bad mV=%d asked to set\n", voltage);
531 return -EINVAL;
532 }
533 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
534 pr_debug("voltage=%d setting %02x\n", voltage, temp);
535 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
536}
537
538#define PM8921_CHG_VBATDET_MIN 3240
539#define PM8921_CHG_VBATDET_MAX 5780
540static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
541{
542 u8 temp;
543
544 if (voltage < PM8921_CHG_VBATDET_MIN
545 || voltage > PM8921_CHG_VBATDET_MAX) {
546 pr_err("bad mV=%d asked to set\n", voltage);
547 return -EINVAL;
548 }
549 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
550 pr_debug("voltage=%d setting %02x\n", voltage, temp);
551 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
552}
553
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700554#define PM8921_CHG_VINMIN_MIN_MV 3800
555#define PM8921_CHG_VINMIN_STEP_MV 100
556#define PM8921_CHG_VINMIN_USABLE_MAX 6500
557#define PM8921_CHG_VINMIN_USABLE_MIN 4300
558#define PM8921_CHG_VINMIN_MASK 0x1F
559static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
560{
561 u8 temp;
562
563 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
564 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
565 pr_err("bad mV=%d asked to set\n", voltage);
566 return -EINVAL;
567 }
568 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
569 pr_debug("voltage=%d setting %02x\n", voltage, temp);
570 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
571 temp);
572}
573
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800574static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
575{
576 u8 temp;
577 int rc, voltage_mv;
578
579 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
580 temp &= PM8921_CHG_VINMIN_MASK;
581
582 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
583 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
584
585 return voltage_mv;
586}
587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588#define PM8921_CHG_IBATMAX_MIN 325
589#define PM8921_CHG_IBATMAX_MAX 2000
590#define PM8921_CHG_I_MIN_MA 225
591#define PM8921_CHG_I_STEP_MA 50
592#define PM8921_CHG_I_MASK 0x3F
593static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
594{
595 u8 temp;
596
597 if (chg_current < PM8921_CHG_IBATMAX_MIN
598 || chg_current > PM8921_CHG_IBATMAX_MAX) {
599 pr_err("bad mA=%d asked to set\n", chg_current);
600 return -EINVAL;
601 }
602 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
603 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
604}
605
606#define PM8921_CHG_IBATSAFE_MIN 225
607#define PM8921_CHG_IBATSAFE_MAX 3375
608static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
609{
610 u8 temp;
611
612 if (chg_current < PM8921_CHG_IBATSAFE_MIN
613 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
614 pr_err("bad mA=%d asked to set\n", chg_current);
615 return -EINVAL;
616 }
617 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
618 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
619 PM8921_CHG_I_MASK, temp);
620}
621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700623#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624#define PM8921_CHG_ITERM_STEP_MA 10
625#define PM8921_CHG_ITERM_MASK 0xF
626static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
627{
628 u8 temp;
629
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700630 if (chg_current < PM8921_CHG_ITERM_MIN_MA
631 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 pr_err("bad mA=%d asked to set\n", chg_current);
633 return -EINVAL;
634 }
635
636 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
637 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700638 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 temp);
640}
641
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700642static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
643{
644 u8 temp;
645 int rc;
646
647 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
648 if (rc) {
649 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700650 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700651 return rc;
652 }
653 temp &= PM8921_CHG_ITERM_MASK;
654 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
655 + PM8921_CHG_ITERM_MIN_MA;
656 return 0;
657}
658
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800659struct usb_ma_limit_entry {
660 int usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800661};
662
663static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitelacf57c82012-03-07 18:48:50 -0800664 {100},
665 {500},
666 {700},
667 {850},
668 {900},
669 {1100},
670 {1300},
671 {1500},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800672};
673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674#define PM8921_CHG_IUSB_MASK 0x1C
675#define PM8921_CHG_IUSB_MAX 7
676#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700677static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678{
679 u8 temp;
680
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700681 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
682 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 return -EINVAL;
684 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700685 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
687 temp);
688}
689
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800690static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
691{
692 u8 temp;
David Keitelacf57c82012-03-07 18:48:50 -0800693 int rc;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800694
695 *mA = 0;
696 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
697 if (rc) {
698 pr_err("err=%d reading PBL_ACCESS2\n", rc);
699 return rc;
700 }
701 temp &= PM8921_CHG_IUSB_MASK;
702 temp = temp >> 2;
David Keitelacf57c82012-03-07 18:48:50 -0800703 *mA = usb_ma_table[temp].usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800704 return rc;
705}
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707#define PM8921_CHG_WD_MASK 0x1F
708static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
709{
710 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700711 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
712}
713
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700714#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700715#define PM8921_CHG_TCHG_MIN 4
716#define PM8921_CHG_TCHG_MAX 512
717#define PM8921_CHG_TCHG_STEP 4
718static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
719{
720 u8 temp;
721
722 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
723 pr_err("bad max minutes =%d asked to set\n", minutes);
724 return -EINVAL;
725 }
726
727 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
728 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
729 temp);
730}
731
732#define PM8921_CHG_TTRKL_MASK 0x1F
733#define PM8921_CHG_TTRKL_MIN 1
734#define PM8921_CHG_TTRKL_MAX 64
735static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
736{
737 u8 temp;
738
739 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
740 pr_err("bad max minutes =%d asked to set\n", minutes);
741 return -EINVAL;
742 }
743
744 temp = minutes - 1;
745 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
746 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747}
748
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700749#define PM8921_CHG_VTRKL_MIN_MV 2050
750#define PM8921_CHG_VTRKL_MAX_MV 2800
751#define PM8921_CHG_VTRKL_STEP_MV 50
752#define PM8921_CHG_VTRKL_SHIFT 4
753#define PM8921_CHG_VTRKL_MASK 0xF0
754static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
755{
756 u8 temp;
757
758 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
759 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
760 pr_err("bad voltage = %dmV asked to set\n", millivolts);
761 return -EINVAL;
762 }
763
764 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
765 temp = temp << PM8921_CHG_VTRKL_SHIFT;
766 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
767 temp);
768}
769
770#define PM8921_CHG_VWEAK_MIN_MV 2100
771#define PM8921_CHG_VWEAK_MAX_MV 3600
772#define PM8921_CHG_VWEAK_STEP_MV 100
773#define PM8921_CHG_VWEAK_MASK 0x0F
774static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
775{
776 u8 temp;
777
778 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
779 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
780 pr_err("bad voltage = %dmV asked to set\n", millivolts);
781 return -EINVAL;
782 }
783
784 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
785 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
786 temp);
787}
788
789#define PM8921_CHG_ITRKL_MIN_MA 50
790#define PM8921_CHG_ITRKL_MAX_MA 200
791#define PM8921_CHG_ITRKL_MASK 0x0F
792#define PM8921_CHG_ITRKL_STEP_MA 10
793static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
794{
795 u8 temp;
796
797 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
798 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
799 pr_err("bad current = %dmA asked to set\n", milliamps);
800 return -EINVAL;
801 }
802
803 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
804
805 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
806 temp);
807}
808
809#define PM8921_CHG_IWEAK_MIN_MA 325
810#define PM8921_CHG_IWEAK_MAX_MA 525
811#define PM8921_CHG_IWEAK_SHIFT 7
812#define PM8921_CHG_IWEAK_MASK 0x80
813static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
814{
815 u8 temp;
816
817 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
818 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
819 pr_err("bad current = %dmA asked to set\n", milliamps);
820 return -EINVAL;
821 }
822
823 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
824 temp = 0;
825 else
826 temp = 1;
827
828 temp = temp << PM8921_CHG_IWEAK_SHIFT;
829 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
830 temp);
831}
832
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700833#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
834#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
835static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
836 enum pm8921_chg_cold_thr cold_thr)
837{
838 u8 temp;
839
840 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
841 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
842 return pm_chg_masked_write(chip, CHG_CNTRL_2,
843 PM8921_CHG_BATT_TEMP_THR_COLD,
844 temp);
845}
846
847#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
848#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
849static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
850 enum pm8921_chg_hot_thr hot_thr)
851{
852 u8 temp;
853
854 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
855 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
856 return pm_chg_masked_write(chip, CHG_CNTRL_2,
857 PM8921_CHG_BATT_TEMP_THR_HOT,
858 temp);
859}
860
Jay Chokshid674a512012-03-15 14:06:04 -0700861#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
862#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
863static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
864 enum pm8921_chg_led_src_config led_src_config)
865{
866 u8 temp;
867
868 if (led_src_config < LED_SRC_GND ||
869 led_src_config > LED_SRC_BYPASS)
870 return -EINVAL;
871
872 if (led_src_config == LED_SRC_BYPASS)
873 return 0;
874
875 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
876
877 return pm_chg_masked_write(chip, CHG_CNTRL_3,
878 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
879}
880
David Keitel8c5201a2012-02-24 16:08:54 -0800881static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
882{
883 u8 temp;
884 int rc;
885
886 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
887 if (rc) {
888 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
889 return;
890 }
891 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
892 if (rc) {
893 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
894 return;
895 }
896 /* set the input voltage disable bit and the write bit */
897 temp |= 0x81;
898 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
899 if (rc) {
900 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
901 return;
902 }
903}
904
905static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
906{
907 u8 temp;
908 int rc;
909
910 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
911 if (rc) {
912 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
913 return;
914 }
915 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
916 if (rc) {
917 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
918 return;
919 }
920 /* unset the input voltage disable bit */
921 temp &= 0xFE;
922 /* set the write bit */
923 temp |= 0x80;
924 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
925 if (rc) {
926 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
927 return;
928 }
929}
930
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700931static int64_t read_battery_id(struct pm8921_chg_chip *chip)
932{
933 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700934 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700935
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700936 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700937 if (rc) {
938 pr_err("error reading batt id channel = %d, rc = %d\n",
939 chip->vbat_channel, rc);
940 return rc;
941 }
942 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
943 result.measurement);
944 return result.physical;
945}
946
947static int is_battery_valid(struct pm8921_chg_chip *chip)
948{
949 int64_t rc;
950
951 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
952 return 1;
953
954 rc = read_battery_id(chip);
955 if (rc < 0) {
956 pr_err("error reading batt id channel = %d, rc = %lld\n",
957 chip->vbat_channel, rc);
958 /* assume battery id is valid when adc error happens */
959 return 1;
960 }
961
962 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
963 pr_err("batt_id phy =%lld is not valid\n", rc);
964 return 0;
965 }
966 return 1;
967}
968
969static void check_battery_valid(struct pm8921_chg_chip *chip)
970{
971 if (is_battery_valid(chip) == 0) {
972 pr_err("batt_id not valid, disbling charging\n");
973 pm_chg_auto_enable(chip, 0);
974 } else {
975 pm_chg_auto_enable(chip, !charging_disabled);
976 }
977}
978
979static void battery_id_valid(struct work_struct *work)
980{
981 struct pm8921_chg_chip *chip = container_of(work,
982 struct pm8921_chg_chip, battery_id_valid_work);
983
984 check_battery_valid(chip);
985}
986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
988{
989 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
990 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
991 enable_irq(chip->pmic_chg_irq[interrupt]);
992 }
993}
994
995static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
996{
997 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
998 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
999 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1000 }
1001}
1002
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001003static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1004{
1005 return test_bit(interrupt, chip->enabled_irqs);
1006}
1007
Amir Samuelovd31ef502011-10-26 14:41:36 +02001008static bool is_ext_charging(struct pm8921_chg_chip *chip)
1009{
David Keitel88e1b572012-01-11 11:57:14 -08001010 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001011
David Keitel88e1b572012-01-11 11:57:14 -08001012 if (!chip->ext_psy)
1013 return false;
1014 if (chip->ext_psy->get_property(chip->ext_psy,
1015 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1016 return false;
1017 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1018 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001019
1020 return false;
1021}
1022
1023static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1024{
David Keitel88e1b572012-01-11 11:57:14 -08001025 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001026
David Keitel88e1b572012-01-11 11:57:14 -08001027 if (!chip->ext_psy)
1028 return false;
1029 if (chip->ext_psy->get_property(chip->ext_psy,
1030 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1031 return false;
1032 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001033 return true;
1034
1035 return false;
1036}
1037
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038static int is_battery_charging(int fsm_state)
1039{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001040 if (is_ext_charging(the_chip))
1041 return 1;
1042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 switch (fsm_state) {
1044 case FSM_STATE_ATC_2A:
1045 case FSM_STATE_ATC_2B:
1046 case FSM_STATE_ON_CHG_AND_BAT_6:
1047 case FSM_STATE_FAST_CHG_7:
1048 case FSM_STATE_TRKL_CHG_8:
1049 return 1;
1050 }
1051 return 0;
1052}
1053
1054static void bms_notify(struct work_struct *work)
1055{
1056 struct bms_notify *n = container_of(work, struct bms_notify, work);
1057
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001058 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001060 } else {
1061 pm8921_bms_charging_end(n->is_battery_full);
1062 n->is_battery_full = 0;
1063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064}
1065
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001066static void bms_notify_check(struct pm8921_chg_chip *chip)
1067{
1068 int fsm_state, new_is_charging;
1069
1070 fsm_state = pm_chg_get_fsm_state(chip);
1071 new_is_charging = is_battery_charging(fsm_state);
1072
1073 if (chip->bms_notify.is_charging ^ new_is_charging) {
1074 chip->bms_notify.is_charging = new_is_charging;
1075 schedule_work(&(chip->bms_notify.work));
1076 }
1077}
1078
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001079static enum power_supply_property pm_power_props_usb[] = {
1080 POWER_SUPPLY_PROP_PRESENT,
1081 POWER_SUPPLY_PROP_ONLINE,
1082 POWER_SUPPLY_PROP_CURRENT_MAX,
1083};
1084
1085static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001087 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088};
1089
1090static char *pm_power_supplied_to[] = {
1091 "battery",
1092};
1093
David Keitel6ed71a52012-01-30 12:42:18 -08001094#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001095static int pm_power_get_property_mains(struct power_supply *psy,
1096 enum power_supply_property psp,
1097 union power_supply_propval *val)
1098{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001099 /* Check if called before init */
1100 if (!the_chip)
1101 return -EINVAL;
1102
1103 switch (psp) {
1104 case POWER_SUPPLY_PROP_PRESENT:
1105 case POWER_SUPPLY_PROP_ONLINE:
1106 val->intval = 0;
1107 if (charging_disabled)
1108 return 0;
1109
1110 /* check external charger first before the dc path */
1111 if (is_ext_charging(the_chip)) {
1112 val->intval = 1;
1113 return 0;
1114 }
1115
1116 if (pm_is_chg_charge_dis(the_chip)) {
1117 val->intval = 0;
1118 return 0;
1119 }
1120
1121 if (the_chip->dc_present) {
1122 val->intval = 1;
1123 return 0;
1124 }
1125
1126 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001127 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001128 val->intval = is_usb_chg_plugged_in(the_chip);
1129 return 0;
1130
1131 break;
1132 default:
1133 return -EINVAL;
1134 }
1135 return 0;
1136}
1137
1138static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 enum power_supply_property psp,
1140 union power_supply_propval *val)
1141{
David Keitel6ed71a52012-01-30 12:42:18 -08001142 int current_max;
1143
1144 /* Check if called before init */
1145 if (!the_chip)
1146 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147
1148 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001149 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001150 if (pm_is_chg_charge_dis(the_chip)) {
1151 val->intval = 0;
1152 } else {
1153 pm_chg_iusbmax_get(the_chip, &current_max);
1154 val->intval = current_max;
1155 }
David Keitel6ed71a52012-01-30 12:42:18 -08001156 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001158 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001159 val->intval = 0;
1160 if (charging_disabled)
1161 return 0;
1162
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001163 /*
1164 * if drawing any current from usb is disabled behave
1165 * as if no usb cable is connected
1166 */
1167 if (pm_is_chg_charge_dis(the_chip))
1168 return 0;
1169
David Keitel63f71662012-02-08 20:30:00 -08001170 /* USB charging */
David Keitel70f6cdc22012-03-15 15:33:26 -07001171 val->intval = is_usb_chg_plugged_in(the_chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 break;
1173 default:
1174 return -EINVAL;
1175 }
1176 return 0;
1177}
1178
1179static enum power_supply_property msm_batt_power_props[] = {
1180 POWER_SUPPLY_PROP_STATUS,
1181 POWER_SUPPLY_PROP_CHARGE_TYPE,
1182 POWER_SUPPLY_PROP_HEALTH,
1183 POWER_SUPPLY_PROP_PRESENT,
1184 POWER_SUPPLY_PROP_TECHNOLOGY,
1185 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1186 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1187 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1188 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001189 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001190 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001191 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192};
1193
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001194static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195{
1196 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001197 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001199 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 if (rc) {
1201 pr_err("error reading adc channel = %d, rc = %d\n",
1202 chip->vbat_channel, rc);
1203 return rc;
1204 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001205 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 result.measurement);
1207 return (int)result.physical;
1208}
1209
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001210static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1211{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001212 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1213 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1214 unsigned int low_voltage = chip->min_voltage_mv;
1215 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001216
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001217 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001218 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001219 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001220 return 100;
1221 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001222 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001223 / (high_voltage - low_voltage);
1224}
1225
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1227{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001228 int percent_soc = pm8921_bms_get_percent_charge();
1229
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001230 if (percent_soc == -ENXIO)
1231 percent_soc = voltage_based_capacity(chip);
1232
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001233 if (percent_soc <= 10)
1234 pr_warn("low battery charge = %d%%\n", percent_soc);
1235
1236 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237}
1238
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001239static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1240{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001241 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001242
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001243 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001244 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001245 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001246 }
1247
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001248 if (rc) {
1249 pr_err("unable to get batt current rc = %d\n", rc);
1250 return rc;
1251 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001252 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001253 }
1254}
1255
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001256static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1257{
1258 int rc;
1259
1260 rc = pm8921_bms_get_fcc();
1261 if (rc < 0)
1262 pr_err("unable to get batt fcc rc = %d\n", rc);
1263 return rc;
1264}
1265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1267{
1268 int temp;
1269
1270 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1271 if (temp)
1272 return POWER_SUPPLY_HEALTH_OVERHEAT;
1273
1274 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1275 if (temp)
1276 return POWER_SUPPLY_HEALTH_COLD;
1277
1278 return POWER_SUPPLY_HEALTH_GOOD;
1279}
1280
1281static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1282{
1283 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1284}
1285
1286static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1287{
1288 int temp;
1289
Amir Samuelovd31ef502011-10-26 14:41:36 +02001290 if (!get_prop_batt_present(chip))
1291 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1292
1293 if (is_ext_trickle_charging(chip))
1294 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1295
1296 if (is_ext_charging(chip))
1297 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1300 if (temp)
1301 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1302
1303 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1304 if (temp)
1305 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1306
1307 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1308}
1309
1310static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1311{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001312 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1313 int fsm_state = pm_chg_get_fsm_state(chip);
1314 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315
David Keitel88e1b572012-01-11 11:57:14 -08001316 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001317 if (chip->ext_charge_done)
1318 return POWER_SUPPLY_STATUS_FULL;
1319 if (chip->ext_charging)
1320 return POWER_SUPPLY_STATUS_CHARGING;
1321 }
1322
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001323 for (i = 0; i < ARRAY_SIZE(map); i++)
1324 if (map[i].fsm_state == fsm_state)
1325 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001326
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001327 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1328 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1329 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001330 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1331 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001332
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001333 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001334 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001335 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336}
1337
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001338#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001339static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1340{
1341 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001342 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001343
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001344 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001345 if (rc) {
1346 pr_err("error reading adc channel = %d, rc = %d\n",
1347 chip->vbat_channel, rc);
1348 return rc;
1349 }
1350 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1351 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001352 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1353 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1354 (int) result.physical);
1355
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001356 return (int)result.physical;
1357}
1358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359static int pm_batt_power_get_property(struct power_supply *psy,
1360 enum power_supply_property psp,
1361 union power_supply_propval *val)
1362{
1363 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1364 batt_psy);
1365
1366 switch (psp) {
1367 case POWER_SUPPLY_PROP_STATUS:
1368 val->intval = get_prop_batt_status(chip);
1369 break;
1370 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1371 val->intval = get_prop_charge_type(chip);
1372 break;
1373 case POWER_SUPPLY_PROP_HEALTH:
1374 val->intval = get_prop_batt_health(chip);
1375 break;
1376 case POWER_SUPPLY_PROP_PRESENT:
1377 val->intval = get_prop_batt_present(chip);
1378 break;
1379 case POWER_SUPPLY_PROP_TECHNOLOGY:
1380 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1381 break;
1382 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001383 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 break;
1385 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001386 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 break;
1388 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001389 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 break;
1391 case POWER_SUPPLY_PROP_CAPACITY:
1392 val->intval = get_prop_batt_capacity(chip);
1393 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001394 case POWER_SUPPLY_PROP_CURRENT_NOW:
1395 val->intval = get_prop_batt_current(chip);
1396 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001397 case POWER_SUPPLY_PROP_TEMP:
1398 val->intval = get_prop_batt_temp(chip);
1399 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001400 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001401 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001402 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 default:
1404 return -EINVAL;
1405 }
1406
1407 return 0;
1408}
1409
1410static void (*notify_vbus_state_func_ptr)(int);
1411static int usb_chg_current;
1412static DEFINE_SPINLOCK(vbus_lock);
1413
1414int pm8921_charger_register_vbus_sn(void (*callback)(int))
1415{
1416 pr_debug("%p\n", callback);
1417 notify_vbus_state_func_ptr = callback;
1418 return 0;
1419}
1420EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1421
1422/* this is passed to the hsusb via platform_data msm_otg_pdata */
1423void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1424{
1425 pr_debug("%p\n", callback);
1426 notify_vbus_state_func_ptr = NULL;
1427}
1428EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1429
1430static void notify_usb_of_the_plugin_event(int plugin)
1431{
1432 plugin = !!plugin;
1433 if (notify_vbus_state_func_ptr) {
1434 pr_debug("notifying plugin\n");
1435 (*notify_vbus_state_func_ptr) (plugin);
1436 } else {
1437 pr_debug("unable to notify plugin\n");
1438 }
1439}
1440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441/* assumes vbus_lock is held */
1442static void __pm8921_charger_vbus_draw(unsigned int mA)
1443{
1444 int i, rc;
1445
1446 if (mA > 0 && mA <= 2) {
1447 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001448 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001450 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 }
1452 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1453 if (rc)
1454 pr_err("fail to set suspend bit rc=%d\n", rc);
1455 } else {
1456 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1457 if (rc)
1458 pr_err("fail to reset suspend bit rc=%d\n", rc);
1459 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1460 if (usb_ma_table[i].usb_ma <= mA)
1461 break;
1462 }
1463 if (i < 0)
1464 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001465 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001467 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 }
1469 }
1470}
1471
1472/* USB calls these to tell us how much max usb current the system can draw */
1473void pm8921_charger_vbus_draw(unsigned int mA)
1474{
1475 unsigned long flags;
1476
1477 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001478
1479 if (usb_max_current && mA > usb_max_current) {
1480 pr_warn("restricting usb current to %d instead of %d\n",
1481 usb_max_current, mA);
1482 mA = usb_max_current;
1483 }
1484 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1485 usb_target_ma = mA;
1486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 spin_lock_irqsave(&vbus_lock, flags);
1488 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001489 if (mA > USB_WALL_THRESHOLD_MA)
1490 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1491 else
1492 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 } else {
1494 /*
1495 * called before pmic initialized,
1496 * save this value and use it at probe
1497 */
David Keitelacf57c82012-03-07 18:48:50 -08001498 if (mA > USB_WALL_THRESHOLD_MA)
1499 usb_chg_current = USB_WALL_THRESHOLD_MA;
1500 else
1501 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 }
1503 spin_unlock_irqrestore(&vbus_lock, flags);
1504}
1505EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1506
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001507int pm8921_charger_enable(bool enable)
1508{
1509 int rc;
1510
1511 if (!the_chip) {
1512 pr_err("called before init\n");
1513 return -EINVAL;
1514 }
1515 enable = !!enable;
1516 rc = pm_chg_auto_enable(the_chip, enable);
1517 if (rc)
1518 pr_err("Failed rc=%d\n", rc);
1519 return rc;
1520}
1521EXPORT_SYMBOL(pm8921_charger_enable);
1522
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001523int pm8921_is_usb_chg_plugged_in(void)
1524{
1525 if (!the_chip) {
1526 pr_err("called before init\n");
1527 return -EINVAL;
1528 }
1529 return is_usb_chg_plugged_in(the_chip);
1530}
1531EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1532
1533int pm8921_is_dc_chg_plugged_in(void)
1534{
1535 if (!the_chip) {
1536 pr_err("called before init\n");
1537 return -EINVAL;
1538 }
1539 return is_dc_chg_plugged_in(the_chip);
1540}
1541EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1542
1543int pm8921_is_battery_present(void)
1544{
1545 if (!the_chip) {
1546 pr_err("called before init\n");
1547 return -EINVAL;
1548 }
1549 return get_prop_batt_present(the_chip);
1550}
1551EXPORT_SYMBOL(pm8921_is_battery_present);
1552
David Keitel012deef2011-12-02 11:49:33 -08001553/*
1554 * Disabling the charge current limit causes current
1555 * current limits to have no monitoring. An adequate charger
1556 * capable of supplying high current while sustaining VIN_MIN
1557 * is required if the limiting is disabled.
1558 */
1559int pm8921_disable_input_current_limit(bool disable)
1560{
1561 if (!the_chip) {
1562 pr_err("called before init\n");
1563 return -EINVAL;
1564 }
1565 if (disable) {
1566 pr_warn("Disabling input current limit!\n");
1567
1568 return pm8xxx_writeb(the_chip->dev->parent,
1569 CHG_BUCK_CTRL_TEST3, 0xF2);
1570 }
1571 return 0;
1572}
1573EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1574
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001575int pm8921_set_max_battery_charge_current(int ma)
1576{
1577 if (!the_chip) {
1578 pr_err("called before init\n");
1579 return -EINVAL;
1580 }
1581 return pm_chg_ibatmax_set(the_chip, ma);
1582}
1583EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1584
1585int pm8921_disable_source_current(bool disable)
1586{
1587 if (!the_chip) {
1588 pr_err("called before init\n");
1589 return -EINVAL;
1590 }
1591 if (disable)
1592 pr_warn("current drawn from chg=0, battery provides current\n");
1593 return pm_chg_charge_dis(the_chip, disable);
1594}
1595EXPORT_SYMBOL(pm8921_disable_source_current);
1596
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001597int pm8921_regulate_input_voltage(int voltage)
1598{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001599 int rc;
1600
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001601 if (!the_chip) {
1602 pr_err("called before init\n");
1603 return -EINVAL;
1604 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001605 rc = pm_chg_vinmin_set(the_chip, voltage);
1606
1607 if (rc == 0)
1608 the_chip->vin_min = voltage;
1609
1610 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001611}
1612
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001613#define USB_OV_THRESHOLD_MASK 0x60
1614#define USB_OV_THRESHOLD_SHIFT 5
1615int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1616{
1617 u8 temp;
1618
1619 if (!the_chip) {
1620 pr_err("called before init\n");
1621 return -EINVAL;
1622 }
1623
1624 if (ov > PM_USB_OV_7V) {
1625 pr_err("limiting to over voltage threshold to 7volts\n");
1626 ov = PM_USB_OV_7V;
1627 }
1628
1629 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1630
1631 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1632 USB_OV_THRESHOLD_MASK, temp);
1633}
1634EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1635
1636#define USB_DEBOUNCE_TIME_MASK 0x06
1637#define USB_DEBOUNCE_TIME_SHIFT 1
1638int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1639{
1640 u8 temp;
1641
1642 if (!the_chip) {
1643 pr_err("called before init\n");
1644 return -EINVAL;
1645 }
1646
1647 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1648 pr_err("limiting debounce to 80.5ms\n");
1649 ms = PM_USB_DEBOUNCE_80P5MS;
1650 }
1651
1652 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1653
1654 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1655 USB_DEBOUNCE_TIME_MASK, temp);
1656}
1657EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1658
1659#define USB_OVP_DISABLE_MASK 0x80
1660int pm8921_usb_ovp_disable(int disable)
1661{
1662 u8 temp = 0;
1663
1664 if (!the_chip) {
1665 pr_err("called before init\n");
1666 return -EINVAL;
1667 }
1668
1669 if (disable)
1670 temp = USB_OVP_DISABLE_MASK;
1671
1672 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1673 USB_OVP_DISABLE_MASK, temp);
1674}
1675
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001676bool pm8921_is_battery_charging(int *source)
1677{
1678 int fsm_state, is_charging, dc_present, usb_present;
1679
1680 if (!the_chip) {
1681 pr_err("called before init\n");
1682 return -EINVAL;
1683 }
1684 fsm_state = pm_chg_get_fsm_state(the_chip);
1685 is_charging = is_battery_charging(fsm_state);
1686 if (is_charging == 0) {
1687 *source = PM8921_CHG_SRC_NONE;
1688 return is_charging;
1689 }
1690
1691 if (source == NULL)
1692 return is_charging;
1693
1694 /* the battery is charging, the source is requested, find it */
1695 dc_present = is_dc_chg_plugged_in(the_chip);
1696 usb_present = is_usb_chg_plugged_in(the_chip);
1697
1698 if (dc_present && !usb_present)
1699 *source = PM8921_CHG_SRC_DC;
1700
1701 if (usb_present && !dc_present)
1702 *source = PM8921_CHG_SRC_USB;
1703
1704 if (usb_present && dc_present)
1705 /*
1706 * The system always chooses dc for charging since it has
1707 * higher priority.
1708 */
1709 *source = PM8921_CHG_SRC_DC;
1710
1711 return is_charging;
1712}
1713EXPORT_SYMBOL(pm8921_is_battery_charging);
1714
1715int pm8921_batt_temperature(void)
1716{
1717 if (!the_chip) {
1718 pr_err("called before init\n");
1719 return -EINVAL;
1720 }
1721 return get_prop_batt_temp(the_chip);
1722}
1723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1725{
1726 int usb_present;
1727
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001728 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 usb_present = is_usb_chg_plugged_in(chip);
1730 if (chip->usb_present ^ usb_present) {
1731 notify_usb_of_the_plugin_event(usb_present);
1732 chip->usb_present = usb_present;
1733 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001734 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001735 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001737 if (usb_present) {
1738 schedule_delayed_work(&chip->unplug_check_work,
1739 round_jiffies_relative(msecs_to_jiffies
1740 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001741 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1742 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001743 /* USB unplugged reset target current */
1744 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001745 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001746 }
David Keitel8c5201a2012-02-24 16:08:54 -08001747 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001748 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749}
1750
Amir Samuelovd31ef502011-10-26 14:41:36 +02001751static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1752{
David Keitel88e1b572012-01-11 11:57:14 -08001753 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001754 pr_debug("external charger not registered.\n");
1755 return;
1756 }
1757
1758 if (!chip->ext_charging) {
1759 pr_debug("already not charging.\n");
1760 return;
1761 }
1762
David Keitel88e1b572012-01-11 11:57:14 -08001763 power_supply_set_charge_type(chip->ext_psy,
1764 POWER_SUPPLY_CHARGE_TYPE_NONE);
1765 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001766 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001767 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001768 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001769 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001770}
1771
1772static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1773{
1774 int dc_present;
1775 int batt_present;
1776 int batt_temp_ok;
1777 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001778 unsigned long delay =
1779 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1780
David Keitel88e1b572012-01-11 11:57:14 -08001781 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001782 pr_debug("external charger not registered.\n");
1783 return;
1784 }
1785
1786 if (chip->ext_charging) {
1787 pr_debug("already charging.\n");
1788 return;
1789 }
1790
David Keitel88e1b572012-01-11 11:57:14 -08001791 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001792 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1793 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001794
1795 if (!dc_present) {
1796 pr_warn("%s. dc not present.\n", __func__);
1797 return;
1798 }
1799 if (!batt_present) {
1800 pr_warn("%s. battery not present.\n", __func__);
1801 return;
1802 }
1803 if (!batt_temp_ok) {
1804 pr_warn("%s. battery temperature not ok.\n", __func__);
1805 return;
1806 }
David Keitel88e1b572012-01-11 11:57:14 -08001807 pm8921_disable_source_current(true); /* Force BATFET=ON */
1808 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001809 if (vbat_ov) {
1810 pr_warn("%s. battery over voltage.\n", __func__);
1811 return;
1812 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001813
David Keitel63f71662012-02-08 20:30:00 -08001814 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001815 power_supply_set_charge_type(chip->ext_psy,
1816 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001817 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001818 chip->ext_charging = true;
1819 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001820 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001821 /* Start BMS */
1822 schedule_delayed_work(&chip->eoc_work, delay);
1823 wake_lock(&chip->eoc_wake_lock);
1824}
1825
David Keitel8c5201a2012-02-24 16:08:54 -08001826static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001827{
1828 u8 temp;
1829 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001830
David Keitel8c5201a2012-02-24 16:08:54 -08001831 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001832 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001833 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1834 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001835 }
David Keitel8c5201a2012-02-24 16:08:54 -08001836 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1837 if (rc) {
1838 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1839 return;
1840 }
1841 /* set ovp fet disable bit and the write bit */
1842 temp |= 0x81;
1843 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1844 if (rc) {
1845 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1846 return;
1847 }
1848}
1849
1850static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1851{
1852 u8 temp;
1853 int rc;
1854
1855 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1856 if (rc) {
1857 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1858 return;
1859 }
1860 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1861 if (rc) {
1862 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1863 return;
1864 }
1865 /* unset ovp fet disable bit and set the write bit */
1866 temp &= 0xFE;
1867 temp |= 0x80;
1868 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1869 if (rc) {
1870 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1871 temp, rc);
1872 return;
1873 }
1874}
1875
1876static int param_open_ovp_counter = 10;
1877module_param(param_open_ovp_counter, int, 0644);
1878
1879#define WRITE_BANK_4 0xC0
1880#define USB_OVP_DEBOUNCE_TIME 0x06
1881static void unplug_ovp_fet_open_worker(struct work_struct *work)
1882{
1883 struct pm8921_chg_chip *chip = container_of(work,
1884 struct pm8921_chg_chip,
1885 unplug_ovp_fet_open_work);
1886 int chg_gone, usb_chg_plugged_in;
1887 int count = 0;
1888
1889 while (count++ < param_open_ovp_counter) {
1890 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1891 USB_OVP_DEBOUNCE_TIME, 0x0);
1892 usleep(10);
1893 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1894 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1895 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1896 count, chg_gone, usb_chg_plugged_in);
1897
1898 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1899 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1900 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1901 turn_off_usb_ovp_fet(chip);
1902
1903 msleep(20);
1904
1905 turn_on_usb_ovp_fet(chip);
1906 } else {
David Keitel712782e2012-03-29 14:11:47 -07001907 break;
David Keitel8c5201a2012-02-24 16:08:54 -08001908 }
1909 }
David Keitel712782e2012-03-29 14:11:47 -07001910 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1911 USB_OVP_DEBOUNCE_TIME, 0x2);
1912 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1913 count, chg_gone, usb_chg_plugged_in);
1914 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001915}
David Keitelacf57c82012-03-07 18:48:50 -08001916
1917static int find_usb_ma_value(int value)
1918{
1919 int i;
1920
1921 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1922 if (value >= usb_ma_table[i].usb_ma)
1923 break;
1924 }
1925
1926 return i;
1927}
1928
1929static void decrease_usb_ma_value(int *value)
1930{
1931 int i;
1932
1933 if (value) {
1934 i = find_usb_ma_value(*value);
1935 if (i > 0)
1936 i--;
1937 *value = usb_ma_table[i].usb_ma;
1938 }
1939}
1940
1941static void increase_usb_ma_value(int *value)
1942{
1943 int i;
1944
1945 if (value) {
1946 i = find_usb_ma_value(*value);
1947
1948 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
1949 i++;
1950 *value = usb_ma_table[i].usb_ma;
1951 }
1952}
1953
1954static void vin_collapse_check_worker(struct work_struct *work)
1955{
1956 struct delayed_work *dwork = to_delayed_work(work);
1957 struct pm8921_chg_chip *chip = container_of(dwork,
1958 struct pm8921_chg_chip, vin_collapse_check_work);
1959
1960 /* AICL only for wall-chargers */
1961 if (is_usb_chg_plugged_in(chip) &&
1962 usb_target_ma > USB_WALL_THRESHOLD_MA) {
1963 /* decrease usb_target_ma */
1964 decrease_usb_ma_value(&usb_target_ma);
1965 /* reset here, increase in unplug_check_worker */
1966 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1967 pr_debug("usb_now=%d, usb_target = %d\n",
1968 USB_WALL_THRESHOLD_MA, usb_target_ma);
1969 } else {
1970 handle_usb_insertion_removal(chip);
1971 }
1972}
1973
1974#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1976{
David Keitelacf57c82012-03-07 18:48:50 -08001977 if (usb_target_ma)
1978 schedule_delayed_work(&the_chip->vin_collapse_check_work,
1979 round_jiffies_relative(msecs_to_jiffies
1980 (VIN_MIN_COLLAPSE_CHECK_MS)));
1981 else
1982 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 return IRQ_HANDLED;
1984}
1985
1986static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1987{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001988 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989 return IRQ_HANDLED;
1990}
1991
1992static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1993{
1994 struct pm8921_chg_chip *chip = data;
1995 int status;
1996
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001997 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1998 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001999 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 pr_debug("battery present=%d", status);
2001 power_supply_changed(&chip->batt_psy);
2002 return IRQ_HANDLED;
2003}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002004
2005/*
2006 * this interrupt used to restart charging a battery.
2007 *
2008 * Note: When DC-inserted the VBAT can't go low.
2009 * VPH_PWR is provided by the ext-charger.
2010 * After End-Of-Charging from DC, charging can be resumed only
2011 * if DC is removed and then inserted after the battery was in use.
2012 * Therefore the handle_start_ext_chg() is not called.
2013 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002014static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2015{
2016 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002017 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002019 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002020
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002021 if (high_transition) {
2022 /* enable auto charging */
2023 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002024 pr_info("batt fell below resume voltage %s\n",
2025 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002026 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 power_supply_changed(&chip->batt_psy);
2030 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002031 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 return IRQ_HANDLED;
2034}
2035
2036static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2037{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002038 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039 return IRQ_HANDLED;
2040}
2041
2042static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2043{
2044 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2045 return IRQ_HANDLED;
2046}
2047
2048static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2049{
2050 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2051 return IRQ_HANDLED;
2052}
2053
2054static irqreturn_t vcp_irq_handler(int irq, void *data)
2055{
David Keitel8c5201a2012-02-24 16:08:54 -08002056 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 return IRQ_HANDLED;
2058}
2059
2060static irqreturn_t atcdone_irq_handler(int irq, void *data)
2061{
2062 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2063 return IRQ_HANDLED;
2064}
2065
2066static irqreturn_t atcfail_irq_handler(int irq, void *data)
2067{
2068 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2069 return IRQ_HANDLED;
2070}
2071
2072static irqreturn_t chgdone_irq_handler(int irq, void *data)
2073{
2074 struct pm8921_chg_chip *chip = data;
2075
2076 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002077
2078 handle_stop_ext_chg(chip);
2079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080 power_supply_changed(&chip->batt_psy);
2081 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002082 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002083
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002084 bms_notify_check(chip);
2085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002086 return IRQ_HANDLED;
2087}
2088
2089static irqreturn_t chgfail_irq_handler(int irq, void *data)
2090{
2091 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002092 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093
David Keitel753ec8d2011-11-02 10:56:37 -07002094 ret = pm_chg_failed_clear(chip, 1);
2095 if (ret)
2096 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2097
2098 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2099 get_prop_batt_present(chip),
2100 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2101 pm_chg_get_fsm_state(data));
2102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 power_supply_changed(&chip->batt_psy);
2104 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002105 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106 return IRQ_HANDLED;
2107}
2108
2109static irqreturn_t chgstate_irq_handler(int irq, void *data)
2110{
2111 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112
2113 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2114 power_supply_changed(&chip->batt_psy);
2115 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002116 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002118 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 return IRQ_HANDLED;
2121}
2122
David Keitel8c5201a2012-02-24 16:08:54 -08002123static int param_vin_disable_counter = 5;
2124module_param(param_vin_disable_counter, int, 0644);
2125
2126static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2127 int count, int usb_ma)
2128{
David Keitelacf57c82012-03-07 18:48:50 -08002129 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002130 pr_debug("count = %d iusb=500mA\n", count);
2131 disable_input_voltage_regulation(chip);
2132 pr_debug("count = %d disable_input_regulation\n", count);
2133
2134 msleep(20);
2135
2136 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2137 count,
2138 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2139 is_usb_chg_plugged_in(chip));
2140 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2141 count, usb_ma);
2142 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002143 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002144}
2145
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002146#define VIN_ACTIVE_BIT BIT(0)
2147#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2148#define VIN_MIN_INCREASE_MV 100
2149static void unplug_check_worker(struct work_struct *work)
2150{
2151 struct delayed_work *dwork = to_delayed_work(work);
2152 struct pm8921_chg_chip *chip = container_of(dwork,
2153 struct pm8921_chg_chip, unplug_check_work);
2154 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002155 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002156 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002157
David Keitelacf57c82012-03-07 18:48:50 -08002158 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002159 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2160 if (!usb_chg_plugged_in) {
2161 pr_debug("Stopping Unplug Check Worker since USB is removed"
2162 "reg_loop = %d, fsm = %d ibat = %d\n",
2163 pm_chg_get_regulation_loop(chip),
2164 pm_chg_get_fsm_state(chip),
2165 get_prop_batt_current(chip)
2166 );
2167 return;
2168 }
David Keitel8c5201a2012-02-24 16:08:54 -08002169
2170 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002171 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002172 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2173 disable_input_voltage_regulation(chip);
2174 return;
2175 }
2176
2177 if (usb_ma <= 100) {
2178 pr_debug(
2179 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2180 usb_ma);
2181 goto check_again_later;
2182 }
2183 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2184 pr_debug("chg gone irq is enabled\n");
2185
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002186 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002187 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002188
2189 if (reg_loop & VIN_ACTIVE_BIT) {
David Keitelacf57c82012-03-07 18:48:50 -08002190 decrease_usb_ma_value(&usb_ma);
2191 usb_target_ma = usb_ma;
2192 /* end AICL here */
2193 __pm8921_charger_vbus_draw(usb_ma);
2194 pr_debug("usb_now=%d, usb_target = %d\n",
2195 usb_ma, usb_target_ma);
2196 }
2197
2198 reg_loop = pm_chg_get_regulation_loop(chip);
2199 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2200
2201 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002202 ibat = get_prop_batt_current(chip);
2203
2204 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2205 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2206 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002207 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002208
David Keitel8c5201a2012-02-24 16:08:54 -08002209 while (count++ < param_vin_disable_counter
2210 && usb_chg_plugged_in == 1) {
2211 attempt_reverse_boost_fix(chip, count, usb_ma);
2212 usb_chg_plugged_in
2213 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002214 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002215 }
2216 }
2217
David Keitel8c5201a2012-02-24 16:08:54 -08002218 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2219 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2220
2221 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2222 /* run the worker directly */
2223 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2224 chg_gone, usb_chg_plugged_in);
2225 schedule_work(&chip->unplug_ovp_fet_open_work);
2226 }
2227
David Keitelacf57c82012-03-07 18:48:50 -08002228 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2229 /* only increase iusb_max if vin loop not active */
2230 if (usb_ma < usb_target_ma) {
2231 increase_usb_ma_value(&usb_ma);
2232 __pm8921_charger_vbus_draw(usb_ma);
2233 pr_debug("usb_now=%d, usb_target = %d\n",
2234 usb_ma, usb_target_ma);
2235 } else {
2236 usb_target_ma = usb_ma;
2237 }
2238 }
David Keitel8c5201a2012-02-24 16:08:54 -08002239check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002240 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002241 schedule_delayed_work(&chip->unplug_check_work,
2242 round_jiffies_relative(msecs_to_jiffies
2243 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2244}
2245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246static irqreturn_t loop_change_irq_handler(int irq, void *data)
2247{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002248 struct pm8921_chg_chip *chip = data;
2249
2250 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2251 pm_chg_get_fsm_state(data),
2252 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002253 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 return IRQ_HANDLED;
2255}
2256
2257static irqreturn_t fastchg_irq_handler(int irq, void *data)
2258{
2259 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002260 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002262 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2263 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2264 wake_lock(&chip->eoc_wake_lock);
2265 schedule_delayed_work(&chip->eoc_work,
2266 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002267 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002268 }
2269 power_supply_changed(&chip->batt_psy);
2270 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 return IRQ_HANDLED;
2272}
2273
2274static irqreturn_t trklchg_irq_handler(int irq, void *data)
2275{
2276 struct pm8921_chg_chip *chip = data;
2277
2278 power_supply_changed(&chip->batt_psy);
2279 return IRQ_HANDLED;
2280}
2281
2282static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2283{
2284 struct pm8921_chg_chip *chip = data;
2285 int status;
2286
2287 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2288 pr_debug("battery present=%d state=%d", !status,
2289 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002290 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 power_supply_changed(&chip->batt_psy);
2292 return IRQ_HANDLED;
2293}
2294
2295static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2296{
2297 struct pm8921_chg_chip *chip = data;
2298
Amir Samuelovd31ef502011-10-26 14:41:36 +02002299 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 power_supply_changed(&chip->batt_psy);
2301 return IRQ_HANDLED;
2302}
2303
2304static irqreturn_t chghot_irq_handler(int irq, void *data)
2305{
2306 struct pm8921_chg_chip *chip = data;
2307
2308 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2309 power_supply_changed(&chip->batt_psy);
2310 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002311 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312 return IRQ_HANDLED;
2313}
2314
2315static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2316{
2317 struct pm8921_chg_chip *chip = data;
2318
2319 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002320 handle_stop_ext_chg(chip);
2321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 power_supply_changed(&chip->batt_psy);
2323 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 return IRQ_HANDLED;
2325}
2326
2327static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2328{
2329 struct pm8921_chg_chip *chip = data;
David Keitel0873d0f2012-03-29 11:44:49 -07002330 u8 reg;
2331 int rc, chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002332
2333 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2334 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2335
2336 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002337 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2338
2339 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL_3, &reg);
2340 if (rc)
2341 pr_err("Failed to read CHG_CNTRL_3 rc=%d\n", rc);
2342
2343 if (reg & CHG_USB_SUSPEND_BIT)
2344 return IRQ_HANDLED;
David Keitel8c5201a2012-02-24 16:08:54 -08002345 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346
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}
David Keitel52fda532011-11-10 10:43:44 -08002351/*
2352 *
2353 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2354 * fire for two cases:
2355 *
2356 * If the interrupt line switches to high temperature is okay
2357 * and thus charging begins.
2358 * If bat_temp_ok is low this means the temperature is now
2359 * too hot or cold, so charging is stopped.
2360 *
2361 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2363{
David Keitel52fda532011-11-10 10:43:44 -08002364 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002365 struct pm8921_chg_chip *chip = data;
2366
David Keitel52fda532011-11-10 10:43:44 -08002367 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2368
2369 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2370 bat_temp_ok, pm_chg_get_fsm_state(data));
2371
2372 if (bat_temp_ok)
2373 handle_start_ext_chg(chip);
2374 else
2375 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377 power_supply_changed(&chip->batt_psy);
2378 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002379 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380 return IRQ_HANDLED;
2381}
2382
2383static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2384{
2385 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2386 return IRQ_HANDLED;
2387}
2388
2389static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2390{
2391 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2392 return IRQ_HANDLED;
2393}
2394
2395static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2396{
2397 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2398 return IRQ_HANDLED;
2399}
2400
2401static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2402{
2403 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2404 return IRQ_HANDLED;
2405}
2406
2407static irqreturn_t batfet_irq_handler(int irq, void *data)
2408{
2409 struct pm8921_chg_chip *chip = data;
2410
2411 pr_debug("vreg ov\n");
2412 power_supply_changed(&chip->batt_psy);
2413 return IRQ_HANDLED;
2414}
2415
2416static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2417{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002418 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002419 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002420
David Keitel88e1b572012-01-11 11:57:14 -08002421 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2422 if (chip->ext_psy)
2423 power_supply_set_online(chip->ext_psy, dc_present);
2424 chip->dc_present = dc_present;
2425 if (dc_present)
2426 handle_start_ext_chg(chip);
2427 else
2428 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429 return IRQ_HANDLED;
2430}
2431
2432static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2433{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002434 struct pm8921_chg_chip *chip = data;
2435
Amir Samuelovd31ef502011-10-26 14:41:36 +02002436 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002437 return IRQ_HANDLED;
2438}
2439
2440static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2441{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002442 struct pm8921_chg_chip *chip = data;
2443
Amir Samuelovd31ef502011-10-26 14:41:36 +02002444 handle_stop_ext_chg(chip);
2445
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446 return IRQ_HANDLED;
2447}
2448
David Keitel88e1b572012-01-11 11:57:14 -08002449static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2450{
2451 struct power_supply *psy = &the_chip->batt_psy;
2452 struct power_supply *epsy = dev_get_drvdata(dev);
2453 int i, dcin_irq;
2454
2455 /* Only search for external supply if none is registered */
2456 if (!the_chip->ext_psy) {
2457 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2458 for (i = 0; i < epsy->num_supplicants; i++) {
2459 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2460 if (!strncmp(epsy->name, "dc", 2)) {
2461 the_chip->ext_psy = epsy;
2462 dcin_valid_irq_handler(dcin_irq,
2463 the_chip);
2464 }
2465 }
2466 }
2467 }
2468 return 0;
2469}
2470
2471static void pm_batt_external_power_changed(struct power_supply *psy)
2472{
2473 /* Only look for an external supply if it hasn't been registered */
2474 if (!the_chip->ext_psy)
2475 class_for_each_device(power_supply_class, NULL, psy,
2476 __pm_batt_external_power_changed_work);
2477}
2478
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002479/**
2480 * update_heartbeat - internal function to update userspace
2481 * per update_time minutes
2482 *
2483 */
2484static void update_heartbeat(struct work_struct *work)
2485{
2486 struct delayed_work *dwork = to_delayed_work(work);
2487 struct pm8921_chg_chip *chip = container_of(dwork,
2488 struct pm8921_chg_chip, update_heartbeat_work);
2489
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002490 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002491 power_supply_changed(&chip->batt_psy);
2492 schedule_delayed_work(&chip->update_heartbeat_work,
2493 round_jiffies_relative(msecs_to_jiffies
2494 (chip->update_time)));
2495}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002496#define VDD_LOOP_ACTIVE_BIT BIT(3)
2497#define VDD_MAX_INCREASE_MV 400
2498static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2499module_param(vdd_max_increase_mv, int, 0644);
2500
2501static int ichg_threshold_ua = -400000;
2502module_param(ichg_threshold_ua, int, 0644);
2503static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2504{
2505 int ichg_meas_ua, vbat_uv;
2506 int ichg_meas_ma;
2507 int adj_vdd_max_mv, programmed_vdd_max;
2508 int vbat_batt_terminal_uv;
2509 int vbat_batt_terminal_mv;
2510 int reg_loop;
2511 int delta_mv = 0;
2512
2513 if (chip->rconn_mohm == 0) {
2514 pr_debug("Exiting as rconn_mohm is 0\n");
2515 return;
2516 }
2517 /* adjust vdd_max only in normal temperature zone */
2518 if (chip->is_bat_cool || chip->is_bat_warm) {
2519 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2520 chip->is_bat_cool, chip->is_bat_warm);
2521 return;
2522 }
2523
2524 reg_loop = pm_chg_get_regulation_loop(chip);
2525 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2526 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2527 reg_loop);
2528 return;
2529 }
2530
2531 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2532 &vbat_uv);
2533 if (ichg_meas_ua >= 0) {
2534 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2535 return;
2536 }
2537 if (ichg_meas_ua <= ichg_threshold_ua) {
2538 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2539 ichg_meas_ua, ichg_threshold_ua);
2540 return;
2541 }
2542 ichg_meas_ma = ichg_meas_ua / 1000;
2543
2544 /* rconn_mohm is in milliOhms */
2545 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2546 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2547 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2548
2549 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2550
2551 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2552 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2553 delta_mv,
2554 programmed_vdd_max,
2555 adj_vdd_max_mv);
2556
2557 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2558 pr_debug("adj vdd_max lower than default max voltage\n");
2559 return;
2560 }
2561
2562 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2563 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2564
2565 pr_debug("adjusting vdd_max_mv to %d to make "
2566 "vbat_batt_termial_uv = %d to %d\n",
2567 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2568 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2569}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002570
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002571enum {
2572 CHG_IN_PROGRESS,
2573 CHG_NOT_IN_PROGRESS,
2574 CHG_FINISHED,
2575};
2576
2577#define VBAT_TOLERANCE_MV 70
2578#define CHG_DISABLE_MSLEEP 100
2579static int is_charging_finished(struct pm8921_chg_chip *chip)
2580{
2581 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2582 int ichg_meas_ma, iterm_programmed;
2583 int regulation_loop, fast_chg, vcp;
2584 int rc;
2585 static int last_vbat_programmed = -EINVAL;
2586
2587 if (!is_ext_charging(chip)) {
2588 /* return if the battery is not being fastcharged */
2589 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2590 pr_debug("fast_chg = %d\n", fast_chg);
2591 if (fast_chg == 0)
2592 return CHG_NOT_IN_PROGRESS;
2593
2594 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2595 pr_debug("vcp = %d\n", vcp);
2596 if (vcp == 1)
2597 return CHG_IN_PROGRESS;
2598
2599 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2600 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2601 if (vbatdet_low == 1)
2602 return CHG_IN_PROGRESS;
2603
2604 /* reset count if battery is hot/cold */
2605 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2606 pr_debug("batt_temp_ok = %d\n", rc);
2607 if (rc == 0)
2608 return CHG_IN_PROGRESS;
2609
2610 /* reset count if battery voltage is less than vddmax */
2611 vbat_meas_uv = get_prop_battery_uvolts(chip);
2612 if (vbat_meas_uv < 0)
2613 return CHG_IN_PROGRESS;
2614 vbat_meas_mv = vbat_meas_uv / 1000;
2615
2616 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2617 if (rc) {
2618 pr_err("couldnt read vddmax rc = %d\n", rc);
2619 return CHG_IN_PROGRESS;
2620 }
2621 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2622 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002623
2624 if (last_vbat_programmed == -EINVAL)
2625 last_vbat_programmed = vbat_programmed;
2626 if (last_vbat_programmed != vbat_programmed) {
2627 /* vddmax changed, reset and check again */
2628 pr_debug("vddmax = %d last_vdd_max=%d\n",
2629 vbat_programmed, last_vbat_programmed);
2630 last_vbat_programmed = vbat_programmed;
2631 return CHG_IN_PROGRESS;
2632 }
2633
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002634 regulation_loop = pm_chg_get_regulation_loop(chip);
2635 if (regulation_loop < 0) {
2636 pr_err("couldnt read the regulation loop err=%d\n",
2637 regulation_loop);
2638 return CHG_IN_PROGRESS;
2639 }
2640 pr_debug("regulation_loop=%d\n", regulation_loop);
2641
2642 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2643 return CHG_IN_PROGRESS;
2644 } /* !is_ext_charging */
2645
2646 /* reset count if battery chg current is more than iterm */
2647 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2648 if (rc) {
2649 pr_err("couldnt read iterm rc = %d\n", rc);
2650 return CHG_IN_PROGRESS;
2651 }
2652
2653 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2654 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2655 iterm_programmed, ichg_meas_ma);
2656 /*
2657 * ichg_meas_ma < 0 means battery is drawing current
2658 * ichg_meas_ma > 0 means battery is providing current
2659 */
2660 if (ichg_meas_ma > 0)
2661 return CHG_IN_PROGRESS;
2662
2663 if (ichg_meas_ma * -1 > iterm_programmed)
2664 return CHG_IN_PROGRESS;
2665
2666 return CHG_FINISHED;
2667}
2668
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002669/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002670 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002671 * has happened
2672 *
2673 * If all conditions favouring, if the charge current is
2674 * less than the term current for three consecutive times
2675 * an EOC has happened.
2676 * The wakelock is released if there is no need to reshedule
2677 * - this happens when the battery is removed or EOC has
2678 * happened
2679 */
2680#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002681static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002682{
2683 struct delayed_work *dwork = to_delayed_work(work);
2684 struct pm8921_chg_chip *chip = container_of(dwork,
2685 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002686 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002687 int end;
2688
2689 pm_chg_failed_clear(chip, 1);
2690 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002691
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002692 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002693 count = 0;
2694 wake_unlock(&chip->eoc_wake_lock);
2695 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002696 }
2697
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002698 if (end == CHG_FINISHED) {
2699 count++;
2700 } else {
2701 count = 0;
2702 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002703
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002704 if (count == CONSECUTIVE_COUNT) {
2705 count = 0;
2706 pr_info("End of Charging\n");
2707
2708 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002709
Amir Samuelovd31ef502011-10-26 14:41:36 +02002710 if (is_ext_charging(chip))
2711 chip->ext_charge_done = true;
2712
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002713 if (chip->is_bat_warm || chip->is_bat_cool)
2714 chip->bms_notify.is_battery_full = 0;
2715 else
2716 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002717 /* declare end of charging by invoking chgdone interrupt */
2718 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2719 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002720 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002721 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002722 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002723 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002724 round_jiffies_relative(msecs_to_jiffies
2725 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002726 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002727}
2728
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002729static void btm_configure_work(struct work_struct *work)
2730{
2731 int rc;
2732
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002733 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002734 if (rc)
2735 pr_err("failed to configure btm rc=%d", rc);
2736}
2737
2738DECLARE_WORK(btm_config_work, btm_configure_work);
2739
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002740static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2741{
2742 unsigned int chg_current = chip->max_bat_chg_current;
2743
2744 if (chip->is_bat_cool)
2745 chg_current = min(chg_current, chip->cool_bat_chg_current);
2746
2747 if (chip->is_bat_warm)
2748 chg_current = min(chg_current, chip->warm_bat_chg_current);
2749
David Keitelfdef3a42011-12-14 19:02:54 -08002750 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002751 chg_current = min(chg_current,
2752 chip->thermal_mitigation[thermal_mitigation]);
2753
2754 pm_chg_ibatmax_set(the_chip, chg_current);
2755}
2756
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002757#define TEMP_HYSTERISIS_DEGC 2
2758static void battery_cool(bool enter)
2759{
2760 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002761 if (enter == the_chip->is_bat_cool)
2762 return;
2763 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002764 if (enter) {
2765 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002766 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002767 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002768 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002769 pm_chg_vbatdet_set(the_chip,
2770 the_chip->cool_bat_voltage
2771 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002772 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002773 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002774 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002775 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002776 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002777 the_chip->max_voltage_mv
2778 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002779 }
2780 schedule_work(&btm_config_work);
2781}
2782
2783static void battery_warm(bool enter)
2784{
2785 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002786 if (enter == the_chip->is_bat_warm)
2787 return;
2788 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002789 if (enter) {
2790 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002791 the_chip->warm_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->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002794 pm_chg_vbatdet_set(the_chip,
2795 the_chip->warm_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.high_thr_temp = the_chip->warm_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 int configure_btm(struct pm8921_chg_chip *chip)
2809{
2810 int rc;
2811
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002812 if (chip->warm_temp_dc != INT_MIN)
2813 btm_config.btm_warm_fn = battery_warm;
2814 else
2815 btm_config.btm_warm_fn = NULL;
2816
2817 if (chip->cool_temp_dc != INT_MIN)
2818 btm_config.btm_cool_fn = battery_cool;
2819 else
2820 btm_config.btm_cool_fn = NULL;
2821
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002822 btm_config.low_thr_temp = chip->cool_temp_dc;
2823 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002824 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002825 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002826 if (rc)
2827 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002828 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002829 if (rc)
2830 pr_err("failed to start btm rc = %d\n", rc);
2831
2832 return rc;
2833}
2834
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002835/**
2836 * set_disable_status_param -
2837 *
2838 * Internal function to disable battery charging and also disable drawing
2839 * any current from the source. The device is forced to run on a battery
2840 * after this.
2841 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842static int set_disable_status_param(const char *val, struct kernel_param *kp)
2843{
2844 int ret;
2845 struct pm8921_chg_chip *chip = the_chip;
2846
2847 ret = param_set_int(val, kp);
2848 if (ret) {
2849 pr_err("error setting value %d\n", ret);
2850 return ret;
2851 }
2852 pr_info("factory set disable param to %d\n", charging_disabled);
2853 if (chip) {
2854 pm_chg_auto_enable(chip, !charging_disabled);
2855 pm_chg_charge_dis(chip, charging_disabled);
2856 }
2857 return 0;
2858}
2859module_param_call(disabled, set_disable_status_param, param_get_uint,
2860 &charging_disabled, 0644);
2861
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002862static int rconn_mohm;
2863static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2864{
2865 int ret;
2866 struct pm8921_chg_chip *chip = the_chip;
2867
2868 ret = param_set_int(val, kp);
2869 if (ret) {
2870 pr_err("error setting value %d\n", ret);
2871 return ret;
2872 }
2873 if (chip)
2874 chip->rconn_mohm = rconn_mohm;
2875 return 0;
2876}
2877module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2878 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002879/**
2880 * set_thermal_mitigation_level -
2881 *
2882 * Internal function to control battery charging current to reduce
2883 * temperature
2884 */
2885static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2886{
2887 int ret;
2888 struct pm8921_chg_chip *chip = the_chip;
2889
2890 ret = param_set_int(val, kp);
2891 if (ret) {
2892 pr_err("error setting value %d\n", ret);
2893 return ret;
2894 }
2895
2896 if (!chip) {
2897 pr_err("called before init\n");
2898 return -EINVAL;
2899 }
2900
2901 if (!chip->thermal_mitigation) {
2902 pr_err("no thermal mitigation\n");
2903 return -EINVAL;
2904 }
2905
2906 if (thermal_mitigation < 0
2907 || thermal_mitigation >= chip->thermal_levels) {
2908 pr_err("out of bound level selected\n");
2909 return -EINVAL;
2910 }
2911
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002912 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002913 return ret;
2914}
2915module_param_call(thermal_mitigation, set_therm_mitigation_level,
2916 param_get_uint,
2917 &thermal_mitigation, 0644);
2918
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002919static int set_usb_max_current(const char *val, struct kernel_param *kp)
2920{
2921 int ret, mA;
2922 struct pm8921_chg_chip *chip = the_chip;
2923
2924 ret = param_set_int(val, kp);
2925 if (ret) {
2926 pr_err("error setting value %d\n", ret);
2927 return ret;
2928 }
2929 if (chip) {
2930 pr_warn("setting current max to %d\n", usb_max_current);
2931 pm_chg_iusbmax_get(chip, &mA);
2932 if (mA > usb_max_current)
2933 pm8921_charger_vbus_draw(usb_max_current);
2934 return 0;
2935 }
2936 return -EINVAL;
2937}
David Keitelacf57c82012-03-07 18:48:50 -08002938module_param_call(usb_max_current, set_usb_max_current,
2939 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941static void free_irqs(struct pm8921_chg_chip *chip)
2942{
2943 int i;
2944
2945 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2946 if (chip->pmic_chg_irq[i]) {
2947 free_irq(chip->pmic_chg_irq[i], chip);
2948 chip->pmic_chg_irq[i] = 0;
2949 }
2950}
2951
David Keitel88e1b572012-01-11 11:57:14 -08002952/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002953static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2954{
2955 unsigned long flags;
2956 int fsm_state;
2957
2958 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2959 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2960
2961 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002962 if (chip->usb_present) {
2963 schedule_delayed_work(&chip->unplug_check_work,
2964 round_jiffies_relative(msecs_to_jiffies
2965 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002966 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002967 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968
2969 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2970 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2971 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002972 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2973 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2974 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2975 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2976 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002977 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002978 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2979 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002980 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002981
2982 spin_lock_irqsave(&vbus_lock, flags);
2983 if (usb_chg_current) {
2984 /* reissue a vbus draw call */
2985 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002986 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 }
2988 spin_unlock_irqrestore(&vbus_lock, flags);
2989
2990 fsm_state = pm_chg_get_fsm_state(chip);
2991 if (is_battery_charging(fsm_state)) {
2992 chip->bms_notify.is_charging = 1;
2993 pm8921_bms_charging_began();
2994 }
2995
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002996 check_battery_valid(chip);
2997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002998 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2999 chip->usb_present,
3000 chip->dc_present,
3001 get_prop_batt_present(chip),
3002 fsm_state);
3003}
3004
3005struct pm_chg_irq_init_data {
3006 unsigned int irq_id;
3007 char *name;
3008 unsigned long flags;
3009 irqreturn_t (*handler)(int, void *);
3010};
3011
3012#define CHG_IRQ(_id, _flags, _handler) \
3013{ \
3014 .irq_id = _id, \
3015 .name = #_id, \
3016 .flags = _flags, \
3017 .handler = _handler, \
3018}
3019struct pm_chg_irq_init_data chg_irq_data[] = {
3020 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3021 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003022 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3024 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003025 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3026 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3028 usbin_uv_irq_handler),
3029 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3030 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3031 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3032 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3033 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3034 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3035 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3036 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3037 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003038 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3039 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003040 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3041 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3042 batt_removed_irq_handler),
3043 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3044 batttemp_hot_irq_handler),
3045 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3046 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3047 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003048 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3049 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003050 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3051 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3053 coarse_det_low_irq_handler),
3054 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3055 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3056 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3057 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3058 batfet_irq_handler),
3059 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3060 dcin_valid_irq_handler),
3061 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3062 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003063 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064};
3065
3066static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3067 struct platform_device *pdev)
3068{
3069 struct resource *res;
3070 int ret, i;
3071
3072 ret = 0;
3073 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3074
3075 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3076 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3077 chg_irq_data[i].name);
3078 if (res == NULL) {
3079 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3080 goto err_out;
3081 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003082 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083 ret = request_irq(res->start, chg_irq_data[i].handler,
3084 chg_irq_data[i].flags,
3085 chg_irq_data[i].name, chip);
3086 if (ret < 0) {
3087 pr_err("couldn't request %d (%s) %d\n", res->start,
3088 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003089 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090 goto err_out;
3091 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003092 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3093 }
3094 return 0;
3095
3096err_out:
3097 free_irqs(chip);
3098 return -EINVAL;
3099}
3100
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003101static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3102{
3103 int err;
3104 u8 temp;
3105
3106 temp = 0xD1;
3107 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3108 if (err) {
3109 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3110 return;
3111 }
3112
3113 temp = 0xD3;
3114 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3115 if (err) {
3116 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3117 return;
3118 }
3119
3120 temp = 0xD1;
3121 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3122 if (err) {
3123 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3124 return;
3125 }
3126
3127 temp = 0xD5;
3128 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3129 if (err) {
3130 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3131 return;
3132 }
3133
3134 udelay(183);
3135
3136 temp = 0xD1;
3137 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3138 if (err) {
3139 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3140 return;
3141 }
3142
3143 temp = 0xD0;
3144 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3145 if (err) {
3146 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3147 return;
3148 }
3149 udelay(32);
3150
3151 temp = 0xD1;
3152 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3153 if (err) {
3154 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3155 return;
3156 }
3157
3158 temp = 0xD3;
3159 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3160 if (err) {
3161 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3162 return;
3163 }
3164}
3165
3166static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3167{
3168 int err;
3169 u8 temp;
3170
3171 temp = 0xD1;
3172 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3173 if (err) {
3174 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3175 return;
3176 }
3177
3178 temp = 0xD0;
3179 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3180 if (err) {
3181 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3182 return;
3183 }
3184}
3185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186#define ENUM_TIMER_STOP_BIT BIT(1)
3187#define BOOT_DONE_BIT BIT(6)
3188#define CHG_BATFET_ON_BIT BIT(3)
3189#define CHG_VCP_EN BIT(0)
3190#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3191#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003192#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3194{
3195 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003196 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003197
3198 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3199 BOOT_DONE_BIT, BOOT_DONE_BIT);
3200 if (rc) {
3201 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3202 return rc;
3203 }
3204
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003205 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3206
3207 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3208 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3209
3210 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3211
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003212 if (rc) {
3213 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003214 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003215 return rc;
3216 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003217 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003218 chip->max_voltage_mv
3219 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003220 if (rc) {
3221 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003222 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 return rc;
3224 }
3225
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003226 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 if (rc) {
3228 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003229 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230 return rc;
3231 }
3232 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3233 if (rc) {
3234 pr_err("Failed to set max voltage to %d rc=%d\n",
3235 SAFE_CURRENT_MA, rc);
3236 return rc;
3237 }
3238
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003239 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003240 if (rc) {
3241 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3242 return rc;
3243 }
3244
3245 rc = pm_chg_iterm_set(chip, chip->term_current);
3246 if (rc) {
3247 pr_err("Failed to set term current to %d rc=%d\n",
3248 chip->term_current, rc);
3249 return rc;
3250 }
3251
3252 /* Disable the ENUM TIMER */
3253 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3254 ENUM_TIMER_STOP_BIT);
3255 if (rc) {
3256 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3257 return rc;
3258 }
3259
3260 /* init with the lowest USB current */
David Keitelacf57c82012-03-07 18:48:50 -08003261 rc = pm_chg_iusbmax_set(chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08003263 pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264 return rc;
3265 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003266
3267 if (chip->safety_time != 0) {
3268 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3269 if (rc) {
3270 pr_err("Failed to set max time to %d minutes rc=%d\n",
3271 chip->safety_time, rc);
3272 return rc;
3273 }
3274 }
3275
3276 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003277 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003278 if (rc) {
3279 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3280 chip->safety_time, rc);
3281 return rc;
3282 }
3283 }
3284
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003285 if (chip->vin_min != 0) {
3286 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3287 if (rc) {
3288 pr_err("Failed to set vin min to %d mV rc=%d\n",
3289 chip->vin_min, rc);
3290 return rc;
3291 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003292 } else {
3293 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003294 }
3295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 rc = pm_chg_disable_wd(chip);
3297 if (rc) {
3298 pr_err("Failed to disable wd rc=%d\n", rc);
3299 return rc;
3300 }
3301
3302 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3303 CHG_BAT_TEMP_DIS_BIT, 0);
3304 if (rc) {
3305 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3306 return rc;
3307 }
3308 /* switch to a 3.2Mhz for the buck */
3309 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3310 if (rc) {
3311 pr_err("Failed to switch buck clk rc=%d\n", rc);
3312 return rc;
3313 }
3314
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003315 if (chip->trkl_voltage != 0) {
3316 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3317 if (rc) {
3318 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3319 chip->trkl_voltage, rc);
3320 return rc;
3321 }
3322 }
3323
3324 if (chip->weak_voltage != 0) {
3325 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3326 if (rc) {
3327 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3328 chip->weak_voltage, rc);
3329 return rc;
3330 }
3331 }
3332
3333 if (chip->trkl_current != 0) {
3334 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3335 if (rc) {
3336 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3337 chip->trkl_voltage, rc);
3338 return rc;
3339 }
3340 }
3341
3342 if (chip->weak_current != 0) {
3343 rc = pm_chg_iweak_set(chip, chip->weak_current);
3344 if (rc) {
3345 pr_err("Failed to set weak current to %dmA rc=%d\n",
3346 chip->weak_current, rc);
3347 return rc;
3348 }
3349 }
3350
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003351 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3352 if (rc) {
3353 pr_err("Failed to set cold config %d rc=%d\n",
3354 chip->cold_thr, rc);
3355 }
3356
3357 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3358 if (rc) {
3359 pr_err("Failed to set hot config %d rc=%d\n",
3360 chip->hot_thr, rc);
3361 }
3362
Jay Chokshid674a512012-03-15 14:06:04 -07003363 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3364 if (rc) {
3365 pr_err("Failed to set charger LED src config %d rc=%d\n",
3366 chip->led_src_config, rc);
3367 }
3368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 /* Workarounds for die 1.1 and 1.0 */
3370 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3371 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3373 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003374
3375 /* software workaround for correct battery_id detection */
3376 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3377 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3378 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3379 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3380 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3381 udelay(100);
3382 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383 }
3384
David Keitelb51995e2011-11-18 17:03:31 -08003385 /* Workarounds for die 3.0 */
3386 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3387 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3388
3389 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3390
David Keitela3c0d822011-11-03 14:18:52 -07003391 /* Disable EOC FSM processing */
3392 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3393
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003394 pm8921_chg_force_19p2mhz_clk(chip);
3395
3396 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3397 VREF_BATT_THERM_FORCE_ON);
3398 if (rc)
3399 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401 rc = pm_chg_charge_dis(chip, charging_disabled);
3402 if (rc) {
3403 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3404 return rc;
3405 }
3406
3407 rc = pm_chg_auto_enable(chip, !charging_disabled);
3408 if (rc) {
3409 pr_err("Failed to enable charging rc=%d\n", rc);
3410 return rc;
3411 }
3412
3413 return 0;
3414}
3415
3416static int get_rt_status(void *data, u64 * val)
3417{
3418 int i = (int)data;
3419 int ret;
3420
3421 /* global irq number is passed in via data */
3422 ret = pm_chg_get_rt_status(the_chip, i);
3423 *val = ret;
3424 return 0;
3425}
3426DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3427
3428static int get_fsm_status(void *data, u64 * val)
3429{
3430 u8 temp;
3431
3432 temp = pm_chg_get_fsm_state(the_chip);
3433 *val = temp;
3434 return 0;
3435}
3436DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3437
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003438static int get_reg_loop(void *data, u64 * val)
3439{
3440 u8 temp;
3441
3442 if (!the_chip) {
3443 pr_err("%s called before init\n", __func__);
3444 return -EINVAL;
3445 }
3446 temp = pm_chg_get_regulation_loop(the_chip);
3447 *val = temp;
3448 return 0;
3449}
3450DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003452static int get_reg(void *data, u64 * val)
3453{
3454 int addr = (int)data;
3455 int ret;
3456 u8 temp;
3457
3458 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3459 if (ret) {
3460 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3461 addr, temp, ret);
3462 return -EAGAIN;
3463 }
3464 *val = temp;
3465 return 0;
3466}
3467
3468static int set_reg(void *data, u64 val)
3469{
3470 int addr = (int)data;
3471 int ret;
3472 u8 temp;
3473
3474 temp = (u8) val;
3475 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3476 if (ret) {
3477 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3478 addr, temp, ret);
3479 return -EAGAIN;
3480 }
3481 return 0;
3482}
3483DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3484
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003485enum {
3486 BAT_WARM_ZONE,
3487 BAT_COOL_ZONE,
3488};
3489static int get_warm_cool(void *data, u64 * val)
3490{
3491 if (!the_chip) {
3492 pr_err("%s called before init\n", __func__);
3493 return -EINVAL;
3494 }
3495 if ((int)data == BAT_WARM_ZONE)
3496 *val = the_chip->is_bat_warm;
3497 if ((int)data == BAT_COOL_ZONE)
3498 *val = the_chip->is_bat_cool;
3499 return 0;
3500}
3501DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3504{
3505 int i;
3506
3507 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3508
3509 if (IS_ERR(chip->dent)) {
3510 pr_err("pmic charger couldnt create debugfs dir\n");
3511 return;
3512 }
3513
3514 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3515 (void *)CHG_CNTRL, &reg_fops);
3516 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3517 (void *)CHG_CNTRL_2, &reg_fops);
3518 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3519 (void *)CHG_CNTRL_3, &reg_fops);
3520 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3521 (void *)PBL_ACCESS1, &reg_fops);
3522 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3523 (void *)PBL_ACCESS2, &reg_fops);
3524 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3525 (void *)SYS_CONFIG_1, &reg_fops);
3526 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3527 (void *)SYS_CONFIG_2, &reg_fops);
3528 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3529 (void *)CHG_VDD_MAX, &reg_fops);
3530 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3531 (void *)CHG_VDD_SAFE, &reg_fops);
3532 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3533 (void *)CHG_VBAT_DET, &reg_fops);
3534 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3535 (void *)CHG_IBAT_MAX, &reg_fops);
3536 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3537 (void *)CHG_IBAT_SAFE, &reg_fops);
3538 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3539 (void *)CHG_VIN_MIN, &reg_fops);
3540 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3541 (void *)CHG_VTRICKLE, &reg_fops);
3542 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3543 (void *)CHG_ITRICKLE, &reg_fops);
3544 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3545 (void *)CHG_ITERM, &reg_fops);
3546 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3547 (void *)CHG_TCHG_MAX, &reg_fops);
3548 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3549 (void *)CHG_TWDOG, &reg_fops);
3550 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3551 (void *)CHG_TEMP_THRESH, &reg_fops);
3552 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3553 (void *)CHG_COMP_OVR, &reg_fops);
3554 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3555 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3556 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3557 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3558 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3559 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3560 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3561 (void *)CHG_TEST, &reg_fops);
3562
3563 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3564 &fsm_fops);
3565
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003566 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3567 &reg_loop_fops);
3568
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003569 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3570 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3571 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3572 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3575 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3576 debugfs_create_file(chg_irq_data[i].name, 0444,
3577 chip->dent,
3578 (void *)chg_irq_data[i].irq_id,
3579 &rt_fops);
3580 }
3581}
3582
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003583static int pm8921_charger_suspend_noirq(struct device *dev)
3584{
3585 int rc;
3586 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3587
3588 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3589 if (rc)
3590 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3591 pm8921_chg_set_hw_clk_switching(chip);
3592 return 0;
3593}
3594
3595static int pm8921_charger_resume_noirq(struct device *dev)
3596{
3597 int rc;
3598 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3599
3600 pm8921_chg_force_19p2mhz_clk(chip);
3601
3602 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3603 VREF_BATT_THERM_FORCE_ON);
3604 if (rc)
3605 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3606 return 0;
3607}
3608
David Keitelf2226022011-12-13 15:55:50 -08003609static int pm8921_charger_resume(struct device *dev)
3610{
3611 int rc;
3612 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3613
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003614 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003615 && !(chip->keep_btm_on_suspend)) {
3616 rc = pm8xxx_adc_btm_configure(&btm_config);
3617 if (rc)
3618 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3619
3620 rc = pm8xxx_adc_btm_start();
3621 if (rc)
3622 pr_err("couldn't restart btm rc=%d\n", rc);
3623 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003624 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3625 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3626 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3627 }
David Keitelf2226022011-12-13 15:55:50 -08003628 return 0;
3629}
3630
3631static int pm8921_charger_suspend(struct device *dev)
3632{
3633 int rc;
3634 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3635
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003636 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003637 && !(chip->keep_btm_on_suspend)) {
3638 rc = pm8xxx_adc_btm_end();
3639 if (rc)
3640 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3641 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003642
3643 if (is_usb_chg_plugged_in(chip)) {
3644 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3645 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3646 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003647
David Keitelf2226022011-12-13 15:55:50 -08003648 return 0;
3649}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003650static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3651{
3652 int rc = 0;
3653 struct pm8921_chg_chip *chip;
3654 const struct pm8921_charger_platform_data *pdata
3655 = pdev->dev.platform_data;
3656
3657 if (!pdata) {
3658 pr_err("missing platform data\n");
3659 return -EINVAL;
3660 }
3661
3662 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3663 GFP_KERNEL);
3664 if (!chip) {
3665 pr_err("Cannot allocate pm_chg_chip\n");
3666 return -ENOMEM;
3667 }
3668
3669 chip->dev = &pdev->dev;
3670 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003671 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003672 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003673 chip->max_voltage_mv = pdata->max_voltage;
3674 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003675 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003676 chip->term_current = pdata->term_current;
3677 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003678 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003679 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3680 chip->batt_id_min = pdata->batt_id_min;
3681 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003682 if (pdata->cool_temp != INT_MIN)
3683 chip->cool_temp_dc = pdata->cool_temp * 10;
3684 else
3685 chip->cool_temp_dc = INT_MIN;
3686
3687 if (pdata->warm_temp != INT_MIN)
3688 chip->warm_temp_dc = pdata->warm_temp * 10;
3689 else
3690 chip->warm_temp_dc = INT_MIN;
3691
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003692 chip->temp_check_period = pdata->temp_check_period;
3693 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3694 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3695 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3696 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3697 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003698 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003699 chip->trkl_voltage = pdata->trkl_voltage;
3700 chip->weak_voltage = pdata->weak_voltage;
3701 chip->trkl_current = pdata->trkl_current;
3702 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003703 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003704 chip->thermal_mitigation = pdata->thermal_mitigation;
3705 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003706
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003707 chip->cold_thr = pdata->cold_thr;
3708 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003709 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003710 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712 rc = pm8921_chg_hw_init(chip);
3713 if (rc) {
3714 pr_err("couldn't init hardware rc=%d\n", rc);
3715 goto free_chip;
3716 }
3717
3718 chip->usb_psy.name = "usb",
3719 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3720 chip->usb_psy.supplied_to = pm_power_supplied_to,
3721 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003722 chip->usb_psy.properties = pm_power_props_usb,
3723 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3724 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725
David Keitel6ed71a52012-01-30 12:42:18 -08003726 chip->dc_psy.name = "pm8921-dc",
3727 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3728 chip->dc_psy.supplied_to = pm_power_supplied_to,
3729 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003730 chip->dc_psy.properties = pm_power_props_mains,
3731 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3732 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003734 chip->batt_psy.name = "battery",
3735 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3736 chip->batt_psy.properties = msm_batt_power_props,
3737 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3738 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003739 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003740 rc = power_supply_register(chip->dev, &chip->usb_psy);
3741 if (rc < 0) {
3742 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003743 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003744 }
3745
David Keitel6ed71a52012-01-30 12:42:18 -08003746 rc = power_supply_register(chip->dev, &chip->dc_psy);
3747 if (rc < 0) {
3748 pr_err("power_supply_register usb failed rc = %d\n", rc);
3749 goto unregister_usb;
3750 }
3751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003752 rc = power_supply_register(chip->dev, &chip->batt_psy);
3753 if (rc < 0) {
3754 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003755 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756 }
3757
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003758 platform_set_drvdata(pdev, chip);
3759 the_chip = chip;
3760
3761 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003762 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003763 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3764 vin_collapse_check_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003765 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3766 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003767 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 rc = request_irqs(chip, pdev);
3770 if (rc) {
3771 pr_err("couldn't register interrupts rc=%d\n", rc);
3772 goto unregister_batt;
3773 }
3774
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003775 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3776 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3777 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003778 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3779 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003780 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003781 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003782 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003783 * care for jeita compliance
3784 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003785 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003786 rc = configure_btm(chip);
3787 if (rc) {
3788 pr_err("couldn't register with btm rc=%d\n", rc);
3789 goto free_irq;
3790 }
3791 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793 create_debugfs_entries(chip);
3794
3795 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003796 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 /* determine what state the charger is in */
3799 determine_initial_state(chip);
3800
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003801 if (chip->update_time) {
3802 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3803 update_heartbeat);
3804 schedule_delayed_work(&chip->update_heartbeat_work,
3805 round_jiffies_relative(msecs_to_jiffies
3806 (chip->update_time)));
3807 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808 return 0;
3809
3810free_irq:
3811 free_irqs(chip);
3812unregister_batt:
3813 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003814unregister_dc:
3815 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816unregister_usb:
3817 power_supply_unregister(&chip->usb_psy);
3818free_chip:
3819 kfree(chip);
3820 return rc;
3821}
3822
3823static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3824{
3825 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3826
3827 free_irqs(chip);
3828 platform_set_drvdata(pdev, NULL);
3829 the_chip = NULL;
3830 kfree(chip);
3831 return 0;
3832}
David Keitelf2226022011-12-13 15:55:50 -08003833static const struct dev_pm_ops pm8921_pm_ops = {
3834 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003835 .suspend_noirq = pm8921_charger_suspend_noirq,
3836 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003837 .resume = pm8921_charger_resume,
3838};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003840 .probe = pm8921_charger_probe,
3841 .remove = __devexit_p(pm8921_charger_remove),
3842 .driver = {
3843 .name = PM8921_CHARGER_DEV_NAME,
3844 .owner = THIS_MODULE,
3845 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846 },
3847};
3848
3849static int __init pm8921_charger_init(void)
3850{
3851 return platform_driver_register(&pm8921_charger_driver);
3852}
3853
3854static void __exit pm8921_charger_exit(void)
3855{
3856 platform_driver_unregister(&pm8921_charger_driver);
3857}
3858
3859late_initcall(pm8921_charger_init);
3860module_exit(pm8921_charger_exit);
3861
3862MODULE_LICENSE("GPL v2");
3863MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3864MODULE_VERSION("1.0");
3865MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);