blob: f6e7e939e7a8097e72a33d034653dcf1d4a44cc5 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266};
267
David Keitelacf57c82012-03-07 18:48:50 -0800268/* user space parameter to limit usb current */
269static unsigned int usb_max_current;
270/*
271 * usb_target_ma is used for wall charger
272 * adaptive input current limiting only. Use
273 * pm_iusbmax_get() to get current maximum usb current setting.
274 */
275static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700277static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278
279static struct pm8921_chg_chip *the_chip;
280
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700281static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
284 u8 mask, u8 val)
285{
286 int rc;
287 u8 reg;
288
289 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
290 if (rc) {
291 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
292 return rc;
293 }
294 reg &= ~mask;
295 reg |= val & mask;
296 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
297 if (rc) {
298 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
299 return rc;
300 }
301 return 0;
302}
303
David Keitelcf867232012-01-27 18:40:12 -0800304static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
305{
306 return pm8xxx_read_irq_stat(chip->dev->parent,
307 chip->pmic_chg_irq[irq_id]);
308}
309
310/* Treat OverVoltage/UnderVoltage as source missing */
311static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
312{
313 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
314}
315
316/* Treat OverVoltage/UnderVoltage as source missing */
317static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
318{
319 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
320}
321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322#define CAPTURE_FSM_STATE_CMD 0xC2
323#define READ_BANK_7 0x70
324#define READ_BANK_4 0x40
325static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
326{
327 u8 temp;
328 int err, ret = 0;
329
330 temp = CAPTURE_FSM_STATE_CMD;
331 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
332 if (err) {
333 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
334 return err;
335 }
336
337 temp = READ_BANK_7;
338 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
339 if (err) {
340 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
341 return err;
342 }
343
344 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
345 if (err) {
346 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
347 return err;
348 }
349 /* get the lower 4 bits */
350 ret = temp & 0xF;
351
352 temp = READ_BANK_4;
353 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
354 if (err) {
355 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
356 return err;
357 }
358
359 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
360 if (err) {
361 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
362 return err;
363 }
364 /* get the upper 1 bit */
365 ret |= (temp & 0x1) << 4;
366 return ret;
367}
368
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700369#define READ_BANK_6 0x60
370static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
371{
372 u8 temp;
373 int err;
374
375 temp = READ_BANK_6;
376 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
377 if (err) {
378 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
379 return err;
380 }
381
382 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
383 if (err) {
384 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
385 return err;
386 }
387
388 /* return the lower 4 bits */
389 return temp & CHG_ALL_LOOPS;
390}
391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392#define CHG_USB_SUSPEND_BIT BIT(2)
393static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
394{
395 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
396 enable ? CHG_USB_SUSPEND_BIT : 0);
397}
398
399#define CHG_EN_BIT BIT(7)
400static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
401{
402 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
403 enable ? CHG_EN_BIT : 0);
404}
405
David Keitel753ec8d2011-11-02 10:56:37 -0700406#define CHG_FAILED_CLEAR BIT(0)
407#define ATC_FAILED_CLEAR BIT(1)
408static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
409{
410 int rc;
411
412 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
413 clear ? ATC_FAILED_CLEAR : 0);
414 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
415 clear ? CHG_FAILED_CLEAR : 0);
416 return rc;
417}
418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419#define CHG_CHARGE_DIS_BIT BIT(1)
420static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
421{
422 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
423 disable ? CHG_CHARGE_DIS_BIT : 0);
424}
425
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800426static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
427{
428 u8 temp;
429
430 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
431 return temp & CHG_CHARGE_DIS_BIT;
432}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433#define PM8921_CHG_V_MIN_MV 3240
434#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800435#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436#define PM8921_CHG_VDDMAX_MAX 4500
437#define PM8921_CHG_VDDMAX_MIN 3400
438#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800439static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800441 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800442 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800444 if (voltage < PM8921_CHG_VDDMAX_MIN
445 || voltage > PM8921_CHG_VDDMAX_MAX) {
446 pr_err("bad mV=%d asked to set\n", voltage);
447 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 }
David Keitelcf867232012-01-27 18:40:12 -0800449
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800450 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
451
452 remainder = voltage % 20;
453 if (remainder >= 10) {
454 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
455 }
456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800458 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459}
460
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700461static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
462{
463 u8 temp;
464 int rc;
465
466 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
467 if (rc) {
468 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700469 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700470 return rc;
471 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800472 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
473 + PM8921_CHG_V_MIN_MV;
474 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
475 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700476 return 0;
477}
478
David Keitelcf867232012-01-27 18:40:12 -0800479static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
480{
481 int current_mv, ret, steps, i;
482 bool increase;
483
484 ret = 0;
485
486 if (voltage < PM8921_CHG_VDDMAX_MIN
487 || voltage > PM8921_CHG_VDDMAX_MAX) {
488 pr_err("bad mV=%d asked to set\n", voltage);
489 return -EINVAL;
490 }
491
492 ret = pm_chg_vddmax_get(chip, &current_mv);
493 if (ret) {
494 pr_err("Failed to read vddmax rc=%d\n", ret);
495 return -EINVAL;
496 }
497 if (current_mv == voltage)
498 return 0;
499
500 /* Only change in increments when USB is present */
501 if (is_usb_chg_plugged_in(chip)) {
502 if (current_mv < voltage) {
503 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
504 increase = true;
505 } else {
506 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
507 increase = false;
508 }
509 for (i = 0; i < steps; i++) {
510 if (increase)
511 current_mv += PM8921_CHG_V_STEP_MV;
512 else
513 current_mv -= PM8921_CHG_V_STEP_MV;
514 ret |= __pm_chg_vddmax_set(chip, current_mv);
515 }
516 }
517 ret |= __pm_chg_vddmax_set(chip, voltage);
518 return ret;
519}
520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521#define PM8921_CHG_VDDSAFE_MIN 3400
522#define PM8921_CHG_VDDSAFE_MAX 4500
523static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
524{
525 u8 temp;
526
527 if (voltage < PM8921_CHG_VDDSAFE_MIN
528 || voltage > PM8921_CHG_VDDSAFE_MAX) {
529 pr_err("bad mV=%d asked to set\n", voltage);
530 return -EINVAL;
531 }
532 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
533 pr_debug("voltage=%d setting %02x\n", voltage, temp);
534 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
535}
536
537#define PM8921_CHG_VBATDET_MIN 3240
538#define PM8921_CHG_VBATDET_MAX 5780
539static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
540{
541 u8 temp;
542
543 if (voltage < PM8921_CHG_VBATDET_MIN
544 || voltage > PM8921_CHG_VBATDET_MAX) {
545 pr_err("bad mV=%d asked to set\n", voltage);
546 return -EINVAL;
547 }
548 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
549 pr_debug("voltage=%d setting %02x\n", voltage, temp);
550 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
551}
552
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700553#define PM8921_CHG_VINMIN_MIN_MV 3800
554#define PM8921_CHG_VINMIN_STEP_MV 100
555#define PM8921_CHG_VINMIN_USABLE_MAX 6500
556#define PM8921_CHG_VINMIN_USABLE_MIN 4300
557#define PM8921_CHG_VINMIN_MASK 0x1F
558static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
559{
560 u8 temp;
561
562 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
563 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
564 pr_err("bad mV=%d asked to set\n", voltage);
565 return -EINVAL;
566 }
567 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
568 pr_debug("voltage=%d setting %02x\n", voltage, temp);
569 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
570 temp);
571}
572
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800573static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
574{
575 u8 temp;
576 int rc, voltage_mv;
577
578 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
579 temp &= PM8921_CHG_VINMIN_MASK;
580
581 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
582 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
583
584 return voltage_mv;
585}
586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587#define PM8921_CHG_IBATMAX_MIN 325
588#define PM8921_CHG_IBATMAX_MAX 2000
589#define PM8921_CHG_I_MIN_MA 225
590#define PM8921_CHG_I_STEP_MA 50
591#define PM8921_CHG_I_MASK 0x3F
592static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
593{
594 u8 temp;
595
596 if (chg_current < PM8921_CHG_IBATMAX_MIN
597 || chg_current > PM8921_CHG_IBATMAX_MAX) {
598 pr_err("bad mA=%d asked to set\n", chg_current);
599 return -EINVAL;
600 }
601 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
602 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
603}
604
605#define PM8921_CHG_IBATSAFE_MIN 225
606#define PM8921_CHG_IBATSAFE_MAX 3375
607static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
608{
609 u8 temp;
610
611 if (chg_current < PM8921_CHG_IBATSAFE_MIN
612 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
613 pr_err("bad mA=%d asked to set\n", chg_current);
614 return -EINVAL;
615 }
616 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
617 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
618 PM8921_CHG_I_MASK, temp);
619}
620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700622#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623#define PM8921_CHG_ITERM_STEP_MA 10
624#define PM8921_CHG_ITERM_MASK 0xF
625static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
626{
627 u8 temp;
628
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700629 if (chg_current < PM8921_CHG_ITERM_MIN_MA
630 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 pr_err("bad mA=%d asked to set\n", chg_current);
632 return -EINVAL;
633 }
634
635 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
636 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700637 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700638 temp);
639}
640
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700641static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
642{
643 u8 temp;
644 int rc;
645
646 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
647 if (rc) {
648 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700649 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700650 return rc;
651 }
652 temp &= PM8921_CHG_ITERM_MASK;
653 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
654 + PM8921_CHG_ITERM_MIN_MA;
655 return 0;
656}
657
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800658struct usb_ma_limit_entry {
659 int usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800660};
661
662static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitelacf57c82012-03-07 18:48:50 -0800663 {100},
664 {500},
665 {700},
666 {850},
667 {900},
668 {1100},
669 {1300},
670 {1500},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800671};
672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673#define PM8921_CHG_IUSB_MASK 0x1C
674#define PM8921_CHG_IUSB_MAX 7
675#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700676static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677{
678 u8 temp;
679
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700680 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
681 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 return -EINVAL;
683 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700684 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
686 temp);
687}
688
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800689static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
690{
691 u8 temp;
David Keitelacf57c82012-03-07 18:48:50 -0800692 int rc;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800693
694 *mA = 0;
695 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
696 if (rc) {
697 pr_err("err=%d reading PBL_ACCESS2\n", rc);
698 return rc;
699 }
700 temp &= PM8921_CHG_IUSB_MASK;
701 temp = temp >> 2;
David Keitelacf57c82012-03-07 18:48:50 -0800702 *mA = usb_ma_table[temp].usb_ma;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800703 return rc;
704}
705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706#define PM8921_CHG_WD_MASK 0x1F
707static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
708{
709 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700710 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
711}
712
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700713#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700714#define PM8921_CHG_TCHG_MIN 4
715#define PM8921_CHG_TCHG_MAX 512
716#define PM8921_CHG_TCHG_STEP 4
717static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
718{
719 u8 temp;
720
721 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
722 pr_err("bad max minutes =%d asked to set\n", minutes);
723 return -EINVAL;
724 }
725
726 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
727 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
728 temp);
729}
730
731#define PM8921_CHG_TTRKL_MASK 0x1F
732#define PM8921_CHG_TTRKL_MIN 1
733#define PM8921_CHG_TTRKL_MAX 64
734static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
735{
736 u8 temp;
737
738 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
739 pr_err("bad max minutes =%d asked to set\n", minutes);
740 return -EINVAL;
741 }
742
743 temp = minutes - 1;
744 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
745 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746}
747
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700748#define PM8921_CHG_VTRKL_MIN_MV 2050
749#define PM8921_CHG_VTRKL_MAX_MV 2800
750#define PM8921_CHG_VTRKL_STEP_MV 50
751#define PM8921_CHG_VTRKL_SHIFT 4
752#define PM8921_CHG_VTRKL_MASK 0xF0
753static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
754{
755 u8 temp;
756
757 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
758 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
759 pr_err("bad voltage = %dmV asked to set\n", millivolts);
760 return -EINVAL;
761 }
762
763 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
764 temp = temp << PM8921_CHG_VTRKL_SHIFT;
765 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
766 temp);
767}
768
769#define PM8921_CHG_VWEAK_MIN_MV 2100
770#define PM8921_CHG_VWEAK_MAX_MV 3600
771#define PM8921_CHG_VWEAK_STEP_MV 100
772#define PM8921_CHG_VWEAK_MASK 0x0F
773static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
774{
775 u8 temp;
776
777 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
778 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
779 pr_err("bad voltage = %dmV asked to set\n", millivolts);
780 return -EINVAL;
781 }
782
783 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
784 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
785 temp);
786}
787
788#define PM8921_CHG_ITRKL_MIN_MA 50
789#define PM8921_CHG_ITRKL_MAX_MA 200
790#define PM8921_CHG_ITRKL_MASK 0x0F
791#define PM8921_CHG_ITRKL_STEP_MA 10
792static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
793{
794 u8 temp;
795
796 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
797 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
798 pr_err("bad current = %dmA asked to set\n", milliamps);
799 return -EINVAL;
800 }
801
802 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
803
804 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
805 temp);
806}
807
808#define PM8921_CHG_IWEAK_MIN_MA 325
809#define PM8921_CHG_IWEAK_MAX_MA 525
810#define PM8921_CHG_IWEAK_SHIFT 7
811#define PM8921_CHG_IWEAK_MASK 0x80
812static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
813{
814 u8 temp;
815
816 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
817 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
818 pr_err("bad current = %dmA asked to set\n", milliamps);
819 return -EINVAL;
820 }
821
822 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
823 temp = 0;
824 else
825 temp = 1;
826
827 temp = temp << PM8921_CHG_IWEAK_SHIFT;
828 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
829 temp);
830}
831
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700832#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
833#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
834static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
835 enum pm8921_chg_cold_thr cold_thr)
836{
837 u8 temp;
838
839 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
840 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
841 return pm_chg_masked_write(chip, CHG_CNTRL_2,
842 PM8921_CHG_BATT_TEMP_THR_COLD,
843 temp);
844}
845
846#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
847#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
848static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
849 enum pm8921_chg_hot_thr hot_thr)
850{
851 u8 temp;
852
853 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
854 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
855 return pm_chg_masked_write(chip, CHG_CNTRL_2,
856 PM8921_CHG_BATT_TEMP_THR_HOT,
857 temp);
858}
859
David Keitel8c5201a2012-02-24 16:08:54 -0800860static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
861{
862 u8 temp;
863 int rc;
864
865 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
866 if (rc) {
867 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
868 return;
869 }
870 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
871 if (rc) {
872 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
873 return;
874 }
875 /* set the input voltage disable bit and the write bit */
876 temp |= 0x81;
877 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
878 if (rc) {
879 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
880 return;
881 }
882}
883
884static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
885{
886 u8 temp;
887 int rc;
888
889 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
890 if (rc) {
891 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
892 return;
893 }
894 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
895 if (rc) {
896 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
897 return;
898 }
899 /* unset the input voltage disable bit */
900 temp &= 0xFE;
901 /* set the write bit */
902 temp |= 0x80;
903 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
904 if (rc) {
905 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
906 return;
907 }
908}
909
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700910static int64_t read_battery_id(struct pm8921_chg_chip *chip)
911{
912 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700913 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700914
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700915 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700916 if (rc) {
917 pr_err("error reading batt id channel = %d, rc = %d\n",
918 chip->vbat_channel, rc);
919 return rc;
920 }
921 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
922 result.measurement);
923 return result.physical;
924}
925
926static int is_battery_valid(struct pm8921_chg_chip *chip)
927{
928 int64_t rc;
929
930 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
931 return 1;
932
933 rc = read_battery_id(chip);
934 if (rc < 0) {
935 pr_err("error reading batt id channel = %d, rc = %lld\n",
936 chip->vbat_channel, rc);
937 /* assume battery id is valid when adc error happens */
938 return 1;
939 }
940
941 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
942 pr_err("batt_id phy =%lld is not valid\n", rc);
943 return 0;
944 }
945 return 1;
946}
947
948static void check_battery_valid(struct pm8921_chg_chip *chip)
949{
950 if (is_battery_valid(chip) == 0) {
951 pr_err("batt_id not valid, disbling charging\n");
952 pm_chg_auto_enable(chip, 0);
953 } else {
954 pm_chg_auto_enable(chip, !charging_disabled);
955 }
956}
957
958static void battery_id_valid(struct work_struct *work)
959{
960 struct pm8921_chg_chip *chip = container_of(work,
961 struct pm8921_chg_chip, battery_id_valid_work);
962
963 check_battery_valid(chip);
964}
965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
967{
968 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
969 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
970 enable_irq(chip->pmic_chg_irq[interrupt]);
971 }
972}
973
974static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
975{
976 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
977 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
978 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
979 }
980}
981
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800982static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
983{
984 return test_bit(interrupt, chip->enabled_irqs);
985}
986
Amir Samuelovd31ef502011-10-26 14:41:36 +0200987static bool is_ext_charging(struct pm8921_chg_chip *chip)
988{
David Keitel88e1b572012-01-11 11:57:14 -0800989 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200990
David Keitel88e1b572012-01-11 11:57:14 -0800991 if (!chip->ext_psy)
992 return false;
993 if (chip->ext_psy->get_property(chip->ext_psy,
994 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
995 return false;
996 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
997 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200998
999 return false;
1000}
1001
1002static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1003{
David Keitel88e1b572012-01-11 11:57:14 -08001004 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001005
David Keitel88e1b572012-01-11 11:57:14 -08001006 if (!chip->ext_psy)
1007 return false;
1008 if (chip->ext_psy->get_property(chip->ext_psy,
1009 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1010 return false;
1011 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001012 return true;
1013
1014 return false;
1015}
1016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017static int is_battery_charging(int fsm_state)
1018{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001019 if (is_ext_charging(the_chip))
1020 return 1;
1021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 switch (fsm_state) {
1023 case FSM_STATE_ATC_2A:
1024 case FSM_STATE_ATC_2B:
1025 case FSM_STATE_ON_CHG_AND_BAT_6:
1026 case FSM_STATE_FAST_CHG_7:
1027 case FSM_STATE_TRKL_CHG_8:
1028 return 1;
1029 }
1030 return 0;
1031}
1032
1033static void bms_notify(struct work_struct *work)
1034{
1035 struct bms_notify *n = container_of(work, struct bms_notify, work);
1036
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001037 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001039 } else {
1040 pm8921_bms_charging_end(n->is_battery_full);
1041 n->is_battery_full = 0;
1042 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043}
1044
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001045static void bms_notify_check(struct pm8921_chg_chip *chip)
1046{
1047 int fsm_state, new_is_charging;
1048
1049 fsm_state = pm_chg_get_fsm_state(chip);
1050 new_is_charging = is_battery_charging(fsm_state);
1051
1052 if (chip->bms_notify.is_charging ^ new_is_charging) {
1053 chip->bms_notify.is_charging = new_is_charging;
1054 schedule_work(&(chip->bms_notify.work));
1055 }
1056}
1057
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001058static enum power_supply_property pm_power_props_usb[] = {
1059 POWER_SUPPLY_PROP_PRESENT,
1060 POWER_SUPPLY_PROP_ONLINE,
1061 POWER_SUPPLY_PROP_CURRENT_MAX,
1062};
1063
1064static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001066 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067};
1068
1069static char *pm_power_supplied_to[] = {
1070 "battery",
1071};
1072
David Keitel6ed71a52012-01-30 12:42:18 -08001073#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001074static int pm_power_get_property_mains(struct power_supply *psy,
1075 enum power_supply_property psp,
1076 union power_supply_propval *val)
1077{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001078 /* Check if called before init */
1079 if (!the_chip)
1080 return -EINVAL;
1081
1082 switch (psp) {
1083 case POWER_SUPPLY_PROP_PRESENT:
1084 case POWER_SUPPLY_PROP_ONLINE:
1085 val->intval = 0;
1086 if (charging_disabled)
1087 return 0;
1088
1089 /* check external charger first before the dc path */
1090 if (is_ext_charging(the_chip)) {
1091 val->intval = 1;
1092 return 0;
1093 }
1094
1095 if (pm_is_chg_charge_dis(the_chip)) {
1096 val->intval = 0;
1097 return 0;
1098 }
1099
1100 if (the_chip->dc_present) {
1101 val->intval = 1;
1102 return 0;
1103 }
1104
1105 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001106 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001107 val->intval = is_usb_chg_plugged_in(the_chip);
1108 return 0;
1109
1110 break;
1111 default:
1112 return -EINVAL;
1113 }
1114 return 0;
1115}
1116
1117static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001118 enum power_supply_property psp,
1119 union power_supply_propval *val)
1120{
David Keitel6ed71a52012-01-30 12:42:18 -08001121 int current_max;
1122
1123 /* Check if called before init */
1124 if (!the_chip)
1125 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001126
1127 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001128 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001129 if (pm_is_chg_charge_dis(the_chip)) {
1130 val->intval = 0;
1131 } else {
1132 pm_chg_iusbmax_get(the_chip, &current_max);
1133 val->intval = current_max;
1134 }
David Keitel6ed71a52012-01-30 12:42:18 -08001135 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001137 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001138 val->intval = 0;
1139 if (charging_disabled)
1140 return 0;
1141
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001142 /*
1143 * if drawing any current from usb is disabled behave
1144 * as if no usb cable is connected
1145 */
1146 if (pm_is_chg_charge_dis(the_chip))
1147 return 0;
1148
David Keitel63f71662012-02-08 20:30:00 -08001149 /* USB charging */
David Keitel70f6cdc22012-03-15 15:33:26 -07001150 val->intval = is_usb_chg_plugged_in(the_chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151 break;
1152 default:
1153 return -EINVAL;
1154 }
1155 return 0;
1156}
1157
1158static enum power_supply_property msm_batt_power_props[] = {
1159 POWER_SUPPLY_PROP_STATUS,
1160 POWER_SUPPLY_PROP_CHARGE_TYPE,
1161 POWER_SUPPLY_PROP_HEALTH,
1162 POWER_SUPPLY_PROP_PRESENT,
1163 POWER_SUPPLY_PROP_TECHNOLOGY,
1164 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1165 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1166 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1167 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001168 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001169 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001170 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171};
1172
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001173static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174{
1175 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001176 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001178 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 if (rc) {
1180 pr_err("error reading adc channel = %d, rc = %d\n",
1181 chip->vbat_channel, rc);
1182 return rc;
1183 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001184 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 result.measurement);
1186 return (int)result.physical;
1187}
1188
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001189static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1190{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001191 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1192 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1193 unsigned int low_voltage = chip->min_voltage_mv;
1194 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001195
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001196 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001197 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001198 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001199 return 100;
1200 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001201 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001202 / (high_voltage - low_voltage);
1203}
1204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1206{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001207 int percent_soc = pm8921_bms_get_percent_charge();
1208
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001209 if (percent_soc == -ENXIO)
1210 percent_soc = voltage_based_capacity(chip);
1211
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001212 if (percent_soc <= 10)
1213 pr_warn("low battery charge = %d%%\n", percent_soc);
1214
1215 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216}
1217
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001218static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1219{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001220 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001221
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001222 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001223 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001224 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001225 }
1226
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001227 if (rc) {
1228 pr_err("unable to get batt current rc = %d\n", rc);
1229 return rc;
1230 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001231 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001232 }
1233}
1234
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001235static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1236{
1237 int rc;
1238
1239 rc = pm8921_bms_get_fcc();
1240 if (rc < 0)
1241 pr_err("unable to get batt fcc rc = %d\n", rc);
1242 return rc;
1243}
1244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1246{
1247 int temp;
1248
1249 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1250 if (temp)
1251 return POWER_SUPPLY_HEALTH_OVERHEAT;
1252
1253 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1254 if (temp)
1255 return POWER_SUPPLY_HEALTH_COLD;
1256
1257 return POWER_SUPPLY_HEALTH_GOOD;
1258}
1259
1260static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1261{
1262 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1263}
1264
1265static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1266{
1267 int temp;
1268
Amir Samuelovd31ef502011-10-26 14:41:36 +02001269 if (!get_prop_batt_present(chip))
1270 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1271
1272 if (is_ext_trickle_charging(chip))
1273 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1274
1275 if (is_ext_charging(chip))
1276 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1279 if (temp)
1280 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1281
1282 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1283 if (temp)
1284 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1285
1286 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1287}
1288
1289static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1290{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001291 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1292 int fsm_state = pm_chg_get_fsm_state(chip);
1293 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294
David Keitel88e1b572012-01-11 11:57:14 -08001295 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001296 if (chip->ext_charge_done)
1297 return POWER_SUPPLY_STATUS_FULL;
1298 if (chip->ext_charging)
1299 return POWER_SUPPLY_STATUS_CHARGING;
1300 }
1301
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001302 for (i = 0; i < ARRAY_SIZE(map); i++)
1303 if (map[i].fsm_state == fsm_state)
1304 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001305
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001306 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1307 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1308 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001309 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1310 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001311
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001312 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001313 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001314 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315}
1316
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001317#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001318static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1319{
1320 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001321 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001322
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001323 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001324 if (rc) {
1325 pr_err("error reading adc channel = %d, rc = %d\n",
1326 chip->vbat_channel, rc);
1327 return rc;
1328 }
1329 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1330 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001331 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1332 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1333 (int) result.physical);
1334
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001335 return (int)result.physical;
1336}
1337
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338static int pm_batt_power_get_property(struct power_supply *psy,
1339 enum power_supply_property psp,
1340 union power_supply_propval *val)
1341{
1342 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1343 batt_psy);
1344
1345 switch (psp) {
1346 case POWER_SUPPLY_PROP_STATUS:
1347 val->intval = get_prop_batt_status(chip);
1348 break;
1349 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1350 val->intval = get_prop_charge_type(chip);
1351 break;
1352 case POWER_SUPPLY_PROP_HEALTH:
1353 val->intval = get_prop_batt_health(chip);
1354 break;
1355 case POWER_SUPPLY_PROP_PRESENT:
1356 val->intval = get_prop_batt_present(chip);
1357 break;
1358 case POWER_SUPPLY_PROP_TECHNOLOGY:
1359 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1360 break;
1361 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001362 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 break;
1364 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001365 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 break;
1367 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001368 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 break;
1370 case POWER_SUPPLY_PROP_CAPACITY:
1371 val->intval = get_prop_batt_capacity(chip);
1372 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001373 case POWER_SUPPLY_PROP_CURRENT_NOW:
1374 val->intval = get_prop_batt_current(chip);
1375 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001376 case POWER_SUPPLY_PROP_TEMP:
1377 val->intval = get_prop_batt_temp(chip);
1378 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001379 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001380 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001381 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001382 default:
1383 return -EINVAL;
1384 }
1385
1386 return 0;
1387}
1388
1389static void (*notify_vbus_state_func_ptr)(int);
1390static int usb_chg_current;
1391static DEFINE_SPINLOCK(vbus_lock);
1392
1393int pm8921_charger_register_vbus_sn(void (*callback)(int))
1394{
1395 pr_debug("%p\n", callback);
1396 notify_vbus_state_func_ptr = callback;
1397 return 0;
1398}
1399EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1400
1401/* this is passed to the hsusb via platform_data msm_otg_pdata */
1402void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1403{
1404 pr_debug("%p\n", callback);
1405 notify_vbus_state_func_ptr = NULL;
1406}
1407EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1408
1409static void notify_usb_of_the_plugin_event(int plugin)
1410{
1411 plugin = !!plugin;
1412 if (notify_vbus_state_func_ptr) {
1413 pr_debug("notifying plugin\n");
1414 (*notify_vbus_state_func_ptr) (plugin);
1415 } else {
1416 pr_debug("unable to notify plugin\n");
1417 }
1418}
1419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420/* assumes vbus_lock is held */
1421static void __pm8921_charger_vbus_draw(unsigned int mA)
1422{
1423 int i, rc;
1424
1425 if (mA > 0 && mA <= 2) {
1426 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001427 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001429 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 }
1431 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1432 if (rc)
1433 pr_err("fail to set suspend bit rc=%d\n", rc);
1434 } else {
1435 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1436 if (rc)
1437 pr_err("fail to reset suspend bit rc=%d\n", rc);
1438 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1439 if (usb_ma_table[i].usb_ma <= mA)
1440 break;
1441 }
1442 if (i < 0)
1443 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001444 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001446 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 }
1448 }
1449}
1450
1451/* USB calls these to tell us how much max usb current the system can draw */
1452void pm8921_charger_vbus_draw(unsigned int mA)
1453{
1454 unsigned long flags;
1455
1456 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001457
1458 if (usb_max_current && mA > usb_max_current) {
1459 pr_warn("restricting usb current to %d instead of %d\n",
1460 usb_max_current, mA);
1461 mA = usb_max_current;
1462 }
1463 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1464 usb_target_ma = mA;
1465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 spin_lock_irqsave(&vbus_lock, flags);
1467 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001468 if (mA > USB_WALL_THRESHOLD_MA)
1469 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1470 else
1471 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 } else {
1473 /*
1474 * called before pmic initialized,
1475 * save this value and use it at probe
1476 */
David Keitelacf57c82012-03-07 18:48:50 -08001477 if (mA > USB_WALL_THRESHOLD_MA)
1478 usb_chg_current = USB_WALL_THRESHOLD_MA;
1479 else
1480 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 }
1482 spin_unlock_irqrestore(&vbus_lock, flags);
1483}
1484EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1485
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001486int pm8921_charger_enable(bool enable)
1487{
1488 int rc;
1489
1490 if (!the_chip) {
1491 pr_err("called before init\n");
1492 return -EINVAL;
1493 }
1494 enable = !!enable;
1495 rc = pm_chg_auto_enable(the_chip, enable);
1496 if (rc)
1497 pr_err("Failed rc=%d\n", rc);
1498 return rc;
1499}
1500EXPORT_SYMBOL(pm8921_charger_enable);
1501
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001502int pm8921_is_usb_chg_plugged_in(void)
1503{
1504 if (!the_chip) {
1505 pr_err("called before init\n");
1506 return -EINVAL;
1507 }
1508 return is_usb_chg_plugged_in(the_chip);
1509}
1510EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1511
1512int pm8921_is_dc_chg_plugged_in(void)
1513{
1514 if (!the_chip) {
1515 pr_err("called before init\n");
1516 return -EINVAL;
1517 }
1518 return is_dc_chg_plugged_in(the_chip);
1519}
1520EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1521
1522int pm8921_is_battery_present(void)
1523{
1524 if (!the_chip) {
1525 pr_err("called before init\n");
1526 return -EINVAL;
1527 }
1528 return get_prop_batt_present(the_chip);
1529}
1530EXPORT_SYMBOL(pm8921_is_battery_present);
1531
David Keitel012deef2011-12-02 11:49:33 -08001532/*
1533 * Disabling the charge current limit causes current
1534 * current limits to have no monitoring. An adequate charger
1535 * capable of supplying high current while sustaining VIN_MIN
1536 * is required if the limiting is disabled.
1537 */
1538int pm8921_disable_input_current_limit(bool disable)
1539{
1540 if (!the_chip) {
1541 pr_err("called before init\n");
1542 return -EINVAL;
1543 }
1544 if (disable) {
1545 pr_warn("Disabling input current limit!\n");
1546
1547 return pm8xxx_writeb(the_chip->dev->parent,
1548 CHG_BUCK_CTRL_TEST3, 0xF2);
1549 }
1550 return 0;
1551}
1552EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1553
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001554int pm8921_set_max_battery_charge_current(int ma)
1555{
1556 if (!the_chip) {
1557 pr_err("called before init\n");
1558 return -EINVAL;
1559 }
1560 return pm_chg_ibatmax_set(the_chip, ma);
1561}
1562EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1563
1564int pm8921_disable_source_current(bool disable)
1565{
1566 if (!the_chip) {
1567 pr_err("called before init\n");
1568 return -EINVAL;
1569 }
1570 if (disable)
1571 pr_warn("current drawn from chg=0, battery provides current\n");
1572 return pm_chg_charge_dis(the_chip, disable);
1573}
1574EXPORT_SYMBOL(pm8921_disable_source_current);
1575
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001576int pm8921_regulate_input_voltage(int voltage)
1577{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001578 int rc;
1579
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001580 if (!the_chip) {
1581 pr_err("called before init\n");
1582 return -EINVAL;
1583 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001584 rc = pm_chg_vinmin_set(the_chip, voltage);
1585
1586 if (rc == 0)
1587 the_chip->vin_min = voltage;
1588
1589 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001590}
1591
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001592#define USB_OV_THRESHOLD_MASK 0x60
1593#define USB_OV_THRESHOLD_SHIFT 5
1594int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1595{
1596 u8 temp;
1597
1598 if (!the_chip) {
1599 pr_err("called before init\n");
1600 return -EINVAL;
1601 }
1602
1603 if (ov > PM_USB_OV_7V) {
1604 pr_err("limiting to over voltage threshold to 7volts\n");
1605 ov = PM_USB_OV_7V;
1606 }
1607
1608 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1609
1610 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1611 USB_OV_THRESHOLD_MASK, temp);
1612}
1613EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1614
1615#define USB_DEBOUNCE_TIME_MASK 0x06
1616#define USB_DEBOUNCE_TIME_SHIFT 1
1617int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1618{
1619 u8 temp;
1620
1621 if (!the_chip) {
1622 pr_err("called before init\n");
1623 return -EINVAL;
1624 }
1625
1626 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1627 pr_err("limiting debounce to 80.5ms\n");
1628 ms = PM_USB_DEBOUNCE_80P5MS;
1629 }
1630
1631 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1632
1633 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1634 USB_DEBOUNCE_TIME_MASK, temp);
1635}
1636EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1637
1638#define USB_OVP_DISABLE_MASK 0x80
1639int pm8921_usb_ovp_disable(int disable)
1640{
1641 u8 temp = 0;
1642
1643 if (!the_chip) {
1644 pr_err("called before init\n");
1645 return -EINVAL;
1646 }
1647
1648 if (disable)
1649 temp = USB_OVP_DISABLE_MASK;
1650
1651 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1652 USB_OVP_DISABLE_MASK, temp);
1653}
1654
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001655bool pm8921_is_battery_charging(int *source)
1656{
1657 int fsm_state, is_charging, dc_present, usb_present;
1658
1659 if (!the_chip) {
1660 pr_err("called before init\n");
1661 return -EINVAL;
1662 }
1663 fsm_state = pm_chg_get_fsm_state(the_chip);
1664 is_charging = is_battery_charging(fsm_state);
1665 if (is_charging == 0) {
1666 *source = PM8921_CHG_SRC_NONE;
1667 return is_charging;
1668 }
1669
1670 if (source == NULL)
1671 return is_charging;
1672
1673 /* the battery is charging, the source is requested, find it */
1674 dc_present = is_dc_chg_plugged_in(the_chip);
1675 usb_present = is_usb_chg_plugged_in(the_chip);
1676
1677 if (dc_present && !usb_present)
1678 *source = PM8921_CHG_SRC_DC;
1679
1680 if (usb_present && !dc_present)
1681 *source = PM8921_CHG_SRC_USB;
1682
1683 if (usb_present && dc_present)
1684 /*
1685 * The system always chooses dc for charging since it has
1686 * higher priority.
1687 */
1688 *source = PM8921_CHG_SRC_DC;
1689
1690 return is_charging;
1691}
1692EXPORT_SYMBOL(pm8921_is_battery_charging);
1693
1694int pm8921_batt_temperature(void)
1695{
1696 if (!the_chip) {
1697 pr_err("called before init\n");
1698 return -EINVAL;
1699 }
1700 return get_prop_batt_temp(the_chip);
1701}
1702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1704{
1705 int usb_present;
1706
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001707 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708 usb_present = is_usb_chg_plugged_in(chip);
1709 if (chip->usb_present ^ usb_present) {
1710 notify_usb_of_the_plugin_event(usb_present);
1711 chip->usb_present = usb_present;
1712 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001713 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001714 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001715 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001716 if (usb_present) {
1717 schedule_delayed_work(&chip->unplug_check_work,
1718 round_jiffies_relative(msecs_to_jiffies
1719 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001720 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1721 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001722 /* USB unplugged reset target current */
1723 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001724 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001725 }
David Keitel8c5201a2012-02-24 16:08:54 -08001726 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001727 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728}
1729
Amir Samuelovd31ef502011-10-26 14:41:36 +02001730static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1731{
David Keitel88e1b572012-01-11 11:57:14 -08001732 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001733 pr_debug("external charger not registered.\n");
1734 return;
1735 }
1736
1737 if (!chip->ext_charging) {
1738 pr_debug("already not charging.\n");
1739 return;
1740 }
1741
David Keitel88e1b572012-01-11 11:57:14 -08001742 power_supply_set_charge_type(chip->ext_psy,
1743 POWER_SUPPLY_CHARGE_TYPE_NONE);
1744 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001745 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001746 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001747 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001748 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001749}
1750
1751static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1752{
1753 int dc_present;
1754 int batt_present;
1755 int batt_temp_ok;
1756 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001757 unsigned long delay =
1758 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1759
David Keitel88e1b572012-01-11 11:57:14 -08001760 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001761 pr_debug("external charger not registered.\n");
1762 return;
1763 }
1764
1765 if (chip->ext_charging) {
1766 pr_debug("already charging.\n");
1767 return;
1768 }
1769
David Keitel88e1b572012-01-11 11:57:14 -08001770 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001771 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1772 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001773
1774 if (!dc_present) {
1775 pr_warn("%s. dc not present.\n", __func__);
1776 return;
1777 }
1778 if (!batt_present) {
1779 pr_warn("%s. battery not present.\n", __func__);
1780 return;
1781 }
1782 if (!batt_temp_ok) {
1783 pr_warn("%s. battery temperature not ok.\n", __func__);
1784 return;
1785 }
David Keitel88e1b572012-01-11 11:57:14 -08001786 pm8921_disable_source_current(true); /* Force BATFET=ON */
1787 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001788 if (vbat_ov) {
1789 pr_warn("%s. battery over voltage.\n", __func__);
1790 return;
1791 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001792
David Keitel63f71662012-02-08 20:30:00 -08001793 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001794 power_supply_set_charge_type(chip->ext_psy,
1795 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001796 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001797 chip->ext_charging = true;
1798 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001799 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001800 /* Start BMS */
1801 schedule_delayed_work(&chip->eoc_work, delay);
1802 wake_lock(&chip->eoc_wake_lock);
1803}
1804
David Keitel8c5201a2012-02-24 16:08:54 -08001805static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001806{
1807 u8 temp;
1808 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001809
David Keitel8c5201a2012-02-24 16:08:54 -08001810 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001811 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001812 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1813 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001814 }
David Keitel8c5201a2012-02-24 16:08:54 -08001815 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1816 if (rc) {
1817 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1818 return;
1819 }
1820 /* set ovp fet disable bit and the write bit */
1821 temp |= 0x81;
1822 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1823 if (rc) {
1824 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1825 return;
1826 }
1827}
1828
1829static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1830{
1831 u8 temp;
1832 int rc;
1833
1834 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1835 if (rc) {
1836 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1837 return;
1838 }
1839 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1840 if (rc) {
1841 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1842 return;
1843 }
1844 /* unset ovp fet disable bit and set the write bit */
1845 temp &= 0xFE;
1846 temp |= 0x80;
1847 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1848 if (rc) {
1849 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1850 temp, rc);
1851 return;
1852 }
1853}
1854
1855static int param_open_ovp_counter = 10;
1856module_param(param_open_ovp_counter, int, 0644);
1857
1858#define WRITE_BANK_4 0xC0
1859#define USB_OVP_DEBOUNCE_TIME 0x06
1860static void unplug_ovp_fet_open_worker(struct work_struct *work)
1861{
1862 struct pm8921_chg_chip *chip = container_of(work,
1863 struct pm8921_chg_chip,
1864 unplug_ovp_fet_open_work);
1865 int chg_gone, usb_chg_plugged_in;
1866 int count = 0;
1867
1868 while (count++ < param_open_ovp_counter) {
1869 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1870 USB_OVP_DEBOUNCE_TIME, 0x0);
1871 usleep(10);
1872 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1873 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1874 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1875 count, chg_gone, usb_chg_plugged_in);
1876
1877 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1878 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1879 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1880 turn_off_usb_ovp_fet(chip);
1881
1882 msleep(20);
1883
1884 turn_on_usb_ovp_fet(chip);
1885 } else {
1886 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1887 USB_OVP_DEBOUNCE_TIME, 0x1);
1888 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1889 count, chg_gone, usb_chg_plugged_in);
1890 return;
1891 }
1892 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001893}
David Keitelacf57c82012-03-07 18:48:50 -08001894
1895static int find_usb_ma_value(int value)
1896{
1897 int i;
1898
1899 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1900 if (value >= usb_ma_table[i].usb_ma)
1901 break;
1902 }
1903
1904 return i;
1905}
1906
1907static void decrease_usb_ma_value(int *value)
1908{
1909 int i;
1910
1911 if (value) {
1912 i = find_usb_ma_value(*value);
1913 if (i > 0)
1914 i--;
1915 *value = usb_ma_table[i].usb_ma;
1916 }
1917}
1918
1919static void increase_usb_ma_value(int *value)
1920{
1921 int i;
1922
1923 if (value) {
1924 i = find_usb_ma_value(*value);
1925
1926 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
1927 i++;
1928 *value = usb_ma_table[i].usb_ma;
1929 }
1930}
1931
1932static void vin_collapse_check_worker(struct work_struct *work)
1933{
1934 struct delayed_work *dwork = to_delayed_work(work);
1935 struct pm8921_chg_chip *chip = container_of(dwork,
1936 struct pm8921_chg_chip, vin_collapse_check_work);
1937
1938 /* AICL only for wall-chargers */
1939 if (is_usb_chg_plugged_in(chip) &&
1940 usb_target_ma > USB_WALL_THRESHOLD_MA) {
1941 /* decrease usb_target_ma */
1942 decrease_usb_ma_value(&usb_target_ma);
1943 /* reset here, increase in unplug_check_worker */
1944 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1945 pr_debug("usb_now=%d, usb_target = %d\n",
1946 USB_WALL_THRESHOLD_MA, usb_target_ma);
1947 } else {
1948 handle_usb_insertion_removal(chip);
1949 }
1950}
1951
1952#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1954{
David Keitelacf57c82012-03-07 18:48:50 -08001955 if (usb_target_ma)
1956 schedule_delayed_work(&the_chip->vin_collapse_check_work,
1957 round_jiffies_relative(msecs_to_jiffies
1958 (VIN_MIN_COLLAPSE_CHECK_MS)));
1959 else
1960 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 return IRQ_HANDLED;
1962}
1963
1964static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1965{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001966 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 return IRQ_HANDLED;
1968}
1969
1970static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1971{
1972 struct pm8921_chg_chip *chip = data;
1973 int status;
1974
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001975 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1976 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001977 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978 pr_debug("battery present=%d", status);
1979 power_supply_changed(&chip->batt_psy);
1980 return IRQ_HANDLED;
1981}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001982
1983/*
1984 * this interrupt used to restart charging a battery.
1985 *
1986 * Note: When DC-inserted the VBAT can't go low.
1987 * VPH_PWR is provided by the ext-charger.
1988 * After End-Of-Charging from DC, charging can be resumed only
1989 * if DC is removed and then inserted after the battery was in use.
1990 * Therefore the handle_start_ext_chg() is not called.
1991 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1993{
1994 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001995 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001997 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001998
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001999 if (high_transition) {
2000 /* enable auto charging */
2001 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002002 pr_info("batt fell below resume voltage %s\n",
2003 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002004 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 power_supply_changed(&chip->batt_psy);
2008 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002009 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002010
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 return IRQ_HANDLED;
2012}
2013
2014static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2015{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002016 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 return IRQ_HANDLED;
2018}
2019
2020static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2021{
2022 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2023 return IRQ_HANDLED;
2024}
2025
2026static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2027{
2028 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2029 return IRQ_HANDLED;
2030}
2031
2032static irqreturn_t vcp_irq_handler(int irq, void *data)
2033{
David Keitel8c5201a2012-02-24 16:08:54 -08002034 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002035 return IRQ_HANDLED;
2036}
2037
2038static irqreturn_t atcdone_irq_handler(int irq, void *data)
2039{
2040 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2041 return IRQ_HANDLED;
2042}
2043
2044static irqreturn_t atcfail_irq_handler(int irq, void *data)
2045{
2046 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2047 return IRQ_HANDLED;
2048}
2049
2050static irqreturn_t chgdone_irq_handler(int irq, void *data)
2051{
2052 struct pm8921_chg_chip *chip = data;
2053
2054 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002055
2056 handle_stop_ext_chg(chip);
2057
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 power_supply_changed(&chip->batt_psy);
2059 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002060 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002061
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002062 bms_notify_check(chip);
2063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 return IRQ_HANDLED;
2065}
2066
2067static irqreturn_t chgfail_irq_handler(int irq, void *data)
2068{
2069 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002070 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071
David Keitel753ec8d2011-11-02 10:56:37 -07002072 ret = pm_chg_failed_clear(chip, 1);
2073 if (ret)
2074 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2075
2076 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2077 get_prop_batt_present(chip),
2078 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2079 pm_chg_get_fsm_state(data));
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 power_supply_changed(&chip->batt_psy);
2082 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002083 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 return IRQ_HANDLED;
2085}
2086
2087static irqreturn_t chgstate_irq_handler(int irq, void *data)
2088{
2089 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090
2091 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2092 power_supply_changed(&chip->batt_psy);
2093 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002094 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002096 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 return IRQ_HANDLED;
2099}
2100
David Keitel8c5201a2012-02-24 16:08:54 -08002101static int param_vin_disable_counter = 5;
2102module_param(param_vin_disable_counter, int, 0644);
2103
2104static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2105 int count, int usb_ma)
2106{
David Keitelacf57c82012-03-07 18:48:50 -08002107 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002108 pr_debug("count = %d iusb=500mA\n", count);
2109 disable_input_voltage_regulation(chip);
2110 pr_debug("count = %d disable_input_regulation\n", count);
2111
2112 msleep(20);
2113
2114 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2115 count,
2116 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2117 is_usb_chg_plugged_in(chip));
2118 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2119 count, usb_ma);
2120 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002121 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002122}
2123
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002124#define VIN_ACTIVE_BIT BIT(0)
2125#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2126#define VIN_MIN_INCREASE_MV 100
2127static void unplug_check_worker(struct work_struct *work)
2128{
2129 struct delayed_work *dwork = to_delayed_work(work);
2130 struct pm8921_chg_chip *chip = container_of(dwork,
2131 struct pm8921_chg_chip, unplug_check_work);
2132 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002133 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002134 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002135
David Keitelacf57c82012-03-07 18:48:50 -08002136 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002137 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2138 if (!usb_chg_plugged_in) {
2139 pr_debug("Stopping Unplug Check Worker since USB is removed"
2140 "reg_loop = %d, fsm = %d ibat = %d\n",
2141 pm_chg_get_regulation_loop(chip),
2142 pm_chg_get_fsm_state(chip),
2143 get_prop_batt_current(chip)
2144 );
2145 return;
2146 }
David Keitel8c5201a2012-02-24 16:08:54 -08002147
2148 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002149 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002150 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2151 disable_input_voltage_regulation(chip);
2152 return;
2153 }
2154
2155 if (usb_ma <= 100) {
2156 pr_debug(
2157 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2158 usb_ma);
2159 goto check_again_later;
2160 }
2161 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2162 pr_debug("chg gone irq is enabled\n");
2163
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002164 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002165 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002166
2167 if (reg_loop & VIN_ACTIVE_BIT) {
David Keitelacf57c82012-03-07 18:48:50 -08002168 decrease_usb_ma_value(&usb_ma);
2169 usb_target_ma = usb_ma;
2170 /* end AICL here */
2171 __pm8921_charger_vbus_draw(usb_ma);
2172 pr_debug("usb_now=%d, usb_target = %d\n",
2173 usb_ma, usb_target_ma);
2174 }
2175
2176 reg_loop = pm_chg_get_regulation_loop(chip);
2177 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2178
2179 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002180 ibat = get_prop_batt_current(chip);
2181
2182 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2183 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2184 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002185 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002186
David Keitel8c5201a2012-02-24 16:08:54 -08002187 while (count++ < param_vin_disable_counter
2188 && usb_chg_plugged_in == 1) {
2189 attempt_reverse_boost_fix(chip, count, usb_ma);
2190 usb_chg_plugged_in
2191 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002192 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002193 }
2194 }
2195
David Keitel8c5201a2012-02-24 16:08:54 -08002196 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2197 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2198
2199 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2200 /* run the worker directly */
2201 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2202 chg_gone, usb_chg_plugged_in);
2203 schedule_work(&chip->unplug_ovp_fet_open_work);
2204 }
2205
David Keitelacf57c82012-03-07 18:48:50 -08002206 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2207 /* only increase iusb_max if vin loop not active */
2208 if (usb_ma < usb_target_ma) {
2209 increase_usb_ma_value(&usb_ma);
2210 __pm8921_charger_vbus_draw(usb_ma);
2211 pr_debug("usb_now=%d, usb_target = %d\n",
2212 usb_ma, usb_target_ma);
2213 } else {
2214 usb_target_ma = usb_ma;
2215 }
2216 }
David Keitel8c5201a2012-02-24 16:08:54 -08002217check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002218 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002219 schedule_delayed_work(&chip->unplug_check_work,
2220 round_jiffies_relative(msecs_to_jiffies
2221 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2222}
2223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224static irqreturn_t loop_change_irq_handler(int irq, void *data)
2225{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002226 struct pm8921_chg_chip *chip = data;
2227
2228 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2229 pm_chg_get_fsm_state(data),
2230 pm_chg_get_regulation_loop(data));
2231 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 return IRQ_HANDLED;
2233}
2234
2235static irqreturn_t fastchg_irq_handler(int irq, void *data)
2236{
2237 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002238 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002240 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2241 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2242 wake_lock(&chip->eoc_wake_lock);
2243 schedule_delayed_work(&chip->eoc_work,
2244 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002245 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002246 }
2247 power_supply_changed(&chip->batt_psy);
2248 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 return IRQ_HANDLED;
2250}
2251
2252static irqreturn_t trklchg_irq_handler(int irq, void *data)
2253{
2254 struct pm8921_chg_chip *chip = data;
2255
2256 power_supply_changed(&chip->batt_psy);
2257 return IRQ_HANDLED;
2258}
2259
2260static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2261{
2262 struct pm8921_chg_chip *chip = data;
2263 int status;
2264
2265 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2266 pr_debug("battery present=%d state=%d", !status,
2267 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002268 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 power_supply_changed(&chip->batt_psy);
2270 return IRQ_HANDLED;
2271}
2272
2273static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2274{
2275 struct pm8921_chg_chip *chip = data;
2276
Amir Samuelovd31ef502011-10-26 14:41:36 +02002277 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 power_supply_changed(&chip->batt_psy);
2279 return IRQ_HANDLED;
2280}
2281
2282static irqreturn_t chghot_irq_handler(int irq, void *data)
2283{
2284 struct pm8921_chg_chip *chip = data;
2285
2286 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2287 power_supply_changed(&chip->batt_psy);
2288 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002289 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290 return IRQ_HANDLED;
2291}
2292
2293static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2294{
2295 struct pm8921_chg_chip *chip = data;
2296
2297 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002298 handle_stop_ext_chg(chip);
2299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 power_supply_changed(&chip->batt_psy);
2301 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 return IRQ_HANDLED;
2303}
2304
2305static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2306{
2307 struct pm8921_chg_chip *chip = data;
David Keitel8c5201a2012-02-24 16:08:54 -08002308 int chg_gone, usb_chg_plugged_in;
2309
2310 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2311 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2312
2313 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2314 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315
2316 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2317 power_supply_changed(&chip->batt_psy);
2318 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 return IRQ_HANDLED;
2320}
David Keitel52fda532011-11-10 10:43:44 -08002321/*
2322 *
2323 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2324 * fire for two cases:
2325 *
2326 * If the interrupt line switches to high temperature is okay
2327 * and thus charging begins.
2328 * If bat_temp_ok is low this means the temperature is now
2329 * too hot or cold, so charging is stopped.
2330 *
2331 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2333{
David Keitel52fda532011-11-10 10:43:44 -08002334 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 struct pm8921_chg_chip *chip = data;
2336
David Keitel52fda532011-11-10 10:43:44 -08002337 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2338
2339 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2340 bat_temp_ok, pm_chg_get_fsm_state(data));
2341
2342 if (bat_temp_ok)
2343 handle_start_ext_chg(chip);
2344 else
2345 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 power_supply_changed(&chip->batt_psy);
2348 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002349 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002350 return IRQ_HANDLED;
2351}
2352
2353static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2354{
2355 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2356 return IRQ_HANDLED;
2357}
2358
2359static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2360{
2361 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2362 return IRQ_HANDLED;
2363}
2364
2365static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2366{
2367 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2368 return IRQ_HANDLED;
2369}
2370
2371static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2372{
2373 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2374 return IRQ_HANDLED;
2375}
2376
2377static irqreturn_t batfet_irq_handler(int irq, void *data)
2378{
2379 struct pm8921_chg_chip *chip = data;
2380
2381 pr_debug("vreg ov\n");
2382 power_supply_changed(&chip->batt_psy);
2383 return IRQ_HANDLED;
2384}
2385
2386static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2387{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002388 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002389 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002390
David Keitel88e1b572012-01-11 11:57:14 -08002391 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2392 if (chip->ext_psy)
2393 power_supply_set_online(chip->ext_psy, dc_present);
2394 chip->dc_present = dc_present;
2395 if (dc_present)
2396 handle_start_ext_chg(chip);
2397 else
2398 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 return IRQ_HANDLED;
2400}
2401
2402static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2403{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002404 struct pm8921_chg_chip *chip = data;
2405
Amir Samuelovd31ef502011-10-26 14:41:36 +02002406 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407 return IRQ_HANDLED;
2408}
2409
2410static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2411{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002412 struct pm8921_chg_chip *chip = data;
2413
Amir Samuelovd31ef502011-10-26 14:41:36 +02002414 handle_stop_ext_chg(chip);
2415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 return IRQ_HANDLED;
2417}
2418
David Keitel88e1b572012-01-11 11:57:14 -08002419static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2420{
2421 struct power_supply *psy = &the_chip->batt_psy;
2422 struct power_supply *epsy = dev_get_drvdata(dev);
2423 int i, dcin_irq;
2424
2425 /* Only search for external supply if none is registered */
2426 if (!the_chip->ext_psy) {
2427 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2428 for (i = 0; i < epsy->num_supplicants; i++) {
2429 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2430 if (!strncmp(epsy->name, "dc", 2)) {
2431 the_chip->ext_psy = epsy;
2432 dcin_valid_irq_handler(dcin_irq,
2433 the_chip);
2434 }
2435 }
2436 }
2437 }
2438 return 0;
2439}
2440
2441static void pm_batt_external_power_changed(struct power_supply *psy)
2442{
2443 /* Only look for an external supply if it hasn't been registered */
2444 if (!the_chip->ext_psy)
2445 class_for_each_device(power_supply_class, NULL, psy,
2446 __pm_batt_external_power_changed_work);
2447}
2448
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002449/**
2450 * update_heartbeat - internal function to update userspace
2451 * per update_time minutes
2452 *
2453 */
2454static void update_heartbeat(struct work_struct *work)
2455{
2456 struct delayed_work *dwork = to_delayed_work(work);
2457 struct pm8921_chg_chip *chip = container_of(dwork,
2458 struct pm8921_chg_chip, update_heartbeat_work);
2459
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002460 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002461 power_supply_changed(&chip->batt_psy);
2462 schedule_delayed_work(&chip->update_heartbeat_work,
2463 round_jiffies_relative(msecs_to_jiffies
2464 (chip->update_time)));
2465}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002466#define VDD_LOOP_ACTIVE_BIT BIT(3)
2467#define VDD_MAX_INCREASE_MV 400
2468static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2469module_param(vdd_max_increase_mv, int, 0644);
2470
2471static int ichg_threshold_ua = -400000;
2472module_param(ichg_threshold_ua, int, 0644);
2473static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2474{
2475 int ichg_meas_ua, vbat_uv;
2476 int ichg_meas_ma;
2477 int adj_vdd_max_mv, programmed_vdd_max;
2478 int vbat_batt_terminal_uv;
2479 int vbat_batt_terminal_mv;
2480 int reg_loop;
2481 int delta_mv = 0;
2482
2483 if (chip->rconn_mohm == 0) {
2484 pr_debug("Exiting as rconn_mohm is 0\n");
2485 return;
2486 }
2487 /* adjust vdd_max only in normal temperature zone */
2488 if (chip->is_bat_cool || chip->is_bat_warm) {
2489 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2490 chip->is_bat_cool, chip->is_bat_warm);
2491 return;
2492 }
2493
2494 reg_loop = pm_chg_get_regulation_loop(chip);
2495 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2496 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2497 reg_loop);
2498 return;
2499 }
2500
2501 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2502 &vbat_uv);
2503 if (ichg_meas_ua >= 0) {
2504 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2505 return;
2506 }
2507 if (ichg_meas_ua <= ichg_threshold_ua) {
2508 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2509 ichg_meas_ua, ichg_threshold_ua);
2510 return;
2511 }
2512 ichg_meas_ma = ichg_meas_ua / 1000;
2513
2514 /* rconn_mohm is in milliOhms */
2515 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2516 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2517 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2518
2519 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2520
2521 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2522 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2523 delta_mv,
2524 programmed_vdd_max,
2525 adj_vdd_max_mv);
2526
2527 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2528 pr_debug("adj vdd_max lower than default max voltage\n");
2529 return;
2530 }
2531
2532 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2533 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2534
2535 pr_debug("adjusting vdd_max_mv to %d to make "
2536 "vbat_batt_termial_uv = %d to %d\n",
2537 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2538 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2539}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002540
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002541enum {
2542 CHG_IN_PROGRESS,
2543 CHG_NOT_IN_PROGRESS,
2544 CHG_FINISHED,
2545};
2546
2547#define VBAT_TOLERANCE_MV 70
2548#define CHG_DISABLE_MSLEEP 100
2549static int is_charging_finished(struct pm8921_chg_chip *chip)
2550{
2551 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2552 int ichg_meas_ma, iterm_programmed;
2553 int regulation_loop, fast_chg, vcp;
2554 int rc;
2555 static int last_vbat_programmed = -EINVAL;
2556
2557 if (!is_ext_charging(chip)) {
2558 /* return if the battery is not being fastcharged */
2559 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2560 pr_debug("fast_chg = %d\n", fast_chg);
2561 if (fast_chg == 0)
2562 return CHG_NOT_IN_PROGRESS;
2563
2564 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2565 pr_debug("vcp = %d\n", vcp);
2566 if (vcp == 1)
2567 return CHG_IN_PROGRESS;
2568
2569 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2570 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2571 if (vbatdet_low == 1)
2572 return CHG_IN_PROGRESS;
2573
2574 /* reset count if battery is hot/cold */
2575 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2576 pr_debug("batt_temp_ok = %d\n", rc);
2577 if (rc == 0)
2578 return CHG_IN_PROGRESS;
2579
2580 /* reset count if battery voltage is less than vddmax */
2581 vbat_meas_uv = get_prop_battery_uvolts(chip);
2582 if (vbat_meas_uv < 0)
2583 return CHG_IN_PROGRESS;
2584 vbat_meas_mv = vbat_meas_uv / 1000;
2585
2586 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2587 if (rc) {
2588 pr_err("couldnt read vddmax rc = %d\n", rc);
2589 return CHG_IN_PROGRESS;
2590 }
2591 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2592 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002593
2594 if (last_vbat_programmed == -EINVAL)
2595 last_vbat_programmed = vbat_programmed;
2596 if (last_vbat_programmed != vbat_programmed) {
2597 /* vddmax changed, reset and check again */
2598 pr_debug("vddmax = %d last_vdd_max=%d\n",
2599 vbat_programmed, last_vbat_programmed);
2600 last_vbat_programmed = vbat_programmed;
2601 return CHG_IN_PROGRESS;
2602 }
2603
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002604 regulation_loop = pm_chg_get_regulation_loop(chip);
2605 if (regulation_loop < 0) {
2606 pr_err("couldnt read the regulation loop err=%d\n",
2607 regulation_loop);
2608 return CHG_IN_PROGRESS;
2609 }
2610 pr_debug("regulation_loop=%d\n", regulation_loop);
2611
2612 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2613 return CHG_IN_PROGRESS;
2614 } /* !is_ext_charging */
2615
2616 /* reset count if battery chg current is more than iterm */
2617 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2618 if (rc) {
2619 pr_err("couldnt read iterm rc = %d\n", rc);
2620 return CHG_IN_PROGRESS;
2621 }
2622
2623 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2624 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2625 iterm_programmed, ichg_meas_ma);
2626 /*
2627 * ichg_meas_ma < 0 means battery is drawing current
2628 * ichg_meas_ma > 0 means battery is providing current
2629 */
2630 if (ichg_meas_ma > 0)
2631 return CHG_IN_PROGRESS;
2632
2633 if (ichg_meas_ma * -1 > iterm_programmed)
2634 return CHG_IN_PROGRESS;
2635
2636 return CHG_FINISHED;
2637}
2638
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002639/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002640 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002641 * has happened
2642 *
2643 * If all conditions favouring, if the charge current is
2644 * less than the term current for three consecutive times
2645 * an EOC has happened.
2646 * The wakelock is released if there is no need to reshedule
2647 * - this happens when the battery is removed or EOC has
2648 * happened
2649 */
2650#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002651static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002652{
2653 struct delayed_work *dwork = to_delayed_work(work);
2654 struct pm8921_chg_chip *chip = container_of(dwork,
2655 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002656 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002657 int end;
2658
2659 pm_chg_failed_clear(chip, 1);
2660 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002661
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002662 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002663 count = 0;
2664 wake_unlock(&chip->eoc_wake_lock);
2665 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002666 }
2667
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002668 if (end == CHG_FINISHED) {
2669 count++;
2670 } else {
2671 count = 0;
2672 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002673
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002674 if (count == CONSECUTIVE_COUNT) {
2675 count = 0;
2676 pr_info("End of Charging\n");
2677
2678 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002679
Amir Samuelovd31ef502011-10-26 14:41:36 +02002680 if (is_ext_charging(chip))
2681 chip->ext_charge_done = true;
2682
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002683 if (chip->is_bat_warm || chip->is_bat_cool)
2684 chip->bms_notify.is_battery_full = 0;
2685 else
2686 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002687 /* declare end of charging by invoking chgdone interrupt */
2688 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2689 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002690 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002691 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002692 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002693 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002694 round_jiffies_relative(msecs_to_jiffies
2695 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002696 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002697}
2698
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002699static void btm_configure_work(struct work_struct *work)
2700{
2701 int rc;
2702
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002703 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002704 if (rc)
2705 pr_err("failed to configure btm rc=%d", rc);
2706}
2707
2708DECLARE_WORK(btm_config_work, btm_configure_work);
2709
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002710static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2711{
2712 unsigned int chg_current = chip->max_bat_chg_current;
2713
2714 if (chip->is_bat_cool)
2715 chg_current = min(chg_current, chip->cool_bat_chg_current);
2716
2717 if (chip->is_bat_warm)
2718 chg_current = min(chg_current, chip->warm_bat_chg_current);
2719
David Keitelfdef3a42011-12-14 19:02:54 -08002720 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002721 chg_current = min(chg_current,
2722 chip->thermal_mitigation[thermal_mitigation]);
2723
2724 pm_chg_ibatmax_set(the_chip, chg_current);
2725}
2726
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002727#define TEMP_HYSTERISIS_DEGC 2
2728static void battery_cool(bool enter)
2729{
2730 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002731 if (enter == the_chip->is_bat_cool)
2732 return;
2733 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002734 if (enter) {
2735 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002736 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002737 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002738 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002739 pm_chg_vbatdet_set(the_chip,
2740 the_chip->cool_bat_voltage
2741 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002742 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002743 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002744 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002745 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002746 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002747 the_chip->max_voltage_mv
2748 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002749 }
2750 schedule_work(&btm_config_work);
2751}
2752
2753static void battery_warm(bool enter)
2754{
2755 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002756 if (enter == the_chip->is_bat_warm)
2757 return;
2758 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002759 if (enter) {
2760 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002761 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002762 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002763 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002764 pm_chg_vbatdet_set(the_chip,
2765 the_chip->warm_bat_voltage
2766 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002767 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002768 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002769 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002770 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002771 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002772 the_chip->max_voltage_mv
2773 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002774 }
2775 schedule_work(&btm_config_work);
2776}
2777
2778static int configure_btm(struct pm8921_chg_chip *chip)
2779{
2780 int rc;
2781
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002782 if (chip->warm_temp_dc != INT_MIN)
2783 btm_config.btm_warm_fn = battery_warm;
2784 else
2785 btm_config.btm_warm_fn = NULL;
2786
2787 if (chip->cool_temp_dc != INT_MIN)
2788 btm_config.btm_cool_fn = battery_cool;
2789 else
2790 btm_config.btm_cool_fn = NULL;
2791
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002792 btm_config.low_thr_temp = chip->cool_temp_dc;
2793 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002794 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002795 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002796 if (rc)
2797 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002798 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002799 if (rc)
2800 pr_err("failed to start btm rc = %d\n", rc);
2801
2802 return rc;
2803}
2804
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002805/**
2806 * set_disable_status_param -
2807 *
2808 * Internal function to disable battery charging and also disable drawing
2809 * any current from the source. The device is forced to run on a battery
2810 * after this.
2811 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812static int set_disable_status_param(const char *val, struct kernel_param *kp)
2813{
2814 int ret;
2815 struct pm8921_chg_chip *chip = the_chip;
2816
2817 ret = param_set_int(val, kp);
2818 if (ret) {
2819 pr_err("error setting value %d\n", ret);
2820 return ret;
2821 }
2822 pr_info("factory set disable param to %d\n", charging_disabled);
2823 if (chip) {
2824 pm_chg_auto_enable(chip, !charging_disabled);
2825 pm_chg_charge_dis(chip, charging_disabled);
2826 }
2827 return 0;
2828}
2829module_param_call(disabled, set_disable_status_param, param_get_uint,
2830 &charging_disabled, 0644);
2831
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002832static int rconn_mohm;
2833static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2834{
2835 int ret;
2836 struct pm8921_chg_chip *chip = the_chip;
2837
2838 ret = param_set_int(val, kp);
2839 if (ret) {
2840 pr_err("error setting value %d\n", ret);
2841 return ret;
2842 }
2843 if (chip)
2844 chip->rconn_mohm = rconn_mohm;
2845 return 0;
2846}
2847module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2848 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002849/**
2850 * set_thermal_mitigation_level -
2851 *
2852 * Internal function to control battery charging current to reduce
2853 * temperature
2854 */
2855static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2856{
2857 int ret;
2858 struct pm8921_chg_chip *chip = the_chip;
2859
2860 ret = param_set_int(val, kp);
2861 if (ret) {
2862 pr_err("error setting value %d\n", ret);
2863 return ret;
2864 }
2865
2866 if (!chip) {
2867 pr_err("called before init\n");
2868 return -EINVAL;
2869 }
2870
2871 if (!chip->thermal_mitigation) {
2872 pr_err("no thermal mitigation\n");
2873 return -EINVAL;
2874 }
2875
2876 if (thermal_mitigation < 0
2877 || thermal_mitigation >= chip->thermal_levels) {
2878 pr_err("out of bound level selected\n");
2879 return -EINVAL;
2880 }
2881
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002882 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002883 return ret;
2884}
2885module_param_call(thermal_mitigation, set_therm_mitigation_level,
2886 param_get_uint,
2887 &thermal_mitigation, 0644);
2888
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002889static int set_usb_max_current(const char *val, struct kernel_param *kp)
2890{
2891 int ret, mA;
2892 struct pm8921_chg_chip *chip = the_chip;
2893
2894 ret = param_set_int(val, kp);
2895 if (ret) {
2896 pr_err("error setting value %d\n", ret);
2897 return ret;
2898 }
2899 if (chip) {
2900 pr_warn("setting current max to %d\n", usb_max_current);
2901 pm_chg_iusbmax_get(chip, &mA);
2902 if (mA > usb_max_current)
2903 pm8921_charger_vbus_draw(usb_max_current);
2904 return 0;
2905 }
2906 return -EINVAL;
2907}
David Keitelacf57c82012-03-07 18:48:50 -08002908module_param_call(usb_max_current, set_usb_max_current,
2909 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002910
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911static void free_irqs(struct pm8921_chg_chip *chip)
2912{
2913 int i;
2914
2915 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2916 if (chip->pmic_chg_irq[i]) {
2917 free_irq(chip->pmic_chg_irq[i], chip);
2918 chip->pmic_chg_irq[i] = 0;
2919 }
2920}
2921
David Keitel88e1b572012-01-11 11:57:14 -08002922/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2924{
2925 unsigned long flags;
2926 int fsm_state;
2927
2928 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2929 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2930
2931 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002932 if (chip->usb_present) {
2933 schedule_delayed_work(&chip->unplug_check_work,
2934 round_jiffies_relative(msecs_to_jiffies
2935 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002936 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002937 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938
2939 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2940 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2941 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002942 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2943 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2944 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2945 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2946 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002947 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002948 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2949 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002950 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951
2952 spin_lock_irqsave(&vbus_lock, flags);
2953 if (usb_chg_current) {
2954 /* reissue a vbus draw call */
2955 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002956 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957 }
2958 spin_unlock_irqrestore(&vbus_lock, flags);
2959
2960 fsm_state = pm_chg_get_fsm_state(chip);
2961 if (is_battery_charging(fsm_state)) {
2962 chip->bms_notify.is_charging = 1;
2963 pm8921_bms_charging_began();
2964 }
2965
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002966 check_battery_valid(chip);
2967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2969 chip->usb_present,
2970 chip->dc_present,
2971 get_prop_batt_present(chip),
2972 fsm_state);
2973}
2974
2975struct pm_chg_irq_init_data {
2976 unsigned int irq_id;
2977 char *name;
2978 unsigned long flags;
2979 irqreturn_t (*handler)(int, void *);
2980};
2981
2982#define CHG_IRQ(_id, _flags, _handler) \
2983{ \
2984 .irq_id = _id, \
2985 .name = #_id, \
2986 .flags = _flags, \
2987 .handler = _handler, \
2988}
2989struct pm_chg_irq_init_data chg_irq_data[] = {
2990 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2991 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002992 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2994 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002995 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2996 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2998 usbin_uv_irq_handler),
2999 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3000 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3001 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3002 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3003 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3004 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3005 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3006 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3007 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003008 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3009 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3011 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3012 batt_removed_irq_handler),
3013 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3014 batttemp_hot_irq_handler),
3015 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3016 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3017 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003018 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3019 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003020 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3021 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3023 coarse_det_low_irq_handler),
3024 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3025 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3026 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3027 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3028 batfet_irq_handler),
3029 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3030 dcin_valid_irq_handler),
3031 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3032 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003033 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034};
3035
3036static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3037 struct platform_device *pdev)
3038{
3039 struct resource *res;
3040 int ret, i;
3041
3042 ret = 0;
3043 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3044
3045 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3046 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3047 chg_irq_data[i].name);
3048 if (res == NULL) {
3049 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3050 goto err_out;
3051 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003052 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 ret = request_irq(res->start, chg_irq_data[i].handler,
3054 chg_irq_data[i].flags,
3055 chg_irq_data[i].name, chip);
3056 if (ret < 0) {
3057 pr_err("couldn't request %d (%s) %d\n", res->start,
3058 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003059 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 goto err_out;
3061 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3063 }
3064 return 0;
3065
3066err_out:
3067 free_irqs(chip);
3068 return -EINVAL;
3069}
3070
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003071static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3072{
3073 int err;
3074 u8 temp;
3075
3076 temp = 0xD1;
3077 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3078 if (err) {
3079 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3080 return;
3081 }
3082
3083 temp = 0xD3;
3084 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3085 if (err) {
3086 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3087 return;
3088 }
3089
3090 temp = 0xD1;
3091 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3092 if (err) {
3093 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3094 return;
3095 }
3096
3097 temp = 0xD5;
3098 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3099 if (err) {
3100 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3101 return;
3102 }
3103
3104 udelay(183);
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 = 0xD0;
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 udelay(32);
3120
3121 temp = 0xD1;
3122 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3123 if (err) {
3124 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3125 return;
3126 }
3127
3128 temp = 0xD3;
3129 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3130 if (err) {
3131 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3132 return;
3133 }
3134}
3135
3136static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3137{
3138 int err;
3139 u8 temp;
3140
3141 temp = 0xD1;
3142 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3143 if (err) {
3144 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3145 return;
3146 }
3147
3148 temp = 0xD0;
3149 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3150 if (err) {
3151 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3152 return;
3153 }
3154}
3155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156#define ENUM_TIMER_STOP_BIT BIT(1)
3157#define BOOT_DONE_BIT BIT(6)
3158#define CHG_BATFET_ON_BIT BIT(3)
3159#define CHG_VCP_EN BIT(0)
3160#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3161#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003162#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3164{
3165 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003166 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167
3168 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3169 BOOT_DONE_BIT, BOOT_DONE_BIT);
3170 if (rc) {
3171 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3172 return rc;
3173 }
3174
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003175 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3176
3177 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3178 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3179
3180 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182 if (rc) {
3183 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003184 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185 return rc;
3186 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003187 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003188 chip->max_voltage_mv
3189 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 if (rc) {
3191 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003192 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 return rc;
3194 }
3195
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003196 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003197 if (rc) {
3198 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003199 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 return rc;
3201 }
3202 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3203 if (rc) {
3204 pr_err("Failed to set max voltage to %d rc=%d\n",
3205 SAFE_CURRENT_MA, rc);
3206 return rc;
3207 }
3208
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003209 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210 if (rc) {
3211 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3212 return rc;
3213 }
3214
3215 rc = pm_chg_iterm_set(chip, chip->term_current);
3216 if (rc) {
3217 pr_err("Failed to set term current to %d rc=%d\n",
3218 chip->term_current, rc);
3219 return rc;
3220 }
3221
3222 /* Disable the ENUM TIMER */
3223 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3224 ENUM_TIMER_STOP_BIT);
3225 if (rc) {
3226 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3227 return rc;
3228 }
3229
3230 /* init with the lowest USB current */
David Keitelacf57c82012-03-07 18:48:50 -08003231 rc = pm_chg_iusbmax_set(chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08003233 pr_err("Failed to set usb max to %d rc=%d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234 return rc;
3235 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003236
3237 if (chip->safety_time != 0) {
3238 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3239 if (rc) {
3240 pr_err("Failed to set max time to %d minutes rc=%d\n",
3241 chip->safety_time, rc);
3242 return rc;
3243 }
3244 }
3245
3246 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003247 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003248 if (rc) {
3249 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3250 chip->safety_time, rc);
3251 return rc;
3252 }
3253 }
3254
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003255 if (chip->vin_min != 0) {
3256 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3257 if (rc) {
3258 pr_err("Failed to set vin min to %d mV rc=%d\n",
3259 chip->vin_min, rc);
3260 return rc;
3261 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003262 } else {
3263 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003264 }
3265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 rc = pm_chg_disable_wd(chip);
3267 if (rc) {
3268 pr_err("Failed to disable wd rc=%d\n", rc);
3269 return rc;
3270 }
3271
3272 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3273 CHG_BAT_TEMP_DIS_BIT, 0);
3274 if (rc) {
3275 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3276 return rc;
3277 }
3278 /* switch to a 3.2Mhz for the buck */
3279 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3280 if (rc) {
3281 pr_err("Failed to switch buck clk rc=%d\n", rc);
3282 return rc;
3283 }
3284
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003285 if (chip->trkl_voltage != 0) {
3286 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3287 if (rc) {
3288 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3289 chip->trkl_voltage, rc);
3290 return rc;
3291 }
3292 }
3293
3294 if (chip->weak_voltage != 0) {
3295 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3296 if (rc) {
3297 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3298 chip->weak_voltage, rc);
3299 return rc;
3300 }
3301 }
3302
3303 if (chip->trkl_current != 0) {
3304 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3305 if (rc) {
3306 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3307 chip->trkl_voltage, rc);
3308 return rc;
3309 }
3310 }
3311
3312 if (chip->weak_current != 0) {
3313 rc = pm_chg_iweak_set(chip, chip->weak_current);
3314 if (rc) {
3315 pr_err("Failed to set weak current to %dmA rc=%d\n",
3316 chip->weak_current, rc);
3317 return rc;
3318 }
3319 }
3320
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003321 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3322 if (rc) {
3323 pr_err("Failed to set cold config %d rc=%d\n",
3324 chip->cold_thr, rc);
3325 }
3326
3327 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3328 if (rc) {
3329 pr_err("Failed to set hot config %d rc=%d\n",
3330 chip->hot_thr, rc);
3331 }
3332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003333 /* Workarounds for die 1.1 and 1.0 */
3334 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3335 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003336 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3337 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003338
3339 /* software workaround for correct battery_id detection */
3340 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3341 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3342 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3343 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3344 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3345 udelay(100);
3346 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347 }
3348
David Keitelb51995e2011-11-18 17:03:31 -08003349 /* Workarounds for die 3.0 */
3350 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3351 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3352
3353 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3354
David Keitela3c0d822011-11-03 14:18:52 -07003355 /* Disable EOC FSM processing */
3356 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3357
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003358 pm8921_chg_force_19p2mhz_clk(chip);
3359
3360 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3361 VREF_BATT_THERM_FORCE_ON);
3362 if (rc)
3363 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3364
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003365 rc = pm_chg_charge_dis(chip, charging_disabled);
3366 if (rc) {
3367 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3368 return rc;
3369 }
3370
3371 rc = pm_chg_auto_enable(chip, !charging_disabled);
3372 if (rc) {
3373 pr_err("Failed to enable charging rc=%d\n", rc);
3374 return rc;
3375 }
3376
3377 return 0;
3378}
3379
3380static int get_rt_status(void *data, u64 * val)
3381{
3382 int i = (int)data;
3383 int ret;
3384
3385 /* global irq number is passed in via data */
3386 ret = pm_chg_get_rt_status(the_chip, i);
3387 *val = ret;
3388 return 0;
3389}
3390DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3391
3392static int get_fsm_status(void *data, u64 * val)
3393{
3394 u8 temp;
3395
3396 temp = pm_chg_get_fsm_state(the_chip);
3397 *val = temp;
3398 return 0;
3399}
3400DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3401
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003402static int get_reg_loop(void *data, u64 * val)
3403{
3404 u8 temp;
3405
3406 if (!the_chip) {
3407 pr_err("%s called before init\n", __func__);
3408 return -EINVAL;
3409 }
3410 temp = pm_chg_get_regulation_loop(the_chip);
3411 *val = temp;
3412 return 0;
3413}
3414DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003416static int get_reg(void *data, u64 * val)
3417{
3418 int addr = (int)data;
3419 int ret;
3420 u8 temp;
3421
3422 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3423 if (ret) {
3424 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3425 addr, temp, ret);
3426 return -EAGAIN;
3427 }
3428 *val = temp;
3429 return 0;
3430}
3431
3432static int set_reg(void *data, u64 val)
3433{
3434 int addr = (int)data;
3435 int ret;
3436 u8 temp;
3437
3438 temp = (u8) val;
3439 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3440 if (ret) {
3441 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3442 addr, temp, ret);
3443 return -EAGAIN;
3444 }
3445 return 0;
3446}
3447DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3448
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003449enum {
3450 BAT_WARM_ZONE,
3451 BAT_COOL_ZONE,
3452};
3453static int get_warm_cool(void *data, u64 * val)
3454{
3455 if (!the_chip) {
3456 pr_err("%s called before init\n", __func__);
3457 return -EINVAL;
3458 }
3459 if ((int)data == BAT_WARM_ZONE)
3460 *val = the_chip->is_bat_warm;
3461 if ((int)data == BAT_COOL_ZONE)
3462 *val = the_chip->is_bat_cool;
3463 return 0;
3464}
3465DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3468{
3469 int i;
3470
3471 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3472
3473 if (IS_ERR(chip->dent)) {
3474 pr_err("pmic charger couldnt create debugfs dir\n");
3475 return;
3476 }
3477
3478 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3479 (void *)CHG_CNTRL, &reg_fops);
3480 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3481 (void *)CHG_CNTRL_2, &reg_fops);
3482 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3483 (void *)CHG_CNTRL_3, &reg_fops);
3484 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3485 (void *)PBL_ACCESS1, &reg_fops);
3486 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3487 (void *)PBL_ACCESS2, &reg_fops);
3488 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3489 (void *)SYS_CONFIG_1, &reg_fops);
3490 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3491 (void *)SYS_CONFIG_2, &reg_fops);
3492 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3493 (void *)CHG_VDD_MAX, &reg_fops);
3494 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3495 (void *)CHG_VDD_SAFE, &reg_fops);
3496 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3497 (void *)CHG_VBAT_DET, &reg_fops);
3498 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3499 (void *)CHG_IBAT_MAX, &reg_fops);
3500 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3501 (void *)CHG_IBAT_SAFE, &reg_fops);
3502 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3503 (void *)CHG_VIN_MIN, &reg_fops);
3504 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3505 (void *)CHG_VTRICKLE, &reg_fops);
3506 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3507 (void *)CHG_ITRICKLE, &reg_fops);
3508 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3509 (void *)CHG_ITERM, &reg_fops);
3510 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3511 (void *)CHG_TCHG_MAX, &reg_fops);
3512 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3513 (void *)CHG_TWDOG, &reg_fops);
3514 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3515 (void *)CHG_TEMP_THRESH, &reg_fops);
3516 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3517 (void *)CHG_COMP_OVR, &reg_fops);
3518 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3519 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3520 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3521 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3522 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3523 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3524 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3525 (void *)CHG_TEST, &reg_fops);
3526
3527 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3528 &fsm_fops);
3529
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003530 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3531 &reg_loop_fops);
3532
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003533 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3534 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3535 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3536 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003538 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3539 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3540 debugfs_create_file(chg_irq_data[i].name, 0444,
3541 chip->dent,
3542 (void *)chg_irq_data[i].irq_id,
3543 &rt_fops);
3544 }
3545}
3546
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003547static int pm8921_charger_suspend_noirq(struct device *dev)
3548{
3549 int rc;
3550 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3551
3552 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3553 if (rc)
3554 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3555 pm8921_chg_set_hw_clk_switching(chip);
3556 return 0;
3557}
3558
3559static int pm8921_charger_resume_noirq(struct device *dev)
3560{
3561 int rc;
3562 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3563
3564 pm8921_chg_force_19p2mhz_clk(chip);
3565
3566 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3567 VREF_BATT_THERM_FORCE_ON);
3568 if (rc)
3569 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3570 return 0;
3571}
3572
David Keitelf2226022011-12-13 15:55:50 -08003573static int pm8921_charger_resume(struct device *dev)
3574{
3575 int rc;
3576 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3577
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003578 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003579 && !(chip->keep_btm_on_suspend)) {
3580 rc = pm8xxx_adc_btm_configure(&btm_config);
3581 if (rc)
3582 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3583
3584 rc = pm8xxx_adc_btm_start();
3585 if (rc)
3586 pr_err("couldn't restart btm rc=%d\n", rc);
3587 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003588 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3589 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3590 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3591 }
David Keitelf2226022011-12-13 15:55:50 -08003592 return 0;
3593}
3594
3595static int pm8921_charger_suspend(struct device *dev)
3596{
3597 int rc;
3598 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3599
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003600 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003601 && !(chip->keep_btm_on_suspend)) {
3602 rc = pm8xxx_adc_btm_end();
3603 if (rc)
3604 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3605 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003606
3607 if (is_usb_chg_plugged_in(chip)) {
3608 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3609 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3610 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003611
David Keitelf2226022011-12-13 15:55:50 -08003612 return 0;
3613}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003614static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3615{
3616 int rc = 0;
3617 struct pm8921_chg_chip *chip;
3618 const struct pm8921_charger_platform_data *pdata
3619 = pdev->dev.platform_data;
3620
3621 if (!pdata) {
3622 pr_err("missing platform data\n");
3623 return -EINVAL;
3624 }
3625
3626 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3627 GFP_KERNEL);
3628 if (!chip) {
3629 pr_err("Cannot allocate pm_chg_chip\n");
3630 return -ENOMEM;
3631 }
3632
3633 chip->dev = &pdev->dev;
3634 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003635 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003637 chip->max_voltage_mv = pdata->max_voltage;
3638 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003639 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003640 chip->term_current = pdata->term_current;
3641 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003642 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003643 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3644 chip->batt_id_min = pdata->batt_id_min;
3645 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003646 if (pdata->cool_temp != INT_MIN)
3647 chip->cool_temp_dc = pdata->cool_temp * 10;
3648 else
3649 chip->cool_temp_dc = INT_MIN;
3650
3651 if (pdata->warm_temp != INT_MIN)
3652 chip->warm_temp_dc = pdata->warm_temp * 10;
3653 else
3654 chip->warm_temp_dc = INT_MIN;
3655
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003656 chip->temp_check_period = pdata->temp_check_period;
3657 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3658 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3659 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3660 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3661 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003662 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003663 chip->trkl_voltage = pdata->trkl_voltage;
3664 chip->weak_voltage = pdata->weak_voltage;
3665 chip->trkl_current = pdata->trkl_current;
3666 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003667 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003668 chip->thermal_mitigation = pdata->thermal_mitigation;
3669 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003671 chip->cold_thr = pdata->cold_thr;
3672 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003673 chip->rconn_mohm = pdata->rconn_mohm;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003674
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003675 rc = pm8921_chg_hw_init(chip);
3676 if (rc) {
3677 pr_err("couldn't init hardware rc=%d\n", rc);
3678 goto free_chip;
3679 }
3680
3681 chip->usb_psy.name = "usb",
3682 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3683 chip->usb_psy.supplied_to = pm_power_supplied_to,
3684 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003685 chip->usb_psy.properties = pm_power_props_usb,
3686 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3687 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688
David Keitel6ed71a52012-01-30 12:42:18 -08003689 chip->dc_psy.name = "pm8921-dc",
3690 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3691 chip->dc_psy.supplied_to = pm_power_supplied_to,
3692 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003693 chip->dc_psy.properties = pm_power_props_mains,
3694 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3695 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003697 chip->batt_psy.name = "battery",
3698 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3699 chip->batt_psy.properties = msm_batt_power_props,
3700 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3701 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003702 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 rc = power_supply_register(chip->dev, &chip->usb_psy);
3704 if (rc < 0) {
3705 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003706 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003707 }
3708
David Keitel6ed71a52012-01-30 12:42:18 -08003709 rc = power_supply_register(chip->dev, &chip->dc_psy);
3710 if (rc < 0) {
3711 pr_err("power_supply_register usb failed rc = %d\n", rc);
3712 goto unregister_usb;
3713 }
3714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 rc = power_supply_register(chip->dev, &chip->batt_psy);
3716 if (rc < 0) {
3717 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003718 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003719 }
3720
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003721 platform_set_drvdata(pdev, chip);
3722 the_chip = chip;
3723
3724 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003725 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003726 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3727 vin_collapse_check_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003728 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3729 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003730 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003732 rc = request_irqs(chip, pdev);
3733 if (rc) {
3734 pr_err("couldn't register interrupts rc=%d\n", rc);
3735 goto unregister_batt;
3736 }
3737
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003738 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3739 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3740 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003741 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3742 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003743 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003744 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003745 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003746 * care for jeita compliance
3747 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003748 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003749 rc = configure_btm(chip);
3750 if (rc) {
3751 pr_err("couldn't register with btm rc=%d\n", rc);
3752 goto free_irq;
3753 }
3754 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756 create_debugfs_entries(chip);
3757
3758 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003759 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761 /* determine what state the charger is in */
3762 determine_initial_state(chip);
3763
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003764 if (chip->update_time) {
3765 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3766 update_heartbeat);
3767 schedule_delayed_work(&chip->update_heartbeat_work,
3768 round_jiffies_relative(msecs_to_jiffies
3769 (chip->update_time)));
3770 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 return 0;
3772
3773free_irq:
3774 free_irqs(chip);
3775unregister_batt:
3776 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003777unregister_dc:
3778 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779unregister_usb:
3780 power_supply_unregister(&chip->usb_psy);
3781free_chip:
3782 kfree(chip);
3783 return rc;
3784}
3785
3786static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3787{
3788 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3789
3790 free_irqs(chip);
3791 platform_set_drvdata(pdev, NULL);
3792 the_chip = NULL;
3793 kfree(chip);
3794 return 0;
3795}
David Keitelf2226022011-12-13 15:55:50 -08003796static const struct dev_pm_ops pm8921_pm_ops = {
3797 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003798 .suspend_noirq = pm8921_charger_suspend_noirq,
3799 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003800 .resume = pm8921_charger_resume,
3801};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003803 .probe = pm8921_charger_probe,
3804 .remove = __devexit_p(pm8921_charger_remove),
3805 .driver = {
3806 .name = PM8921_CHARGER_DEV_NAME,
3807 .owner = THIS_MODULE,
3808 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 },
3810};
3811
3812static int __init pm8921_charger_init(void)
3813{
3814 return platform_driver_register(&pm8921_charger_driver);
3815}
3816
3817static void __exit pm8921_charger_exit(void)
3818{
3819 platform_driver_unregister(&pm8921_charger_driver);
3820}
3821
3822late_initcall(pm8921_charger_init);
3823module_exit(pm8921_charger_exit);
3824
3825MODULE_LICENSE("GPL v2");
3826MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3827MODULE_VERSION("1.0");
3828MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);