blob: a74459dd75aed86542b6e1b351edbcbfd72ecd9f [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
roy.park94dc2002012-06-19 12:14:46 -070034#ifdef CONFIG_LGE_PM_BATTERY_ID_CHECKER
35#include <mach/board_lge.h>
36#endif
37
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#define CHG_BUCK_CLOCK_CTRL 0x14
39
40#define PBL_ACCESS1 0x04
41#define PBL_ACCESS2 0x05
42#define SYS_CONFIG_1 0x06
43#define SYS_CONFIG_2 0x07
44#define CHG_CNTRL 0x204
45#define CHG_IBAT_MAX 0x205
46#define CHG_TEST 0x206
47#define CHG_BUCK_CTRL_TEST1 0x207
48#define CHG_BUCK_CTRL_TEST2 0x208
49#define CHG_BUCK_CTRL_TEST3 0x209
50#define COMPARATOR_OVERRIDE 0x20A
51#define PSI_TXRX_SAMPLE_DATA_0 0x20B
52#define PSI_TXRX_SAMPLE_DATA_1 0x20C
53#define PSI_TXRX_SAMPLE_DATA_2 0x20D
54#define PSI_TXRX_SAMPLE_DATA_3 0x20E
55#define PSI_CONFIG_STATUS 0x20F
56#define CHG_IBAT_SAFE 0x210
57#define CHG_ITRICKLE 0x211
58#define CHG_CNTRL_2 0x212
59#define CHG_VBAT_DET 0x213
60#define CHG_VTRICKLE 0x214
61#define CHG_ITERM 0x215
62#define CHG_CNTRL_3 0x216
63#define CHG_VIN_MIN 0x217
64#define CHG_TWDOG 0x218
65#define CHG_TTRKL_MAX 0x219
66#define CHG_TEMP_THRESH 0x21A
67#define CHG_TCHG_MAX 0x21B
68#define USB_OVP_CONTROL 0x21C
69#define DC_OVP_CONTROL 0x21D
70#define USB_OVP_TEST 0x21E
71#define DC_OVP_TEST 0x21F
72#define CHG_VDD_MAX 0x220
73#define CHG_VDD_SAFE 0x221
74#define CHG_VBAT_BOOT_THRESH 0x222
75#define USB_OVP_TRIM 0x355
76#define BUCK_CONTROL_TRIM1 0x356
77#define BUCK_CONTROL_TRIM2 0x357
78#define BUCK_CONTROL_TRIM3 0x358
79#define BUCK_CONTROL_TRIM4 0x359
80#define CHG_DEFAULTS_TRIM 0x35A
81#define CHG_ITRIM 0x35B
82#define CHG_TTRIM 0x35C
83#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070084#define IUSB_FINE_RES 0x2B6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070086/* check EOC every 10 seconds */
87#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080088/* check for USB unplug every 200 msecs */
89#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091enum chg_fsm_state {
92 FSM_STATE_OFF_0 = 0,
93 FSM_STATE_BATFETDET_START_12 = 12,
94 FSM_STATE_BATFETDET_END_16 = 16,
95 FSM_STATE_ON_CHG_HIGHI_1 = 1,
96 FSM_STATE_ATC_2A = 2,
97 FSM_STATE_ATC_2B = 18,
98 FSM_STATE_ON_BAT_3 = 3,
99 FSM_STATE_ATC_FAIL_4 = 4 ,
100 FSM_STATE_DELAY_5 = 5,
101 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
102 FSM_STATE_FAST_CHG_7 = 7,
103 FSM_STATE_TRKL_CHG_8 = 8,
104 FSM_STATE_CHG_FAIL_9 = 9,
105 FSM_STATE_EOC_10 = 10,
106 FSM_STATE_ON_CHG_VREGOK_11 = 11,
107 FSM_STATE_ATC_PAUSE_13 = 13,
108 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
109 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
110 FSM_STATE_START_BOOT = 20,
111 FSM_STATE_FLCB_VREGOK = 21,
112 FSM_STATE_FLCB = 22,
113};
114
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700115struct fsm_state_to_batt_status {
116 enum chg_fsm_state fsm_state;
117 int batt_state;
118};
119
120static struct fsm_state_to_batt_status map[] = {
121 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
122 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
123 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
124 /*
125 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
126 * too hot/cold, charger too hot
127 */
128 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
129 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
130 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
132 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
133 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
134 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
135 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
136 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
137 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
138 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
139 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
141 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
142 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
143 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
144 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
146};
147
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700148enum chg_regulation_loop {
149 VDD_LOOP = BIT(3),
150 BAT_CURRENT_LOOP = BIT(2),
151 INPUT_CURRENT_LOOP = BIT(1),
152 INPUT_VOLTAGE_LOOP = BIT(0),
153 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
154 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
155};
156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157enum pmic_chg_interrupts {
158 USBIN_VALID_IRQ = 0,
159 USBIN_OV_IRQ,
160 BATT_INSERTED_IRQ,
161 VBATDET_LOW_IRQ,
162 USBIN_UV_IRQ,
163 VBAT_OV_IRQ,
164 CHGWDOG_IRQ,
165 VCP_IRQ,
166 ATCDONE_IRQ,
167 ATCFAIL_IRQ,
168 CHGDONE_IRQ,
169 CHGFAIL_IRQ,
170 CHGSTATE_IRQ,
171 LOOP_CHANGE_IRQ,
172 FASTCHG_IRQ,
173 TRKLCHG_IRQ,
174 BATT_REMOVED_IRQ,
175 BATTTEMP_HOT_IRQ,
176 CHGHOT_IRQ,
177 BATTTEMP_COLD_IRQ,
178 CHG_GONE_IRQ,
179 BAT_TEMP_OK_IRQ,
180 COARSE_DET_LOW_IRQ,
181 VDD_LOOP_IRQ,
182 VREG_OV_IRQ,
183 VBATDET_IRQ,
184 BATFET_IRQ,
185 PSI_IRQ,
186 DCIN_VALID_IRQ,
187 DCIN_OV_IRQ,
188 DCIN_UV_IRQ,
189 PM_CHG_MAX_INTS,
190};
191
192struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700193 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 int is_charging;
195 struct work_struct work;
196};
197
198/**
199 * struct pm8921_chg_chip -device information
200 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 * @usb_present: present status of usb
202 * @dc_present: present status of dc
203 * @usb_charger_current: usb current to charge the battery with used when
204 * the usb path is enabled or charging is resumed
205 * @safety_time: max time for which charging will happen
206 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800207 * @max_voltage_mv: the max volts the batt should be charged up to
208 * @min_voltage_mv: the min battery voltage before turning the FETon
209 * @cool_temp_dc: the cool temp threshold in deciCelcius
210 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700211 * @resume_voltage_delta: the voltage delta from vdd max at which the
212 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 * @term_current: The charging based term current
214 *
215 */
216struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700217 struct device *dev;
218 unsigned int usb_present;
219 unsigned int dc_present;
220 unsigned int usb_charger_current;
221 unsigned int max_bat_chg_current;
222 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
223 unsigned int safety_time;
224 unsigned int ttrkl_time;
225 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800226 unsigned int max_voltage_mv;
227 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800228 int cool_temp_dc;
229 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700230 unsigned int temp_check_period;
231 unsigned int cool_bat_chg_current;
232 unsigned int warm_bat_chg_current;
233 unsigned int cool_bat_voltage;
234 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700235 unsigned int is_bat_cool;
236 unsigned int is_bat_warm;
237 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700238 unsigned int term_current;
239 unsigned int vbat_channel;
240 unsigned int batt_temp_channel;
241 unsigned int batt_id_channel;
242 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800243 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800244 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700245 struct power_supply batt_psy;
246 struct dentry *dent;
247 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800248 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200249 bool ext_charging;
250 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700251 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700253 struct work_struct battery_id_valid_work;
254 int64_t batt_id_min;
255 int64_t batt_id_max;
256 int trkl_voltage;
257 int weak_voltage;
258 int trkl_current;
259 int weak_current;
260 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800261 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 int thermal_levels;
263 struct delayed_work update_heartbeat_work;
264 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800265 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800266 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700267 struct wake_lock eoc_wake_lock;
268 enum pm8921_chg_cold_thr cold_thr;
269 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800270 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700271 enum pm8921_chg_led_src_config led_src_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272};
273
David Keitelacf57c82012-03-07 18:48:50 -0800274/* user space parameter to limit usb current */
275static unsigned int usb_max_current;
276/*
277 * usb_target_ma is used for wall charger
278 * adaptive input current limiting only. Use
279 * pm_iusbmax_get() to get current maximum usb current setting.
280 */
281static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700283static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284
285static struct pm8921_chg_chip *the_chip;
286
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700287static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
290 u8 mask, u8 val)
291{
292 int rc;
293 u8 reg;
294
295 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
296 if (rc) {
297 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
298 return rc;
299 }
300 reg &= ~mask;
301 reg |= val & mask;
302 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
303 if (rc) {
304 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
305 return rc;
306 }
307 return 0;
308}
309
David Keitelcf867232012-01-27 18:40:12 -0800310static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
311{
312 return pm8xxx_read_irq_stat(chip->dev->parent,
313 chip->pmic_chg_irq[irq_id]);
314}
315
316/* Treat OverVoltage/UnderVoltage as source missing */
317static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
318{
319 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
320}
321
322/* Treat OverVoltage/UnderVoltage as source missing */
323static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
324{
325 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
326}
327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328#define CAPTURE_FSM_STATE_CMD 0xC2
329#define READ_BANK_7 0x70
330#define READ_BANK_4 0x40
331static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
332{
333 u8 temp;
334 int err, ret = 0;
335
336 temp = CAPTURE_FSM_STATE_CMD;
337 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
338 if (err) {
339 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
340 return err;
341 }
342
343 temp = READ_BANK_7;
344 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
345 if (err) {
346 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
347 return err;
348 }
349
350 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
351 if (err) {
352 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
353 return err;
354 }
355 /* get the lower 4 bits */
356 ret = temp & 0xF;
357
358 temp = READ_BANK_4;
359 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
360 if (err) {
361 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
362 return err;
363 }
364
365 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
366 if (err) {
367 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
368 return err;
369 }
370 /* get the upper 1 bit */
371 ret |= (temp & 0x1) << 4;
372 return ret;
373}
374
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700375#define READ_BANK_6 0x60
376static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
377{
378 u8 temp;
379 int err;
380
381 temp = READ_BANK_6;
382 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
383 if (err) {
384 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
385 return err;
386 }
387
388 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
389 if (err) {
390 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
391 return err;
392 }
393
394 /* return the lower 4 bits */
395 return temp & CHG_ALL_LOOPS;
396}
397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398#define CHG_USB_SUSPEND_BIT BIT(2)
399static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
400{
401 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
402 enable ? CHG_USB_SUSPEND_BIT : 0);
403}
404
405#define CHG_EN_BIT BIT(7)
406static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
407{
408 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
409 enable ? CHG_EN_BIT : 0);
410}
411
David Keitel753ec8d2011-11-02 10:56:37 -0700412#define CHG_FAILED_CLEAR BIT(0)
413#define ATC_FAILED_CLEAR BIT(1)
414static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
415{
416 int rc;
417
418 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
419 clear ? ATC_FAILED_CLEAR : 0);
420 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
421 clear ? CHG_FAILED_CLEAR : 0);
422 return rc;
423}
424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425#define CHG_CHARGE_DIS_BIT BIT(1)
426static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
427{
428 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
429 disable ? CHG_CHARGE_DIS_BIT : 0);
430}
431
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800432static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
433{
434 u8 temp;
435
436 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
437 return temp & CHG_CHARGE_DIS_BIT;
438}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439#define PM8921_CHG_V_MIN_MV 3240
440#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800441#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442#define PM8921_CHG_VDDMAX_MAX 4500
443#define PM8921_CHG_VDDMAX_MIN 3400
444#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800445static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800447 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800448 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800450 if (voltage < PM8921_CHG_VDDMAX_MIN
451 || voltage > PM8921_CHG_VDDMAX_MAX) {
452 pr_err("bad mV=%d asked to set\n", voltage);
453 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 }
David Keitelcf867232012-01-27 18:40:12 -0800455
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800456 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
457
458 remainder = voltage % 20;
459 if (remainder >= 10) {
460 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
461 }
462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800464 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465}
466
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700467static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
468{
469 u8 temp;
470 int rc;
471
472 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
473 if (rc) {
474 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700475 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700476 return rc;
477 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800478 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
479 + PM8921_CHG_V_MIN_MV;
480 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
481 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700482 return 0;
483}
484
David Keitelcf867232012-01-27 18:40:12 -0800485static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
486{
487 int current_mv, ret, steps, i;
488 bool increase;
489
490 ret = 0;
491
492 if (voltage < PM8921_CHG_VDDMAX_MIN
493 || voltage > PM8921_CHG_VDDMAX_MAX) {
494 pr_err("bad mV=%d asked to set\n", voltage);
495 return -EINVAL;
496 }
497
498 ret = pm_chg_vddmax_get(chip, &current_mv);
499 if (ret) {
500 pr_err("Failed to read vddmax rc=%d\n", ret);
501 return -EINVAL;
502 }
503 if (current_mv == voltage)
504 return 0;
505
506 /* Only change in increments when USB is present */
507 if (is_usb_chg_plugged_in(chip)) {
508 if (current_mv < voltage) {
509 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
510 increase = true;
511 } else {
512 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
513 increase = false;
514 }
515 for (i = 0; i < steps; i++) {
516 if (increase)
517 current_mv += PM8921_CHG_V_STEP_MV;
518 else
519 current_mv -= PM8921_CHG_V_STEP_MV;
520 ret |= __pm_chg_vddmax_set(chip, current_mv);
521 }
522 }
523 ret |= __pm_chg_vddmax_set(chip, voltage);
524 return ret;
525}
526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527#define PM8921_CHG_VDDSAFE_MIN 3400
528#define PM8921_CHG_VDDSAFE_MAX 4500
529static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
530{
531 u8 temp;
532
533 if (voltage < PM8921_CHG_VDDSAFE_MIN
534 || voltage > PM8921_CHG_VDDSAFE_MAX) {
535 pr_err("bad mV=%d asked to set\n", voltage);
536 return -EINVAL;
537 }
538 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
539 pr_debug("voltage=%d setting %02x\n", voltage, temp);
540 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
541}
542
543#define PM8921_CHG_VBATDET_MIN 3240
544#define PM8921_CHG_VBATDET_MAX 5780
545static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
546{
547 u8 temp;
548
549 if (voltage < PM8921_CHG_VBATDET_MIN
550 || voltage > PM8921_CHG_VBATDET_MAX) {
551 pr_err("bad mV=%d asked to set\n", voltage);
552 return -EINVAL;
553 }
554 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
555 pr_debug("voltage=%d setting %02x\n", voltage, temp);
556 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
557}
558
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700559#define PM8921_CHG_VINMIN_MIN_MV 3800
560#define PM8921_CHG_VINMIN_STEP_MV 100
561#define PM8921_CHG_VINMIN_USABLE_MAX 6500
562#define PM8921_CHG_VINMIN_USABLE_MIN 4300
563#define PM8921_CHG_VINMIN_MASK 0x1F
564static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
565{
566 u8 temp;
567
568 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
569 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
570 pr_err("bad mV=%d asked to set\n", voltage);
571 return -EINVAL;
572 }
573 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
574 pr_debug("voltage=%d setting %02x\n", voltage, temp);
575 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
576 temp);
577}
578
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800579static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
580{
581 u8 temp;
582 int rc, voltage_mv;
583
584 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
585 temp &= PM8921_CHG_VINMIN_MASK;
586
587 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
588 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
589
590 return voltage_mv;
591}
592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593#define PM8921_CHG_IBATMAX_MIN 325
594#define PM8921_CHG_IBATMAX_MAX 2000
595#define PM8921_CHG_I_MIN_MA 225
596#define PM8921_CHG_I_STEP_MA 50
597#define PM8921_CHG_I_MASK 0x3F
598static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
599{
600 u8 temp;
601
602 if (chg_current < PM8921_CHG_IBATMAX_MIN
603 || chg_current > PM8921_CHG_IBATMAX_MAX) {
604 pr_err("bad mA=%d asked to set\n", chg_current);
605 return -EINVAL;
606 }
607 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
608 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
609}
610
611#define PM8921_CHG_IBATSAFE_MIN 225
612#define PM8921_CHG_IBATSAFE_MAX 3375
613static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
614{
615 u8 temp;
616
617 if (chg_current < PM8921_CHG_IBATSAFE_MIN
618 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
619 pr_err("bad mA=%d asked to set\n", chg_current);
620 return -EINVAL;
621 }
622 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
623 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
624 PM8921_CHG_I_MASK, temp);
625}
626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700628#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629#define PM8921_CHG_ITERM_STEP_MA 10
630#define PM8921_CHG_ITERM_MASK 0xF
631static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
632{
633 u8 temp;
634
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700635 if (chg_current < PM8921_CHG_ITERM_MIN_MA
636 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 pr_err("bad mA=%d asked to set\n", chg_current);
638 return -EINVAL;
639 }
640
641 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
642 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700643 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644 temp);
645}
646
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700647static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
648{
649 u8 temp;
650 int rc;
651
652 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
653 if (rc) {
654 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700655 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700656 return rc;
657 }
658 temp &= PM8921_CHG_ITERM_MASK;
659 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
660 + PM8921_CHG_ITERM_MIN_MA;
661 return 0;
662}
663
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800664struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700665 int usb_ma;
666 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800667};
668
669static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700670 {100, 0x0},
671 {200, 0x1},
672 {500, 0x2},
673 {600, 0x3},
674 {700, 0x4},
675 {800, 0x5},
676 {850, 0x6},
677 {900, 0x8},
678 {950, 0x7},
679 {1000, 0x9},
680 {1100, 0xA},
681 {1200, 0xB},
682 {1300, 0xC},
683 {1400, 0xD},
684 {1500, 0xE},
685 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800686};
687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700689#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690#define PM8921_CHG_IUSB_MAX 7
691#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700692#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700693static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694{
David Keitel38bdd4f2012-04-19 15:39:13 -0700695 u8 temp, fineres;
696 int rc;
697
698 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
699 reg_val = usb_ma_table[reg_val].value >> 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700701 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
702 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703 return -EINVAL;
704 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700705 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
706
707 /* IUSB_FINE_RES */
708 if (chip->iusb_fine_res) {
709 /* Clear IUSB_FINE_RES bit to avoid overshoot */
710 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
711 PM8917_IUSB_FINE_RES, 0);
712
713 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
714 PM8921_CHG_IUSB_MASK, temp);
715
716 if (rc) {
717 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
718 return rc;
719 }
720
721 if (fineres) {
722 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
723 PM8917_IUSB_FINE_RES, fineres);
724 if (rc)
725 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
726 rc);
727 }
728 } else {
729 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
730 PM8921_CHG_IUSB_MASK, temp);
731 if (rc)
732 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
733 }
734
735 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700736}
737
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800738static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
739{
David Keitel38bdd4f2012-04-19 15:39:13 -0700740 u8 temp, fineres;
741 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800742
David Keitel38bdd4f2012-04-19 15:39:13 -0700743 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800744 *mA = 0;
745 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
746 if (rc) {
747 pr_err("err=%d reading PBL_ACCESS2\n", rc);
748 return rc;
749 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700750
751 if (chip->iusb_fine_res) {
752 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
753 if (rc) {
754 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
755 return rc;
756 }
757 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800758 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -0700759 temp = temp >> PM8921_CHG_IUSB_SHIFT;
760
761 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
762 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
763 if (usb_ma_table[i].value == temp)
764 break;
765 }
766
767 *mA = usb_ma_table[i].usb_ma;
768
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800769 return rc;
770}
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772#define PM8921_CHG_WD_MASK 0x1F
773static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
774{
775 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700776 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
777}
778
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700779#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700780#define PM8921_CHG_TCHG_MIN 4
781#define PM8921_CHG_TCHG_MAX 512
782#define PM8921_CHG_TCHG_STEP 4
783static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
784{
785 u8 temp;
786
787 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
788 pr_err("bad max minutes =%d asked to set\n", minutes);
789 return -EINVAL;
790 }
791
792 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
793 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
794 temp);
795}
796
797#define PM8921_CHG_TTRKL_MASK 0x1F
798#define PM8921_CHG_TTRKL_MIN 1
799#define PM8921_CHG_TTRKL_MAX 64
800static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
801{
802 u8 temp;
803
804 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
805 pr_err("bad max minutes =%d asked to set\n", minutes);
806 return -EINVAL;
807 }
808
809 temp = minutes - 1;
810 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
811 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812}
813
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700814#define PM8921_CHG_VTRKL_MIN_MV 2050
815#define PM8921_CHG_VTRKL_MAX_MV 2800
816#define PM8921_CHG_VTRKL_STEP_MV 50
817#define PM8921_CHG_VTRKL_SHIFT 4
818#define PM8921_CHG_VTRKL_MASK 0xF0
819static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
820{
821 u8 temp;
822
823 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
824 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
825 pr_err("bad voltage = %dmV asked to set\n", millivolts);
826 return -EINVAL;
827 }
828
829 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
830 temp = temp << PM8921_CHG_VTRKL_SHIFT;
831 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
832 temp);
833}
834
835#define PM8921_CHG_VWEAK_MIN_MV 2100
836#define PM8921_CHG_VWEAK_MAX_MV 3600
837#define PM8921_CHG_VWEAK_STEP_MV 100
838#define PM8921_CHG_VWEAK_MASK 0x0F
839static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
840{
841 u8 temp;
842
843 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
844 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
845 pr_err("bad voltage = %dmV asked to set\n", millivolts);
846 return -EINVAL;
847 }
848
849 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
850 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
851 temp);
852}
853
854#define PM8921_CHG_ITRKL_MIN_MA 50
855#define PM8921_CHG_ITRKL_MAX_MA 200
856#define PM8921_CHG_ITRKL_MASK 0x0F
857#define PM8921_CHG_ITRKL_STEP_MA 10
858static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
859{
860 u8 temp;
861
862 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
863 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
864 pr_err("bad current = %dmA asked to set\n", milliamps);
865 return -EINVAL;
866 }
867
868 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
869
870 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
871 temp);
872}
873
874#define PM8921_CHG_IWEAK_MIN_MA 325
875#define PM8921_CHG_IWEAK_MAX_MA 525
876#define PM8921_CHG_IWEAK_SHIFT 7
877#define PM8921_CHG_IWEAK_MASK 0x80
878static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
879{
880 u8 temp;
881
882 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
883 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
884 pr_err("bad current = %dmA asked to set\n", milliamps);
885 return -EINVAL;
886 }
887
888 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
889 temp = 0;
890 else
891 temp = 1;
892
893 temp = temp << PM8921_CHG_IWEAK_SHIFT;
894 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
895 temp);
896}
897
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700898#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
899#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
900static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
901 enum pm8921_chg_cold_thr cold_thr)
902{
903 u8 temp;
904
905 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
906 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
907 return pm_chg_masked_write(chip, CHG_CNTRL_2,
908 PM8921_CHG_BATT_TEMP_THR_COLD,
909 temp);
910}
911
912#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
913#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
914static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
915 enum pm8921_chg_hot_thr hot_thr)
916{
917 u8 temp;
918
919 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
920 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
921 return pm_chg_masked_write(chip, CHG_CNTRL_2,
922 PM8921_CHG_BATT_TEMP_THR_HOT,
923 temp);
924}
925
Jay Chokshid674a512012-03-15 14:06:04 -0700926#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
927#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
928static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
929 enum pm8921_chg_led_src_config led_src_config)
930{
931 u8 temp;
932
933 if (led_src_config < LED_SRC_GND ||
934 led_src_config > LED_SRC_BYPASS)
935 return -EINVAL;
936
937 if (led_src_config == LED_SRC_BYPASS)
938 return 0;
939
940 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
941
942 return pm_chg_masked_write(chip, CHG_CNTRL_3,
943 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
944}
945
David Keitel8c5201a2012-02-24 16:08:54 -0800946static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
947{
948 u8 temp;
949 int rc;
950
951 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
952 if (rc) {
953 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
954 return;
955 }
956 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
957 if (rc) {
958 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
959 return;
960 }
961 /* set the input voltage disable bit and the write bit */
962 temp |= 0x81;
963 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
964 if (rc) {
965 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
966 return;
967 }
968}
969
970static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
971{
972 u8 temp;
973 int rc;
974
975 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
976 if (rc) {
977 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
978 return;
979 }
980 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
981 if (rc) {
982 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
983 return;
984 }
985 /* unset the input voltage disable bit */
986 temp &= 0xFE;
987 /* set the write bit */
988 temp |= 0x80;
989 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
990 if (rc) {
991 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
992 return;
993 }
994}
995
roy.park94dc2002012-06-19 12:14:46 -0700996#ifndef CONFIG_LGE_PM_BATTERY_ID_CHECKER
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700997static int64_t read_battery_id(struct pm8921_chg_chip *chip)
998{
999 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001000 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001001
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001002 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001003 if (rc) {
1004 pr_err("error reading batt id channel = %d, rc = %d\n",
1005 chip->vbat_channel, rc);
1006 return rc;
1007 }
1008 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1009 result.measurement);
1010 return result.physical;
1011}
roy.park94dc2002012-06-19 12:14:46 -07001012#endif
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001013
1014static int is_battery_valid(struct pm8921_chg_chip *chip)
1015{
roy.park94dc2002012-06-19 12:14:46 -07001016#ifndef CONFIG_LGE_PM_BATTERY_ID_CHECKER
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001017 int64_t rc;
roy.park94dc2002012-06-19 12:14:46 -07001018#endif
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001019
roy.park94dc2002012-06-19 12:14:46 -07001020#ifdef CONFIG_LGE_PM_BATTERY_ID_CHECKER
1021 if (is_lge_battery())
1022 return 1;
1023 else
1024 return 0;
1025#else
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001026 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1027 return 1;
1028
1029 rc = read_battery_id(chip);
1030 if (rc < 0) {
1031 pr_err("error reading batt id channel = %d, rc = %lld\n",
1032 chip->vbat_channel, rc);
1033 /* assume battery id is valid when adc error happens */
1034 return 1;
1035 }
1036
1037 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1038 pr_err("batt_id phy =%lld is not valid\n", rc);
1039 return 0;
1040 }
1041 return 1;
roy.park94dc2002012-06-19 12:14:46 -07001042#endif
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001043}
1044
1045static void check_battery_valid(struct pm8921_chg_chip *chip)
1046{
1047 if (is_battery_valid(chip) == 0) {
1048 pr_err("batt_id not valid, disbling charging\n");
1049 pm_chg_auto_enable(chip, 0);
1050 } else {
1051 pm_chg_auto_enable(chip, !charging_disabled);
1052 }
1053}
1054
1055static void battery_id_valid(struct work_struct *work)
1056{
1057 struct pm8921_chg_chip *chip = container_of(work,
1058 struct pm8921_chg_chip, battery_id_valid_work);
1059
1060 check_battery_valid(chip);
1061}
1062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1064{
1065 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1066 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1067 enable_irq(chip->pmic_chg_irq[interrupt]);
1068 }
1069}
1070
1071static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1072{
1073 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1074 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1075 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1076 }
1077}
1078
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001079static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1080{
1081 return test_bit(interrupt, chip->enabled_irqs);
1082}
1083
Amir Samuelovd31ef502011-10-26 14:41:36 +02001084static bool is_ext_charging(struct pm8921_chg_chip *chip)
1085{
David Keitel88e1b572012-01-11 11:57:14 -08001086 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001087
David Keitel88e1b572012-01-11 11:57:14 -08001088 if (!chip->ext_psy)
1089 return false;
1090 if (chip->ext_psy->get_property(chip->ext_psy,
1091 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1092 return false;
1093 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1094 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001095
1096 return false;
1097}
1098
1099static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1100{
David Keitel88e1b572012-01-11 11:57:14 -08001101 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001102
David Keitel88e1b572012-01-11 11:57:14 -08001103 if (!chip->ext_psy)
1104 return false;
1105 if (chip->ext_psy->get_property(chip->ext_psy,
1106 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1107 return false;
1108 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001109 return true;
1110
1111 return false;
1112}
1113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114static int is_battery_charging(int fsm_state)
1115{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001116 if (is_ext_charging(the_chip))
1117 return 1;
1118
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 switch (fsm_state) {
1120 case FSM_STATE_ATC_2A:
1121 case FSM_STATE_ATC_2B:
1122 case FSM_STATE_ON_CHG_AND_BAT_6:
1123 case FSM_STATE_FAST_CHG_7:
1124 case FSM_STATE_TRKL_CHG_8:
1125 return 1;
1126 }
1127 return 0;
1128}
1129
1130static void bms_notify(struct work_struct *work)
1131{
1132 struct bms_notify *n = container_of(work, struct bms_notify, work);
1133
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001134 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001136 } else {
1137 pm8921_bms_charging_end(n->is_battery_full);
1138 n->is_battery_full = 0;
1139 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140}
1141
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001142static void bms_notify_check(struct pm8921_chg_chip *chip)
1143{
1144 int fsm_state, new_is_charging;
1145
1146 fsm_state = pm_chg_get_fsm_state(chip);
1147 new_is_charging = is_battery_charging(fsm_state);
1148
1149 if (chip->bms_notify.is_charging ^ new_is_charging) {
1150 chip->bms_notify.is_charging = new_is_charging;
1151 schedule_work(&(chip->bms_notify.work));
1152 }
1153}
1154
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001155static enum power_supply_property pm_power_props_usb[] = {
1156 POWER_SUPPLY_PROP_PRESENT,
1157 POWER_SUPPLY_PROP_ONLINE,
1158 POWER_SUPPLY_PROP_CURRENT_MAX,
1159};
1160
1161static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001163 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164};
1165
1166static char *pm_power_supplied_to[] = {
1167 "battery",
1168};
1169
David Keitel6ed71a52012-01-30 12:42:18 -08001170#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001171static int pm_power_get_property_mains(struct power_supply *psy,
1172 enum power_supply_property psp,
1173 union power_supply_propval *val)
1174{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001175 /* Check if called before init */
1176 if (!the_chip)
1177 return -EINVAL;
1178
1179 switch (psp) {
1180 case POWER_SUPPLY_PROP_PRESENT:
1181 case POWER_SUPPLY_PROP_ONLINE:
1182 val->intval = 0;
1183 if (charging_disabled)
1184 return 0;
1185
1186 /* check external charger first before the dc path */
1187 if (is_ext_charging(the_chip)) {
1188 val->intval = 1;
1189 return 0;
1190 }
1191
1192 if (pm_is_chg_charge_dis(the_chip)) {
1193 val->intval = 0;
1194 return 0;
1195 }
1196
1197 if (the_chip->dc_present) {
1198 val->intval = 1;
1199 return 0;
1200 }
1201
1202 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001203 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001204 val->intval = is_usb_chg_plugged_in(the_chip);
1205 return 0;
1206
1207 break;
1208 default:
1209 return -EINVAL;
1210 }
1211 return 0;
1212}
1213
1214static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215 enum power_supply_property psp,
1216 union power_supply_propval *val)
1217{
David Keitel6ed71a52012-01-30 12:42:18 -08001218 int current_max;
1219
1220 /* Check if called before init */
1221 if (!the_chip)
1222 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223
1224 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001225 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001226 if (pm_is_chg_charge_dis(the_chip)) {
1227 val->intval = 0;
1228 } else {
1229 pm_chg_iusbmax_get(the_chip, &current_max);
1230 val->intval = current_max;
1231 }
David Keitel6ed71a52012-01-30 12:42:18 -08001232 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001234 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001235 val->intval = 0;
1236 if (charging_disabled)
1237 return 0;
1238
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001239 /*
1240 * if drawing any current from usb is disabled behave
1241 * as if no usb cable is connected
1242 */
1243 if (pm_is_chg_charge_dis(the_chip))
1244 return 0;
1245
David Keitel63f71662012-02-08 20:30:00 -08001246 /* USB charging */
David Keitelaf515712012-04-13 17:25:31 -07001247 if (usb_target_ma < USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001248 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001249 else
1250 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 break;
1252 default:
1253 return -EINVAL;
1254 }
1255 return 0;
1256}
1257
1258static enum power_supply_property msm_batt_power_props[] = {
1259 POWER_SUPPLY_PROP_STATUS,
1260 POWER_SUPPLY_PROP_CHARGE_TYPE,
1261 POWER_SUPPLY_PROP_HEALTH,
1262 POWER_SUPPLY_PROP_PRESENT,
1263 POWER_SUPPLY_PROP_TECHNOLOGY,
1264 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1265 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1266 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1267 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001268 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001269 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001270 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271};
1272
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001273static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274{
1275 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001276 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001278 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 if (rc) {
1280 pr_err("error reading adc channel = %d, rc = %d\n",
1281 chip->vbat_channel, rc);
1282 return rc;
1283 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001284 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 result.measurement);
1286 return (int)result.physical;
1287}
1288
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001289static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1290{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001291 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1292 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1293 unsigned int low_voltage = chip->min_voltage_mv;
1294 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001295
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001296 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001297 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001298 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001299 return 100;
1300 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001301 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001302 / (high_voltage - low_voltage);
1303}
1304
David Keitel4f9397b2012-04-16 11:46:16 -07001305static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1306{
roy.park94dc2002012-06-19 12:14:46 -07001307
1308#ifdef CONFIG_LGE_PM_BATTERY_ID_CHECKER
1309 if (is_lge_battery() == false)
1310 return 0;
1311#endif
David Keitel4f9397b2012-04-16 11:46:16 -07001312 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1313}
1314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1316{
David Keitel4f9397b2012-04-16 11:46:16 -07001317 int percent_soc;
1318
1319 if (!get_prop_batt_present(chip))
1320 percent_soc = voltage_based_capacity(chip);
1321 else
1322 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001323
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001324 if (percent_soc == -ENXIO)
1325 percent_soc = voltage_based_capacity(chip);
1326
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001327 if (percent_soc <= 10)
1328 pr_warn("low battery charge = %d%%\n", percent_soc);
1329
1330 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331}
1332
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001333static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1334{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001335 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001336
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001337 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001338 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001339 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001340 }
1341
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001342 if (rc) {
1343 pr_err("unable to get batt current rc = %d\n", rc);
1344 return rc;
1345 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001346 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001347 }
1348}
1349
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001350static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1351{
1352 int rc;
1353
1354 rc = pm8921_bms_get_fcc();
1355 if (rc < 0)
1356 pr_err("unable to get batt fcc rc = %d\n", rc);
1357 return rc;
1358}
1359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1361{
1362 int temp;
1363
roy.park94dc2002012-06-19 12:14:46 -07001364#ifdef CONFIG_LGE_PM_BATTERY_ID_CHECKER
1365 if (is_lge_battery() == false)
1366 return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
1367#endif
1368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1370 if (temp)
1371 return POWER_SUPPLY_HEALTH_OVERHEAT;
1372
1373 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1374 if (temp)
1375 return POWER_SUPPLY_HEALTH_COLD;
1376
1377 return POWER_SUPPLY_HEALTH_GOOD;
1378}
1379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1381{
1382 int temp;
1383
Amir Samuelovd31ef502011-10-26 14:41:36 +02001384 if (!get_prop_batt_present(chip))
1385 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1386
1387 if (is_ext_trickle_charging(chip))
1388 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1389
1390 if (is_ext_charging(chip))
1391 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1394 if (temp)
1395 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1396
1397 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1398 if (temp)
1399 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1400
1401 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1402}
1403
1404static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1405{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001406 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1407 int fsm_state = pm_chg_get_fsm_state(chip);
1408 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409
David Keitel88e1b572012-01-11 11:57:14 -08001410 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001411 if (chip->ext_charge_done)
1412 return POWER_SUPPLY_STATUS_FULL;
1413 if (chip->ext_charging)
1414 return POWER_SUPPLY_STATUS_CHARGING;
1415 }
1416
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001417 for (i = 0; i < ARRAY_SIZE(map); i++)
1418 if (map[i].fsm_state == fsm_state)
1419 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001420
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001421 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1422 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1423 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001424 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1425 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001426
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001427 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001428 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001429 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430}
1431
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001432#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001433static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1434{
1435 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001436 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001437
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001438 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001439 if (rc) {
1440 pr_err("error reading adc channel = %d, rc = %d\n",
1441 chip->vbat_channel, rc);
1442 return rc;
1443 }
1444 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1445 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001446 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1447 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1448 (int) result.physical);
1449
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001450 return (int)result.physical;
1451}
1452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453static int pm_batt_power_get_property(struct power_supply *psy,
1454 enum power_supply_property psp,
1455 union power_supply_propval *val)
1456{
1457 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1458 batt_psy);
1459
1460 switch (psp) {
1461 case POWER_SUPPLY_PROP_STATUS:
1462 val->intval = get_prop_batt_status(chip);
1463 break;
1464 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1465 val->intval = get_prop_charge_type(chip);
1466 break;
1467 case POWER_SUPPLY_PROP_HEALTH:
1468 val->intval = get_prop_batt_health(chip);
1469 break;
1470 case POWER_SUPPLY_PROP_PRESENT:
1471 val->intval = get_prop_batt_present(chip);
1472 break;
1473 case POWER_SUPPLY_PROP_TECHNOLOGY:
1474 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1475 break;
1476 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001477 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 break;
1479 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001480 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 break;
1482 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001483 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 break;
1485 case POWER_SUPPLY_PROP_CAPACITY:
1486 val->intval = get_prop_batt_capacity(chip);
1487 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001488 case POWER_SUPPLY_PROP_CURRENT_NOW:
1489 val->intval = get_prop_batt_current(chip);
1490 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001491 case POWER_SUPPLY_PROP_TEMP:
1492 val->intval = get_prop_batt_temp(chip);
1493 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001494 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001495 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001496 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 default:
1498 return -EINVAL;
1499 }
1500
1501 return 0;
1502}
1503
1504static void (*notify_vbus_state_func_ptr)(int);
1505static int usb_chg_current;
1506static DEFINE_SPINLOCK(vbus_lock);
1507
1508int pm8921_charger_register_vbus_sn(void (*callback)(int))
1509{
1510 pr_debug("%p\n", callback);
1511 notify_vbus_state_func_ptr = callback;
1512 return 0;
1513}
1514EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1515
1516/* this is passed to the hsusb via platform_data msm_otg_pdata */
1517void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1518{
1519 pr_debug("%p\n", callback);
1520 notify_vbus_state_func_ptr = NULL;
1521}
1522EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1523
1524static void notify_usb_of_the_plugin_event(int plugin)
1525{
1526 plugin = !!plugin;
1527 if (notify_vbus_state_func_ptr) {
1528 pr_debug("notifying plugin\n");
1529 (*notify_vbus_state_func_ptr) (plugin);
1530 } else {
1531 pr_debug("unable to notify plugin\n");
1532 }
1533}
1534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535/* assumes vbus_lock is held */
1536static void __pm8921_charger_vbus_draw(unsigned int mA)
1537{
1538 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001539 if (!the_chip) {
1540 pr_err("called before init\n");
1541 return;
1542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543
David Keitel38bdd4f2012-04-19 15:39:13 -07001544 if (mA >= 0 && mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001546 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001548 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549 }
1550 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1551 if (rc)
1552 pr_err("fail to set suspend bit rc=%d\n", rc);
1553 } else {
1554 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1555 if (rc)
1556 pr_err("fail to reset suspend bit rc=%d\n", rc);
1557 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1558 if (usb_ma_table[i].usb_ma <= mA)
1559 break;
1560 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001561
1562 /* Check if IUSB_FINE_RES is available */
1563 if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
1564 && !the_chip->iusb_fine_res)
1565 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 if (i < 0)
1567 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001568 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001570 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571 }
1572 }
1573}
1574
1575/* USB calls these to tell us how much max usb current the system can draw */
1576void pm8921_charger_vbus_draw(unsigned int mA)
1577{
1578 unsigned long flags;
1579
1580 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001581
David Keitel62c6a4b2012-05-17 12:54:59 -07001582 if (!the_chip) {
1583 pr_err("chip not yet initalized\n");
1584 return;
1585 }
1586
1587 /*
1588 * Reject VBUS requests if USB connection is the only available
1589 * power source. This makes sure that if booting without
1590 * battery the iusb_max value is not decreased avoiding potential
1591 * brown_outs.
1592 *
1593 * This would also apply when the battery has been
1594 * removed from the running system.
1595 */
1596 if (!get_prop_batt_present(the_chip)
1597 && !is_dc_chg_plugged_in(the_chip)) {
1598 pr_err("rejected: no other power source connected\n");
1599 return;
1600 }
1601
David Keitelacf57c82012-03-07 18:48:50 -08001602 if (usb_max_current && mA > usb_max_current) {
1603 pr_warn("restricting usb current to %d instead of %d\n",
1604 usb_max_current, mA);
1605 mA = usb_max_current;
1606 }
1607 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1608 usb_target_ma = mA;
1609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 spin_lock_irqsave(&vbus_lock, flags);
1611 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001612 if (mA > USB_WALL_THRESHOLD_MA)
1613 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1614 else
1615 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 } else {
1617 /*
1618 * called before pmic initialized,
1619 * save this value and use it at probe
1620 */
David Keitelacf57c82012-03-07 18:48:50 -08001621 if (mA > USB_WALL_THRESHOLD_MA)
1622 usb_chg_current = USB_WALL_THRESHOLD_MA;
1623 else
1624 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625 }
1626 spin_unlock_irqrestore(&vbus_lock, flags);
1627}
1628EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1629
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001630int pm8921_charger_enable(bool enable)
1631{
1632 int rc;
1633
1634 if (!the_chip) {
1635 pr_err("called before init\n");
1636 return -EINVAL;
1637 }
1638 enable = !!enable;
1639 rc = pm_chg_auto_enable(the_chip, enable);
1640 if (rc)
1641 pr_err("Failed rc=%d\n", rc);
1642 return rc;
1643}
1644EXPORT_SYMBOL(pm8921_charger_enable);
1645
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001646int pm8921_is_usb_chg_plugged_in(void)
1647{
1648 if (!the_chip) {
1649 pr_err("called before init\n");
1650 return -EINVAL;
1651 }
1652 return is_usb_chg_plugged_in(the_chip);
1653}
1654EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1655
1656int pm8921_is_dc_chg_plugged_in(void)
1657{
1658 if (!the_chip) {
1659 pr_err("called before init\n");
1660 return -EINVAL;
1661 }
1662 return is_dc_chg_plugged_in(the_chip);
1663}
1664EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1665
1666int pm8921_is_battery_present(void)
1667{
1668 if (!the_chip) {
1669 pr_err("called before init\n");
1670 return -EINVAL;
1671 }
1672 return get_prop_batt_present(the_chip);
1673}
1674EXPORT_SYMBOL(pm8921_is_battery_present);
1675
David Keitel012deef2011-12-02 11:49:33 -08001676/*
1677 * Disabling the charge current limit causes current
1678 * current limits to have no monitoring. An adequate charger
1679 * capable of supplying high current while sustaining VIN_MIN
1680 * is required if the limiting is disabled.
1681 */
1682int pm8921_disable_input_current_limit(bool disable)
1683{
1684 if (!the_chip) {
1685 pr_err("called before init\n");
1686 return -EINVAL;
1687 }
1688 if (disable) {
1689 pr_warn("Disabling input current limit!\n");
1690
1691 return pm8xxx_writeb(the_chip->dev->parent,
1692 CHG_BUCK_CTRL_TEST3, 0xF2);
1693 }
1694 return 0;
1695}
1696EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1697
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001698int pm8921_set_max_battery_charge_current(int ma)
1699{
1700 if (!the_chip) {
1701 pr_err("called before init\n");
1702 return -EINVAL;
1703 }
1704 return pm_chg_ibatmax_set(the_chip, ma);
1705}
1706EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1707
1708int pm8921_disable_source_current(bool disable)
1709{
1710 if (!the_chip) {
1711 pr_err("called before init\n");
1712 return -EINVAL;
1713 }
1714 if (disable)
1715 pr_warn("current drawn from chg=0, battery provides current\n");
1716 return pm_chg_charge_dis(the_chip, disable);
1717}
1718EXPORT_SYMBOL(pm8921_disable_source_current);
1719
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001720int pm8921_regulate_input_voltage(int voltage)
1721{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001722 int rc;
1723
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001724 if (!the_chip) {
1725 pr_err("called before init\n");
1726 return -EINVAL;
1727 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001728 rc = pm_chg_vinmin_set(the_chip, voltage);
1729
1730 if (rc == 0)
1731 the_chip->vin_min = voltage;
1732
1733 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001734}
1735
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001736#define USB_OV_THRESHOLD_MASK 0x60
1737#define USB_OV_THRESHOLD_SHIFT 5
1738int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1739{
1740 u8 temp;
1741
1742 if (!the_chip) {
1743 pr_err("called before init\n");
1744 return -EINVAL;
1745 }
1746
1747 if (ov > PM_USB_OV_7V) {
1748 pr_err("limiting to over voltage threshold to 7volts\n");
1749 ov = PM_USB_OV_7V;
1750 }
1751
1752 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1753
1754 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1755 USB_OV_THRESHOLD_MASK, temp);
1756}
1757EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1758
1759#define USB_DEBOUNCE_TIME_MASK 0x06
1760#define USB_DEBOUNCE_TIME_SHIFT 1
1761int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1762{
1763 u8 temp;
1764
1765 if (!the_chip) {
1766 pr_err("called before init\n");
1767 return -EINVAL;
1768 }
1769
1770 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1771 pr_err("limiting debounce to 80.5ms\n");
1772 ms = PM_USB_DEBOUNCE_80P5MS;
1773 }
1774
1775 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1776
1777 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1778 USB_DEBOUNCE_TIME_MASK, temp);
1779}
1780EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1781
1782#define USB_OVP_DISABLE_MASK 0x80
1783int pm8921_usb_ovp_disable(int disable)
1784{
1785 u8 temp = 0;
1786
1787 if (!the_chip) {
1788 pr_err("called before init\n");
1789 return -EINVAL;
1790 }
1791
1792 if (disable)
1793 temp = USB_OVP_DISABLE_MASK;
1794
1795 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1796 USB_OVP_DISABLE_MASK, temp);
1797}
1798
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001799bool pm8921_is_battery_charging(int *source)
1800{
1801 int fsm_state, is_charging, dc_present, usb_present;
1802
1803 if (!the_chip) {
1804 pr_err("called before init\n");
1805 return -EINVAL;
1806 }
1807 fsm_state = pm_chg_get_fsm_state(the_chip);
1808 is_charging = is_battery_charging(fsm_state);
1809 if (is_charging == 0) {
1810 *source = PM8921_CHG_SRC_NONE;
1811 return is_charging;
1812 }
1813
1814 if (source == NULL)
1815 return is_charging;
1816
1817 /* the battery is charging, the source is requested, find it */
1818 dc_present = is_dc_chg_plugged_in(the_chip);
1819 usb_present = is_usb_chg_plugged_in(the_chip);
1820
1821 if (dc_present && !usb_present)
1822 *source = PM8921_CHG_SRC_DC;
1823
1824 if (usb_present && !dc_present)
1825 *source = PM8921_CHG_SRC_USB;
1826
1827 if (usb_present && dc_present)
1828 /*
1829 * The system always chooses dc for charging since it has
1830 * higher priority.
1831 */
1832 *source = PM8921_CHG_SRC_DC;
1833
1834 return is_charging;
1835}
1836EXPORT_SYMBOL(pm8921_is_battery_charging);
1837
David Keitel86034022012-04-18 12:33:58 -07001838int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1839{
1840 if (!the_chip) {
1841 pr_err("called before init\n");
1842 return -EINVAL;
1843 }
1844
1845 if (type < POWER_SUPPLY_TYPE_USB)
1846 return -EINVAL;
1847
1848 the_chip->usb_psy.type = type;
1849 power_supply_changed(&the_chip->usb_psy);
1850 power_supply_changed(&the_chip->dc_psy);
1851 return 0;
1852}
1853EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1854
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001855int pm8921_batt_temperature(void)
1856{
1857 if (!the_chip) {
1858 pr_err("called before init\n");
1859 return -EINVAL;
1860 }
1861 return get_prop_batt_temp(the_chip);
1862}
1863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1865{
1866 int usb_present;
1867
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001868 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 usb_present = is_usb_chg_plugged_in(chip);
1870 if (chip->usb_present ^ usb_present) {
1871 notify_usb_of_the_plugin_event(usb_present);
1872 chip->usb_present = usb_present;
1873 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001874 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001875 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001877 if (usb_present) {
1878 schedule_delayed_work(&chip->unplug_check_work,
1879 round_jiffies_relative(msecs_to_jiffies
1880 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001881 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1882 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001883 /* USB unplugged reset target current */
1884 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001885 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001886 }
David Keitel8c5201a2012-02-24 16:08:54 -08001887 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001888 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889}
1890
Amir Samuelovd31ef502011-10-26 14:41:36 +02001891static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1892{
David Keitel88e1b572012-01-11 11:57:14 -08001893 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001894 pr_debug("external charger not registered.\n");
1895 return;
1896 }
1897
1898 if (!chip->ext_charging) {
1899 pr_debug("already not charging.\n");
1900 return;
1901 }
1902
David Keitel88e1b572012-01-11 11:57:14 -08001903 power_supply_set_charge_type(chip->ext_psy,
1904 POWER_SUPPLY_CHARGE_TYPE_NONE);
1905 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001906 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001907 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001908 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001909 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03001910 /* Update battery charging LEDs and user space battery info */
1911 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001912}
1913
1914static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1915{
1916 int dc_present;
1917 int batt_present;
1918 int batt_temp_ok;
1919 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001920 unsigned long delay =
1921 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1922
David Keitel88e1b572012-01-11 11:57:14 -08001923 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001924 pr_debug("external charger not registered.\n");
1925 return;
1926 }
1927
1928 if (chip->ext_charging) {
1929 pr_debug("already charging.\n");
1930 return;
1931 }
1932
David Keitel88e1b572012-01-11 11:57:14 -08001933 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001934 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1935 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001936
1937 if (!dc_present) {
1938 pr_warn("%s. dc not present.\n", __func__);
1939 return;
1940 }
1941 if (!batt_present) {
1942 pr_warn("%s. battery not present.\n", __func__);
1943 return;
1944 }
1945 if (!batt_temp_ok) {
1946 pr_warn("%s. battery temperature not ok.\n", __func__);
1947 return;
1948 }
David Keitel88e1b572012-01-11 11:57:14 -08001949 pm8921_disable_source_current(true); /* Force BATFET=ON */
1950 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001951 if (vbat_ov) {
1952 pr_warn("%s. battery over voltage.\n", __func__);
1953 return;
1954 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001955
David Keitel63f71662012-02-08 20:30:00 -08001956 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001957 power_supply_set_charge_type(chip->ext_psy,
1958 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001959 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001960 chip->ext_charging = true;
1961 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001962 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001963 /* Start BMS */
1964 schedule_delayed_work(&chip->eoc_work, delay);
1965 wake_lock(&chip->eoc_wake_lock);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03001966 /* Update battery charging LEDs and user space battery info */
1967 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001968}
1969
David Keitel8c5201a2012-02-24 16:08:54 -08001970static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001971{
1972 u8 temp;
1973 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001974
David Keitel8c5201a2012-02-24 16:08:54 -08001975 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001976 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001977 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1978 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001979 }
David Keitel8c5201a2012-02-24 16:08:54 -08001980 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1981 if (rc) {
1982 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1983 return;
1984 }
1985 /* set ovp fet disable bit and the write bit */
1986 temp |= 0x81;
1987 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1988 if (rc) {
1989 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1990 return;
1991 }
1992}
1993
1994static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1995{
1996 u8 temp;
1997 int rc;
1998
1999 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
2000 if (rc) {
2001 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
2002 return;
2003 }
2004 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
2005 if (rc) {
2006 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
2007 return;
2008 }
2009 /* unset ovp fet disable bit and set the write bit */
2010 temp &= 0xFE;
2011 temp |= 0x80;
2012 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
2013 if (rc) {
2014 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
2015 temp, rc);
2016 return;
2017 }
2018}
2019
2020static int param_open_ovp_counter = 10;
2021module_param(param_open_ovp_counter, int, 0644);
2022
2023#define WRITE_BANK_4 0xC0
2024#define USB_OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002025static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002026{
Steve Mucklef132c6c2012-06-06 18:30:57 -07002027 int chg_gone = 0, usb_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002028 int count = 0;
2029
2030 while (count++ < param_open_ovp_counter) {
2031 pm_chg_masked_write(chip, USB_OVP_CONTROL,
2032 USB_OVP_DEBOUNCE_TIME, 0x0);
2033 usleep(10);
2034 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2035 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2036 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
2037 count, chg_gone, usb_chg_plugged_in);
2038
2039 /* note usb_chg_plugged_in=0 => chg_gone=1 */
2040 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2041 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
2042 turn_off_usb_ovp_fet(chip);
2043
2044 msleep(20);
2045
2046 turn_on_usb_ovp_fet(chip);
2047 } else {
David Keitel712782e2012-03-29 14:11:47 -07002048 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002049 }
2050 }
David Keitel712782e2012-03-29 14:11:47 -07002051 pm_chg_masked_write(chip, USB_OVP_CONTROL,
2052 USB_OVP_DEBOUNCE_TIME, 0x2);
2053 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
2054 count, chg_gone, usb_chg_plugged_in);
2055 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002056}
David Keitelacf57c82012-03-07 18:48:50 -08002057
2058static int find_usb_ma_value(int value)
2059{
2060 int i;
2061
2062 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2063 if (value >= usb_ma_table[i].usb_ma)
2064 break;
2065 }
2066
2067 return i;
2068}
2069
2070static void decrease_usb_ma_value(int *value)
2071{
2072 int i;
2073
2074 if (value) {
2075 i = find_usb_ma_value(*value);
2076 if (i > 0)
2077 i--;
2078 *value = usb_ma_table[i].usb_ma;
2079 }
2080}
2081
2082static void increase_usb_ma_value(int *value)
2083{
2084 int i;
2085
2086 if (value) {
2087 i = find_usb_ma_value(*value);
2088
2089 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2090 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002091 /* Get next correct entry if IUSB_FINE_RES is not available */
2092 while (!the_chip->iusb_fine_res
2093 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2094 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2095 i++;
2096
David Keitelacf57c82012-03-07 18:48:50 -08002097 *value = usb_ma_table[i].usb_ma;
2098 }
2099}
2100
2101static void vin_collapse_check_worker(struct work_struct *work)
2102{
2103 struct delayed_work *dwork = to_delayed_work(work);
2104 struct pm8921_chg_chip *chip = container_of(dwork,
2105 struct pm8921_chg_chip, vin_collapse_check_work);
2106
2107 /* AICL only for wall-chargers */
2108 if (is_usb_chg_plugged_in(chip) &&
2109 usb_target_ma > USB_WALL_THRESHOLD_MA) {
2110 /* decrease usb_target_ma */
2111 decrease_usb_ma_value(&usb_target_ma);
2112 /* reset here, increase in unplug_check_worker */
2113 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2114 pr_debug("usb_now=%d, usb_target = %d\n",
2115 USB_WALL_THRESHOLD_MA, usb_target_ma);
2116 } else {
2117 handle_usb_insertion_removal(chip);
2118 }
2119}
2120
2121#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2123{
David Keitelacf57c82012-03-07 18:48:50 -08002124 if (usb_target_ma)
2125 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2126 round_jiffies_relative(msecs_to_jiffies
2127 (VIN_MIN_COLLAPSE_CHECK_MS)));
2128 else
2129 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 return IRQ_HANDLED;
2131}
2132
2133static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
2134{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002135 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 return IRQ_HANDLED;
2137}
2138
2139static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2140{
2141 struct pm8921_chg_chip *chip = data;
2142 int status;
2143
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002144 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2145 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002146 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 pr_debug("battery present=%d", status);
2148 power_supply_changed(&chip->batt_psy);
2149 return IRQ_HANDLED;
2150}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002151
2152/*
2153 * this interrupt used to restart charging a battery.
2154 *
2155 * Note: When DC-inserted the VBAT can't go low.
2156 * VPH_PWR is provided by the ext-charger.
2157 * After End-Of-Charging from DC, charging can be resumed only
2158 * if DC is removed and then inserted after the battery was in use.
2159 * Therefore the handle_start_ext_chg() is not called.
2160 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2162{
2163 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002164 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002166 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002167
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002168 if (high_transition) {
2169 /* enable auto charging */
2170 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002171 pr_info("batt fell below resume voltage %s\n",
2172 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002173 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 power_supply_changed(&chip->batt_psy);
2177 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002178 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 return IRQ_HANDLED;
2181}
2182
2183static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2184{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002185 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 return IRQ_HANDLED;
2187}
2188
2189static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2190{
2191 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2192 return IRQ_HANDLED;
2193}
2194
2195static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2196{
2197 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2198 return IRQ_HANDLED;
2199}
2200
2201static irqreturn_t vcp_irq_handler(int irq, void *data)
2202{
David Keitel8c5201a2012-02-24 16:08:54 -08002203 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 return IRQ_HANDLED;
2205}
2206
2207static irqreturn_t atcdone_irq_handler(int irq, void *data)
2208{
2209 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2210 return IRQ_HANDLED;
2211}
2212
2213static irqreturn_t atcfail_irq_handler(int irq, void *data)
2214{
2215 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2216 return IRQ_HANDLED;
2217}
2218
2219static irqreturn_t chgdone_irq_handler(int irq, void *data)
2220{
2221 struct pm8921_chg_chip *chip = data;
2222
2223 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002224
2225 handle_stop_ext_chg(chip);
2226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227 power_supply_changed(&chip->batt_psy);
2228 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002229 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002230
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002231 bms_notify_check(chip);
2232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 return IRQ_HANDLED;
2234}
2235
2236static irqreturn_t chgfail_irq_handler(int irq, void *data)
2237{
2238 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002239 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240
David Keitel753ec8d2011-11-02 10:56:37 -07002241 ret = pm_chg_failed_clear(chip, 1);
2242 if (ret)
2243 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2244
2245 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2246 get_prop_batt_present(chip),
2247 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2248 pm_chg_get_fsm_state(data));
2249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250 power_supply_changed(&chip->batt_psy);
2251 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002252 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 return IRQ_HANDLED;
2254}
2255
2256static irqreturn_t chgstate_irq_handler(int irq, void *data)
2257{
2258 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259
2260 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2261 power_supply_changed(&chip->batt_psy);
2262 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002263 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002265 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 return IRQ_HANDLED;
2268}
2269
David Keitel8c5201a2012-02-24 16:08:54 -08002270static int param_vin_disable_counter = 5;
2271module_param(param_vin_disable_counter, int, 0644);
2272
2273static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2274 int count, int usb_ma)
2275{
David Keitelacf57c82012-03-07 18:48:50 -08002276 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002277 pr_debug("count = %d iusb=500mA\n", count);
2278 disable_input_voltage_regulation(chip);
2279 pr_debug("count = %d disable_input_regulation\n", count);
2280
2281 msleep(20);
2282
2283 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2284 count,
2285 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2286 is_usb_chg_plugged_in(chip));
2287 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2288 count, usb_ma);
2289 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002290 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002291}
2292
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002293#define VIN_ACTIVE_BIT BIT(0)
2294#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2295#define VIN_MIN_INCREASE_MV 100
2296static void unplug_check_worker(struct work_struct *work)
2297{
2298 struct delayed_work *dwork = to_delayed_work(work);
2299 struct pm8921_chg_chip *chip = container_of(dwork,
2300 struct pm8921_chg_chip, unplug_check_work);
2301 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002302 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002303 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002304
David Keitelacf57c82012-03-07 18:48:50 -08002305 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002306 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2307 if (!usb_chg_plugged_in) {
2308 pr_debug("Stopping Unplug Check Worker since USB is removed"
2309 "reg_loop = %d, fsm = %d ibat = %d\n",
2310 pm_chg_get_regulation_loop(chip),
2311 pm_chg_get_fsm_state(chip),
2312 get_prop_batt_current(chip)
2313 );
2314 return;
2315 }
David Keitel8c5201a2012-02-24 16:08:54 -08002316
2317 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002318 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002319 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2320 disable_input_voltage_regulation(chip);
2321 return;
2322 }
2323
2324 if (usb_ma <= 100) {
2325 pr_debug(
2326 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2327 usb_ma);
2328 goto check_again_later;
2329 }
2330 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2331 pr_debug("chg gone irq is enabled\n");
2332
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002333 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002334 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002335
David Keitel21b7dfb2012-03-31 13:57:14 -07002336 if ((reg_loop & VIN_ACTIVE_BIT) && (usb_ma > USB_WALL_THRESHOLD_MA)) {
David Keitelacf57c82012-03-07 18:48:50 -08002337 decrease_usb_ma_value(&usb_ma);
2338 usb_target_ma = usb_ma;
2339 /* end AICL here */
2340 __pm8921_charger_vbus_draw(usb_ma);
2341 pr_debug("usb_now=%d, usb_target = %d\n",
2342 usb_ma, usb_target_ma);
2343 }
2344
2345 reg_loop = pm_chg_get_regulation_loop(chip);
2346 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2347
2348 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002349 ibat = get_prop_batt_current(chip);
2350
2351 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2352 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2353 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002354 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002355
David Keitel8c5201a2012-02-24 16:08:54 -08002356 while (count++ < param_vin_disable_counter
2357 && usb_chg_plugged_in == 1) {
2358 attempt_reverse_boost_fix(chip, count, usb_ma);
2359 usb_chg_plugged_in
2360 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002361 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002362 }
2363 }
2364
David Keitel8c5201a2012-02-24 16:08:54 -08002365 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2366 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2367
2368 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2369 /* run the worker directly */
2370 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2371 chg_gone, usb_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002372 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002373 }
2374
David Keitelacf57c82012-03-07 18:48:50 -08002375 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2376 /* only increase iusb_max if vin loop not active */
2377 if (usb_ma < usb_target_ma) {
2378 increase_usb_ma_value(&usb_ma);
2379 __pm8921_charger_vbus_draw(usb_ma);
2380 pr_debug("usb_now=%d, usb_target = %d\n",
2381 usb_ma, usb_target_ma);
2382 } else {
2383 usb_target_ma = usb_ma;
2384 }
2385 }
David Keitel8c5201a2012-02-24 16:08:54 -08002386check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002387 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002388 schedule_delayed_work(&chip->unplug_check_work,
2389 round_jiffies_relative(msecs_to_jiffies
2390 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2391}
2392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393static irqreturn_t loop_change_irq_handler(int irq, void *data)
2394{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002395 struct pm8921_chg_chip *chip = data;
2396
2397 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2398 pm_chg_get_fsm_state(data),
2399 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002400 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 return IRQ_HANDLED;
2402}
2403
2404static irqreturn_t fastchg_irq_handler(int irq, void *data)
2405{
2406 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002407 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002409 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2410 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2411 wake_lock(&chip->eoc_wake_lock);
2412 schedule_delayed_work(&chip->eoc_work,
2413 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002414 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002415 }
2416 power_supply_changed(&chip->batt_psy);
2417 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 return IRQ_HANDLED;
2419}
2420
2421static irqreturn_t trklchg_irq_handler(int irq, void *data)
2422{
2423 struct pm8921_chg_chip *chip = data;
2424
2425 power_supply_changed(&chip->batt_psy);
2426 return IRQ_HANDLED;
2427}
2428
2429static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2430{
2431 struct pm8921_chg_chip *chip = data;
2432 int status;
2433
2434 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2435 pr_debug("battery present=%d state=%d", !status,
2436 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002437 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 power_supply_changed(&chip->batt_psy);
2439 return IRQ_HANDLED;
2440}
2441
2442static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2443{
2444 struct pm8921_chg_chip *chip = data;
2445
Amir Samuelovd31ef502011-10-26 14:41:36 +02002446 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447 power_supply_changed(&chip->batt_psy);
2448 return IRQ_HANDLED;
2449}
2450
2451static irqreturn_t chghot_irq_handler(int irq, void *data)
2452{
2453 struct pm8921_chg_chip *chip = data;
2454
2455 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2456 power_supply_changed(&chip->batt_psy);
2457 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002458 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 return IRQ_HANDLED;
2460}
2461
2462static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2463{
2464 struct pm8921_chg_chip *chip = data;
2465
2466 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002467 handle_stop_ext_chg(chip);
2468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002469 power_supply_changed(&chip->batt_psy);
2470 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471 return IRQ_HANDLED;
2472}
2473
2474static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2475{
2476 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002477 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002478
2479 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2480 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2481
2482 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002483 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 power_supply_changed(&chip->batt_psy);
2486 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487 return IRQ_HANDLED;
2488}
David Keitel52fda532011-11-10 10:43:44 -08002489/*
2490 *
2491 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2492 * fire for two cases:
2493 *
2494 * If the interrupt line switches to high temperature is okay
2495 * and thus charging begins.
2496 * If bat_temp_ok is low this means the temperature is now
2497 * too hot or cold, so charging is stopped.
2498 *
2499 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002500static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2501{
David Keitel52fda532011-11-10 10:43:44 -08002502 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503 struct pm8921_chg_chip *chip = data;
2504
David Keitel52fda532011-11-10 10:43:44 -08002505 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2506
2507 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2508 bat_temp_ok, pm_chg_get_fsm_state(data));
2509
2510 if (bat_temp_ok)
2511 handle_start_ext_chg(chip);
2512 else
2513 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515 power_supply_changed(&chip->batt_psy);
2516 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002517 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 return IRQ_HANDLED;
2519}
2520
2521static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2522{
2523 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2524 return IRQ_HANDLED;
2525}
2526
2527static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2528{
2529 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2530 return IRQ_HANDLED;
2531}
2532
2533static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2534{
2535 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2536 return IRQ_HANDLED;
2537}
2538
2539static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2540{
2541 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2542 return IRQ_HANDLED;
2543}
2544
2545static irqreturn_t batfet_irq_handler(int irq, void *data)
2546{
2547 struct pm8921_chg_chip *chip = data;
2548
2549 pr_debug("vreg ov\n");
2550 power_supply_changed(&chip->batt_psy);
2551 return IRQ_HANDLED;
2552}
2553
2554static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2555{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002556 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002557 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002558
David Keitel88e1b572012-01-11 11:57:14 -08002559 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2560 if (chip->ext_psy)
2561 power_supply_set_online(chip->ext_psy, dc_present);
2562 chip->dc_present = dc_present;
2563 if (dc_present)
2564 handle_start_ext_chg(chip);
2565 else
2566 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 return IRQ_HANDLED;
2568}
2569
2570static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2571{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002572 struct pm8921_chg_chip *chip = data;
2573
Amir Samuelovd31ef502011-10-26 14:41:36 +02002574 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002575 return IRQ_HANDLED;
2576}
2577
2578static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2579{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002580 struct pm8921_chg_chip *chip = data;
2581
Amir Samuelovd31ef502011-10-26 14:41:36 +02002582 handle_stop_ext_chg(chip);
2583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 return IRQ_HANDLED;
2585}
2586
David Keitel88e1b572012-01-11 11:57:14 -08002587static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2588{
2589 struct power_supply *psy = &the_chip->batt_psy;
2590 struct power_supply *epsy = dev_get_drvdata(dev);
2591 int i, dcin_irq;
2592
2593 /* Only search for external supply if none is registered */
2594 if (!the_chip->ext_psy) {
2595 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2596 for (i = 0; i < epsy->num_supplicants; i++) {
2597 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2598 if (!strncmp(epsy->name, "dc", 2)) {
2599 the_chip->ext_psy = epsy;
2600 dcin_valid_irq_handler(dcin_irq,
2601 the_chip);
2602 }
2603 }
2604 }
2605 }
2606 return 0;
2607}
2608
2609static void pm_batt_external_power_changed(struct power_supply *psy)
2610{
2611 /* Only look for an external supply if it hasn't been registered */
2612 if (!the_chip->ext_psy)
2613 class_for_each_device(power_supply_class, NULL, psy,
2614 __pm_batt_external_power_changed_work);
2615}
2616
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002617/**
2618 * update_heartbeat - internal function to update userspace
2619 * per update_time minutes
2620 *
2621 */
2622static void update_heartbeat(struct work_struct *work)
2623{
2624 struct delayed_work *dwork = to_delayed_work(work);
2625 struct pm8921_chg_chip *chip = container_of(dwork,
2626 struct pm8921_chg_chip, update_heartbeat_work);
2627
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002628 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002629 power_supply_changed(&chip->batt_psy);
2630 schedule_delayed_work(&chip->update_heartbeat_work,
2631 round_jiffies_relative(msecs_to_jiffies
2632 (chip->update_time)));
2633}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002634#define VDD_LOOP_ACTIVE_BIT BIT(3)
2635#define VDD_MAX_INCREASE_MV 400
2636static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2637module_param(vdd_max_increase_mv, int, 0644);
2638
2639static int ichg_threshold_ua = -400000;
2640module_param(ichg_threshold_ua, int, 0644);
2641static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2642{
2643 int ichg_meas_ua, vbat_uv;
2644 int ichg_meas_ma;
2645 int adj_vdd_max_mv, programmed_vdd_max;
2646 int vbat_batt_terminal_uv;
2647 int vbat_batt_terminal_mv;
2648 int reg_loop;
2649 int delta_mv = 0;
2650
2651 if (chip->rconn_mohm == 0) {
2652 pr_debug("Exiting as rconn_mohm is 0\n");
2653 return;
2654 }
2655 /* adjust vdd_max only in normal temperature zone */
2656 if (chip->is_bat_cool || chip->is_bat_warm) {
2657 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2658 chip->is_bat_cool, chip->is_bat_warm);
2659 return;
2660 }
2661
2662 reg_loop = pm_chg_get_regulation_loop(chip);
2663 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2664 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2665 reg_loop);
2666 return;
2667 }
2668
2669 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2670 &vbat_uv);
2671 if (ichg_meas_ua >= 0) {
2672 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2673 return;
2674 }
2675 if (ichg_meas_ua <= ichg_threshold_ua) {
2676 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2677 ichg_meas_ua, ichg_threshold_ua);
2678 return;
2679 }
2680 ichg_meas_ma = ichg_meas_ua / 1000;
2681
2682 /* rconn_mohm is in milliOhms */
2683 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2684 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2685 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2686
2687 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2688
2689 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2690 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2691 delta_mv,
2692 programmed_vdd_max,
2693 adj_vdd_max_mv);
2694
2695 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2696 pr_debug("adj vdd_max lower than default max voltage\n");
2697 return;
2698 }
2699
2700 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2701 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2702
2703 pr_debug("adjusting vdd_max_mv to %d to make "
2704 "vbat_batt_termial_uv = %d to %d\n",
2705 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2706 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2707}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002708
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002709enum {
2710 CHG_IN_PROGRESS,
2711 CHG_NOT_IN_PROGRESS,
2712 CHG_FINISHED,
2713};
2714
2715#define VBAT_TOLERANCE_MV 70
2716#define CHG_DISABLE_MSLEEP 100
2717static int is_charging_finished(struct pm8921_chg_chip *chip)
2718{
2719 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2720 int ichg_meas_ma, iterm_programmed;
2721 int regulation_loop, fast_chg, vcp;
2722 int rc;
2723 static int last_vbat_programmed = -EINVAL;
2724
2725 if (!is_ext_charging(chip)) {
2726 /* return if the battery is not being fastcharged */
2727 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2728 pr_debug("fast_chg = %d\n", fast_chg);
2729 if (fast_chg == 0)
2730 return CHG_NOT_IN_PROGRESS;
2731
2732 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2733 pr_debug("vcp = %d\n", vcp);
2734 if (vcp == 1)
2735 return CHG_IN_PROGRESS;
2736
2737 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2738 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2739 if (vbatdet_low == 1)
2740 return CHG_IN_PROGRESS;
2741
2742 /* reset count if battery is hot/cold */
2743 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2744 pr_debug("batt_temp_ok = %d\n", rc);
2745 if (rc == 0)
2746 return CHG_IN_PROGRESS;
2747
2748 /* reset count if battery voltage is less than vddmax */
2749 vbat_meas_uv = get_prop_battery_uvolts(chip);
2750 if (vbat_meas_uv < 0)
2751 return CHG_IN_PROGRESS;
2752 vbat_meas_mv = vbat_meas_uv / 1000;
2753
2754 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2755 if (rc) {
2756 pr_err("couldnt read vddmax rc = %d\n", rc);
2757 return CHG_IN_PROGRESS;
2758 }
2759 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2760 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002761
2762 if (last_vbat_programmed == -EINVAL)
2763 last_vbat_programmed = vbat_programmed;
2764 if (last_vbat_programmed != vbat_programmed) {
2765 /* vddmax changed, reset and check again */
2766 pr_debug("vddmax = %d last_vdd_max=%d\n",
2767 vbat_programmed, last_vbat_programmed);
2768 last_vbat_programmed = vbat_programmed;
2769 return CHG_IN_PROGRESS;
2770 }
2771
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002772 regulation_loop = pm_chg_get_regulation_loop(chip);
2773 if (regulation_loop < 0) {
2774 pr_err("couldnt read the regulation loop err=%d\n",
2775 regulation_loop);
2776 return CHG_IN_PROGRESS;
2777 }
2778 pr_debug("regulation_loop=%d\n", regulation_loop);
2779
2780 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2781 return CHG_IN_PROGRESS;
2782 } /* !is_ext_charging */
2783
2784 /* reset count if battery chg current is more than iterm */
2785 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2786 if (rc) {
2787 pr_err("couldnt read iterm rc = %d\n", rc);
2788 return CHG_IN_PROGRESS;
2789 }
2790
2791 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2792 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2793 iterm_programmed, ichg_meas_ma);
2794 /*
2795 * ichg_meas_ma < 0 means battery is drawing current
2796 * ichg_meas_ma > 0 means battery is providing current
2797 */
2798 if (ichg_meas_ma > 0)
2799 return CHG_IN_PROGRESS;
2800
2801 if (ichg_meas_ma * -1 > iterm_programmed)
2802 return CHG_IN_PROGRESS;
2803
2804 return CHG_FINISHED;
2805}
2806
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002807/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002808 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002809 * has happened
2810 *
2811 * If all conditions favouring, if the charge current is
2812 * less than the term current for three consecutive times
2813 * an EOC has happened.
2814 * The wakelock is released if there is no need to reshedule
2815 * - this happens when the battery is removed or EOC has
2816 * happened
2817 */
2818#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002819static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002820{
2821 struct delayed_work *dwork = to_delayed_work(work);
2822 struct pm8921_chg_chip *chip = container_of(dwork,
2823 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002824 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002825 int end;
2826
2827 pm_chg_failed_clear(chip, 1);
2828 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002829
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002830 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002831 count = 0;
2832 wake_unlock(&chip->eoc_wake_lock);
2833 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002834 }
2835
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002836 if (end == CHG_FINISHED) {
2837 count++;
2838 } else {
2839 count = 0;
2840 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002841
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002842 if (count == CONSECUTIVE_COUNT) {
2843 count = 0;
2844 pr_info("End of Charging\n");
2845
2846 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002847
Amir Samuelovd31ef502011-10-26 14:41:36 +02002848 if (is_ext_charging(chip))
2849 chip->ext_charge_done = true;
2850
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002851 if (chip->is_bat_warm || chip->is_bat_cool)
2852 chip->bms_notify.is_battery_full = 0;
2853 else
2854 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002855 /* declare end of charging by invoking chgdone interrupt */
2856 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2857 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002858 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002859 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002860 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002861 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002862 round_jiffies_relative(msecs_to_jiffies
2863 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002864 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002865}
2866
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002867static void btm_configure_work(struct work_struct *work)
2868{
2869 int rc;
2870
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002871 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002872 if (rc)
2873 pr_err("failed to configure btm rc=%d", rc);
2874}
2875
2876DECLARE_WORK(btm_config_work, btm_configure_work);
2877
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002878static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2879{
2880 unsigned int chg_current = chip->max_bat_chg_current;
2881
2882 if (chip->is_bat_cool)
2883 chg_current = min(chg_current, chip->cool_bat_chg_current);
2884
2885 if (chip->is_bat_warm)
2886 chg_current = min(chg_current, chip->warm_bat_chg_current);
2887
David Keitelfdef3a42011-12-14 19:02:54 -08002888 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002889 chg_current = min(chg_current,
2890 chip->thermal_mitigation[thermal_mitigation]);
2891
2892 pm_chg_ibatmax_set(the_chip, chg_current);
2893}
2894
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002895#define TEMP_HYSTERISIS_DEGC 2
2896static void battery_cool(bool enter)
2897{
2898 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002899 if (enter == the_chip->is_bat_cool)
2900 return;
2901 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002902 if (enter) {
2903 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002904 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002905 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002906 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002907 pm_chg_vbatdet_set(the_chip,
2908 the_chip->cool_bat_voltage
2909 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002910 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002911 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002912 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002913 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002914 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002915 the_chip->max_voltage_mv
2916 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002917 }
2918 schedule_work(&btm_config_work);
2919}
2920
2921static void battery_warm(bool enter)
2922{
2923 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002924 if (enter == the_chip->is_bat_warm)
2925 return;
2926 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002927 if (enter) {
2928 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002929 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002930 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002931 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002932 pm_chg_vbatdet_set(the_chip,
2933 the_chip->warm_bat_voltage
2934 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002935 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002936 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002937 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002938 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002939 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002940 the_chip->max_voltage_mv
2941 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002942 }
2943 schedule_work(&btm_config_work);
2944}
2945
2946static int configure_btm(struct pm8921_chg_chip *chip)
2947{
2948 int rc;
2949
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002950 if (chip->warm_temp_dc != INT_MIN)
2951 btm_config.btm_warm_fn = battery_warm;
2952 else
2953 btm_config.btm_warm_fn = NULL;
2954
2955 if (chip->cool_temp_dc != INT_MIN)
2956 btm_config.btm_cool_fn = battery_cool;
2957 else
2958 btm_config.btm_cool_fn = NULL;
2959
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002960 btm_config.low_thr_temp = chip->cool_temp_dc;
2961 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002962 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002963 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002964 if (rc)
2965 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002966 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002967 if (rc)
2968 pr_err("failed to start btm rc = %d\n", rc);
2969
2970 return rc;
2971}
2972
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002973/**
2974 * set_disable_status_param -
2975 *
2976 * Internal function to disable battery charging and also disable drawing
2977 * any current from the source. The device is forced to run on a battery
2978 * after this.
2979 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980static int set_disable_status_param(const char *val, struct kernel_param *kp)
2981{
2982 int ret;
2983 struct pm8921_chg_chip *chip = the_chip;
2984
2985 ret = param_set_int(val, kp);
2986 if (ret) {
2987 pr_err("error setting value %d\n", ret);
2988 return ret;
2989 }
2990 pr_info("factory set disable param to %d\n", charging_disabled);
2991 if (chip) {
2992 pm_chg_auto_enable(chip, !charging_disabled);
2993 pm_chg_charge_dis(chip, charging_disabled);
2994 }
2995 return 0;
2996}
2997module_param_call(disabled, set_disable_status_param, param_get_uint,
2998 &charging_disabled, 0644);
2999
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003000static int rconn_mohm;
3001static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3002{
3003 int ret;
3004 struct pm8921_chg_chip *chip = the_chip;
3005
3006 ret = param_set_int(val, kp);
3007 if (ret) {
3008 pr_err("error setting value %d\n", ret);
3009 return ret;
3010 }
3011 if (chip)
3012 chip->rconn_mohm = rconn_mohm;
3013 return 0;
3014}
3015module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3016 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003017/**
3018 * set_thermal_mitigation_level -
3019 *
3020 * Internal function to control battery charging current to reduce
3021 * temperature
3022 */
3023static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3024{
3025 int ret;
3026 struct pm8921_chg_chip *chip = the_chip;
3027
3028 ret = param_set_int(val, kp);
3029 if (ret) {
3030 pr_err("error setting value %d\n", ret);
3031 return ret;
3032 }
3033
3034 if (!chip) {
3035 pr_err("called before init\n");
3036 return -EINVAL;
3037 }
3038
3039 if (!chip->thermal_mitigation) {
3040 pr_err("no thermal mitigation\n");
3041 return -EINVAL;
3042 }
3043
3044 if (thermal_mitigation < 0
3045 || thermal_mitigation >= chip->thermal_levels) {
3046 pr_err("out of bound level selected\n");
3047 return -EINVAL;
3048 }
3049
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003050 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003051 return ret;
3052}
3053module_param_call(thermal_mitigation, set_therm_mitigation_level,
3054 param_get_uint,
3055 &thermal_mitigation, 0644);
3056
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003057static int set_usb_max_current(const char *val, struct kernel_param *kp)
3058{
3059 int ret, mA;
3060 struct pm8921_chg_chip *chip = the_chip;
3061
3062 ret = param_set_int(val, kp);
3063 if (ret) {
3064 pr_err("error setting value %d\n", ret);
3065 return ret;
3066 }
3067 if (chip) {
3068 pr_warn("setting current max to %d\n", usb_max_current);
3069 pm_chg_iusbmax_get(chip, &mA);
3070 if (mA > usb_max_current)
3071 pm8921_charger_vbus_draw(usb_max_current);
3072 return 0;
3073 }
3074 return -EINVAL;
3075}
David Keitelacf57c82012-03-07 18:48:50 -08003076module_param_call(usb_max_current, set_usb_max_current,
3077 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079static void free_irqs(struct pm8921_chg_chip *chip)
3080{
3081 int i;
3082
3083 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3084 if (chip->pmic_chg_irq[i]) {
3085 free_irq(chip->pmic_chg_irq[i], chip);
3086 chip->pmic_chg_irq[i] = 0;
3087 }
3088}
3089
David Keitel88e1b572012-01-11 11:57:14 -08003090/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3092{
3093 unsigned long flags;
3094 int fsm_state;
3095
3096 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3097 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3098
3099 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003100 if (chip->usb_present) {
3101 schedule_delayed_work(&chip->unplug_check_work,
3102 round_jiffies_relative(msecs_to_jiffies
3103 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08003104 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003105 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106
3107 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3108 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3109 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003110 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
3111 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
3112 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
3113 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3114 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003115 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003116 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3117 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08003118 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003119
3120 spin_lock_irqsave(&vbus_lock, flags);
3121 if (usb_chg_current) {
3122 /* reissue a vbus draw call */
3123 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003124 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125 }
3126 spin_unlock_irqrestore(&vbus_lock, flags);
3127
3128 fsm_state = pm_chg_get_fsm_state(chip);
3129 if (is_battery_charging(fsm_state)) {
3130 chip->bms_notify.is_charging = 1;
3131 pm8921_bms_charging_began();
3132 }
3133
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003134 check_battery_valid(chip);
3135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3137 chip->usb_present,
3138 chip->dc_present,
3139 get_prop_batt_present(chip),
3140 fsm_state);
3141}
3142
3143struct pm_chg_irq_init_data {
3144 unsigned int irq_id;
3145 char *name;
3146 unsigned long flags;
3147 irqreturn_t (*handler)(int, void *);
3148};
3149
3150#define CHG_IRQ(_id, _flags, _handler) \
3151{ \
3152 .irq_id = _id, \
3153 .name = #_id, \
3154 .flags = _flags, \
3155 .handler = _handler, \
3156}
3157struct pm_chg_irq_init_data chg_irq_data[] = {
3158 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3159 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003160 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3162 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003163 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3164 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3166 usbin_uv_irq_handler),
3167 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3168 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3169 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3170 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3171 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3172 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3173 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3174 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3175 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003176 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3177 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3179 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3180 batt_removed_irq_handler),
3181 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3182 batttemp_hot_irq_handler),
3183 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3184 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3185 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003186 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3187 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003188 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3189 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3191 coarse_det_low_irq_handler),
3192 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3193 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3194 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3195 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3196 batfet_irq_handler),
3197 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3198 dcin_valid_irq_handler),
3199 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3200 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003201 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202};
3203
3204static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3205 struct platform_device *pdev)
3206{
3207 struct resource *res;
3208 int ret, i;
3209
3210 ret = 0;
3211 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3212
3213 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3214 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3215 chg_irq_data[i].name);
3216 if (res == NULL) {
3217 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3218 goto err_out;
3219 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003220 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003221 ret = request_irq(res->start, chg_irq_data[i].handler,
3222 chg_irq_data[i].flags,
3223 chg_irq_data[i].name, chip);
3224 if (ret < 0) {
3225 pr_err("couldn't request %d (%s) %d\n", res->start,
3226 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003227 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003228 goto err_out;
3229 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3231 }
3232 return 0;
3233
3234err_out:
3235 free_irqs(chip);
3236 return -EINVAL;
3237}
3238
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003239static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3240{
3241 int err;
3242 u8 temp;
3243
3244 temp = 0xD1;
3245 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3246 if (err) {
3247 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3248 return;
3249 }
3250
3251 temp = 0xD3;
3252 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3253 if (err) {
3254 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3255 return;
3256 }
3257
3258 temp = 0xD1;
3259 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3260 if (err) {
3261 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3262 return;
3263 }
3264
3265 temp = 0xD5;
3266 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3267 if (err) {
3268 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3269 return;
3270 }
3271
3272 udelay(183);
3273
3274 temp = 0xD1;
3275 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3276 if (err) {
3277 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3278 return;
3279 }
3280
3281 temp = 0xD0;
3282 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3283 if (err) {
3284 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3285 return;
3286 }
3287 udelay(32);
3288
3289 temp = 0xD1;
3290 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3291 if (err) {
3292 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3293 return;
3294 }
3295
3296 temp = 0xD3;
3297 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3298 if (err) {
3299 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3300 return;
3301 }
3302}
3303
3304static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3305{
3306 int err;
3307 u8 temp;
3308
3309 temp = 0xD1;
3310 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3311 if (err) {
3312 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3313 return;
3314 }
3315
3316 temp = 0xD0;
3317 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3318 if (err) {
3319 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3320 return;
3321 }
3322}
3323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003324#define ENUM_TIMER_STOP_BIT BIT(1)
3325#define BOOT_DONE_BIT BIT(6)
3326#define CHG_BATFET_ON_BIT BIT(3)
3327#define CHG_VCP_EN BIT(0)
3328#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3329#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003330#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3332{
3333 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003334 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003335
3336 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3337 BOOT_DONE_BIT, BOOT_DONE_BIT);
3338 if (rc) {
3339 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3340 return rc;
3341 }
3342
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003343 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3344
3345 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3346 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3347
3348 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350 if (rc) {
3351 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003352 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 return rc;
3354 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003355 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003356 chip->max_voltage_mv
3357 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 if (rc) {
3359 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003360 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 return rc;
3362 }
3363
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003364 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003365 if (rc) {
3366 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003367 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368 return rc;
3369 }
3370 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3371 if (rc) {
3372 pr_err("Failed to set max voltage to %d rc=%d\n",
3373 SAFE_CURRENT_MA, rc);
3374 return rc;
3375 }
3376
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003377 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 if (rc) {
3379 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3380 return rc;
3381 }
3382
3383 rc = pm_chg_iterm_set(chip, chip->term_current);
3384 if (rc) {
3385 pr_err("Failed to set term current to %d rc=%d\n",
3386 chip->term_current, rc);
3387 return rc;
3388 }
3389
3390 /* Disable the ENUM TIMER */
3391 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3392 ENUM_TIMER_STOP_BIT);
3393 if (rc) {
3394 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3395 return rc;
3396 }
3397
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003398 if (chip->safety_time != 0) {
3399 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3400 if (rc) {
3401 pr_err("Failed to set max time to %d minutes rc=%d\n",
3402 chip->safety_time, rc);
3403 return rc;
3404 }
3405 }
3406
3407 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003408 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003409 if (rc) {
3410 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3411 chip->safety_time, rc);
3412 return rc;
3413 }
3414 }
3415
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003416 if (chip->vin_min != 0) {
3417 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3418 if (rc) {
3419 pr_err("Failed to set vin min to %d mV rc=%d\n",
3420 chip->vin_min, rc);
3421 return rc;
3422 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003423 } else {
3424 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003425 }
3426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427 rc = pm_chg_disable_wd(chip);
3428 if (rc) {
3429 pr_err("Failed to disable wd rc=%d\n", rc);
3430 return rc;
3431 }
3432
3433 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3434 CHG_BAT_TEMP_DIS_BIT, 0);
3435 if (rc) {
3436 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3437 return rc;
3438 }
3439 /* switch to a 3.2Mhz for the buck */
3440 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3441 if (rc) {
3442 pr_err("Failed to switch buck clk rc=%d\n", rc);
3443 return rc;
3444 }
3445
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003446 if (chip->trkl_voltage != 0) {
3447 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3448 if (rc) {
3449 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3450 chip->trkl_voltage, rc);
3451 return rc;
3452 }
3453 }
3454
3455 if (chip->weak_voltage != 0) {
3456 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3457 if (rc) {
3458 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3459 chip->weak_voltage, rc);
3460 return rc;
3461 }
3462 }
3463
3464 if (chip->trkl_current != 0) {
3465 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3466 if (rc) {
3467 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3468 chip->trkl_voltage, rc);
3469 return rc;
3470 }
3471 }
3472
3473 if (chip->weak_current != 0) {
3474 rc = pm_chg_iweak_set(chip, chip->weak_current);
3475 if (rc) {
3476 pr_err("Failed to set weak current to %dmA rc=%d\n",
3477 chip->weak_current, rc);
3478 return rc;
3479 }
3480 }
3481
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003482 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3483 if (rc) {
3484 pr_err("Failed to set cold config %d rc=%d\n",
3485 chip->cold_thr, rc);
3486 }
3487
3488 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3489 if (rc) {
3490 pr_err("Failed to set hot config %d rc=%d\n",
3491 chip->hot_thr, rc);
3492 }
3493
Jay Chokshid674a512012-03-15 14:06:04 -07003494 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3495 if (rc) {
3496 pr_err("Failed to set charger LED src config %d rc=%d\n",
3497 chip->led_src_config, rc);
3498 }
3499
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 /* Workarounds for die 1.1 and 1.0 */
3501 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3502 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3504 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003505
3506 /* software workaround for correct battery_id detection */
3507 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3508 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3509 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3510 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3511 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3512 udelay(100);
3513 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003514 }
3515
David Keitelb51995e2011-11-18 17:03:31 -08003516 /* Workarounds for die 3.0 */
3517 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3518 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3519
David Keitel38bdd4f2012-04-19 15:39:13 -07003520 /* Enable isub_fine resolution AICL for PM8917 */
3521 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3522 chip->iusb_fine_res = true;
3523
David Keitelb51995e2011-11-18 17:03:31 -08003524 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3525
David Keitela3c0d822011-11-03 14:18:52 -07003526 /* Disable EOC FSM processing */
3527 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3528
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003529 pm8921_chg_force_19p2mhz_clk(chip);
3530
3531 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3532 VREF_BATT_THERM_FORCE_ON);
3533 if (rc)
3534 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003536 rc = pm_chg_charge_dis(chip, charging_disabled);
3537 if (rc) {
3538 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3539 return rc;
3540 }
3541
3542 rc = pm_chg_auto_enable(chip, !charging_disabled);
3543 if (rc) {
3544 pr_err("Failed to enable charging rc=%d\n", rc);
3545 return rc;
3546 }
3547
3548 return 0;
3549}
3550
3551static int get_rt_status(void *data, u64 * val)
3552{
3553 int i = (int)data;
3554 int ret;
3555
3556 /* global irq number is passed in via data */
3557 ret = pm_chg_get_rt_status(the_chip, i);
3558 *val = ret;
3559 return 0;
3560}
3561DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3562
3563static int get_fsm_status(void *data, u64 * val)
3564{
3565 u8 temp;
3566
3567 temp = pm_chg_get_fsm_state(the_chip);
3568 *val = temp;
3569 return 0;
3570}
3571DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3572
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003573static int get_reg_loop(void *data, u64 * val)
3574{
3575 u8 temp;
3576
3577 if (!the_chip) {
3578 pr_err("%s called before init\n", __func__);
3579 return -EINVAL;
3580 }
3581 temp = pm_chg_get_regulation_loop(the_chip);
3582 *val = temp;
3583 return 0;
3584}
3585DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003587static int get_reg(void *data, u64 * val)
3588{
3589 int addr = (int)data;
3590 int ret;
3591 u8 temp;
3592
3593 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3594 if (ret) {
3595 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3596 addr, temp, ret);
3597 return -EAGAIN;
3598 }
3599 *val = temp;
3600 return 0;
3601}
3602
3603static int set_reg(void *data, u64 val)
3604{
3605 int addr = (int)data;
3606 int ret;
3607 u8 temp;
3608
3609 temp = (u8) val;
3610 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3611 if (ret) {
3612 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3613 addr, temp, ret);
3614 return -EAGAIN;
3615 }
3616 return 0;
3617}
3618DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3619
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003620enum {
3621 BAT_WARM_ZONE,
3622 BAT_COOL_ZONE,
3623};
3624static int get_warm_cool(void *data, u64 * val)
3625{
3626 if (!the_chip) {
3627 pr_err("%s called before init\n", __func__);
3628 return -EINVAL;
3629 }
3630 if ((int)data == BAT_WARM_ZONE)
3631 *val = the_chip->is_bat_warm;
3632 if ((int)data == BAT_COOL_ZONE)
3633 *val = the_chip->is_bat_cool;
3634 return 0;
3635}
3636DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003638static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3639{
3640 int i;
3641
3642 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3643
3644 if (IS_ERR(chip->dent)) {
3645 pr_err("pmic charger couldnt create debugfs dir\n");
3646 return;
3647 }
3648
3649 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3650 (void *)CHG_CNTRL, &reg_fops);
3651 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3652 (void *)CHG_CNTRL_2, &reg_fops);
3653 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3654 (void *)CHG_CNTRL_3, &reg_fops);
3655 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3656 (void *)PBL_ACCESS1, &reg_fops);
3657 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3658 (void *)PBL_ACCESS2, &reg_fops);
3659 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3660 (void *)SYS_CONFIG_1, &reg_fops);
3661 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3662 (void *)SYS_CONFIG_2, &reg_fops);
3663 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3664 (void *)CHG_VDD_MAX, &reg_fops);
3665 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3666 (void *)CHG_VDD_SAFE, &reg_fops);
3667 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3668 (void *)CHG_VBAT_DET, &reg_fops);
3669 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3670 (void *)CHG_IBAT_MAX, &reg_fops);
3671 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3672 (void *)CHG_IBAT_SAFE, &reg_fops);
3673 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3674 (void *)CHG_VIN_MIN, &reg_fops);
3675 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3676 (void *)CHG_VTRICKLE, &reg_fops);
3677 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3678 (void *)CHG_ITRICKLE, &reg_fops);
3679 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3680 (void *)CHG_ITERM, &reg_fops);
3681 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3682 (void *)CHG_TCHG_MAX, &reg_fops);
3683 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3684 (void *)CHG_TWDOG, &reg_fops);
3685 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3686 (void *)CHG_TEMP_THRESH, &reg_fops);
3687 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3688 (void *)CHG_COMP_OVR, &reg_fops);
3689 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3690 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3691 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3692 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3693 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3694 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3695 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3696 (void *)CHG_TEST, &reg_fops);
3697
3698 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3699 &fsm_fops);
3700
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003701 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3702 &reg_loop_fops);
3703
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003704 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3705 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3706 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3707 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3710 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3711 debugfs_create_file(chg_irq_data[i].name, 0444,
3712 chip->dent,
3713 (void *)chg_irq_data[i].irq_id,
3714 &rt_fops);
3715 }
3716}
3717
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003718static int pm8921_charger_suspend_noirq(struct device *dev)
3719{
3720 int rc;
3721 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3722
3723 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3724 if (rc)
3725 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3726 pm8921_chg_set_hw_clk_switching(chip);
3727 return 0;
3728}
3729
3730static int pm8921_charger_resume_noirq(struct device *dev)
3731{
3732 int rc;
3733 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3734
3735 pm8921_chg_force_19p2mhz_clk(chip);
3736
3737 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3738 VREF_BATT_THERM_FORCE_ON);
3739 if (rc)
3740 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3741 return 0;
3742}
3743
David Keitelf2226022011-12-13 15:55:50 -08003744static int pm8921_charger_resume(struct device *dev)
3745{
3746 int rc;
3747 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3748
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003749 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003750 && !(chip->keep_btm_on_suspend)) {
3751 rc = pm8xxx_adc_btm_configure(&btm_config);
3752 if (rc)
3753 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3754
3755 rc = pm8xxx_adc_btm_start();
3756 if (rc)
3757 pr_err("couldn't restart btm rc=%d\n", rc);
3758 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003759 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3760 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3761 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3762 }
David Keitelf2226022011-12-13 15:55:50 -08003763 return 0;
3764}
3765
3766static int pm8921_charger_suspend(struct device *dev)
3767{
3768 int rc;
3769 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3770
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003771 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003772 && !(chip->keep_btm_on_suspend)) {
3773 rc = pm8xxx_adc_btm_end();
3774 if (rc)
3775 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3776 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003777
3778 if (is_usb_chg_plugged_in(chip)) {
3779 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3780 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3781 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003782
David Keitelf2226022011-12-13 15:55:50 -08003783 return 0;
3784}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3786{
3787 int rc = 0;
3788 struct pm8921_chg_chip *chip;
3789 const struct pm8921_charger_platform_data *pdata
3790 = pdev->dev.platform_data;
3791
3792 if (!pdata) {
3793 pr_err("missing platform data\n");
3794 return -EINVAL;
3795 }
3796
3797 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3798 GFP_KERNEL);
3799 if (!chip) {
3800 pr_err("Cannot allocate pm_chg_chip\n");
3801 return -ENOMEM;
3802 }
3803
3804 chip->dev = &pdev->dev;
3805 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003806 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003807 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003808 chip->max_voltage_mv = pdata->max_voltage;
3809 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003810 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003811 chip->term_current = pdata->term_current;
3812 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003813 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003814 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3815 chip->batt_id_min = pdata->batt_id_min;
3816 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003817 if (pdata->cool_temp != INT_MIN)
3818 chip->cool_temp_dc = pdata->cool_temp * 10;
3819 else
3820 chip->cool_temp_dc = INT_MIN;
3821
3822 if (pdata->warm_temp != INT_MIN)
3823 chip->warm_temp_dc = pdata->warm_temp * 10;
3824 else
3825 chip->warm_temp_dc = INT_MIN;
3826
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003827 chip->temp_check_period = pdata->temp_check_period;
3828 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3829 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3830 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3831 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3832 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003833 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003834 chip->trkl_voltage = pdata->trkl_voltage;
3835 chip->weak_voltage = pdata->weak_voltage;
3836 chip->trkl_current = pdata->trkl_current;
3837 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003838 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003839 chip->thermal_mitigation = pdata->thermal_mitigation;
3840 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003842 chip->cold_thr = pdata->cold_thr;
3843 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003844 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003845 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003846
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 rc = pm8921_chg_hw_init(chip);
3848 if (rc) {
3849 pr_err("couldn't init hardware rc=%d\n", rc);
3850 goto free_chip;
3851 }
3852
3853 chip->usb_psy.name = "usb",
3854 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3855 chip->usb_psy.supplied_to = pm_power_supplied_to,
3856 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003857 chip->usb_psy.properties = pm_power_props_usb,
3858 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3859 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003860
David Keitel6ed71a52012-01-30 12:42:18 -08003861 chip->dc_psy.name = "pm8921-dc",
3862 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3863 chip->dc_psy.supplied_to = pm_power_supplied_to,
3864 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003865 chip->dc_psy.properties = pm_power_props_mains,
3866 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3867 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 chip->batt_psy.name = "battery",
3870 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3871 chip->batt_psy.properties = msm_batt_power_props,
3872 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3873 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003874 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 rc = power_supply_register(chip->dev, &chip->usb_psy);
3876 if (rc < 0) {
3877 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003878 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 }
3880
David Keitel6ed71a52012-01-30 12:42:18 -08003881 rc = power_supply_register(chip->dev, &chip->dc_psy);
3882 if (rc < 0) {
3883 pr_err("power_supply_register usb failed rc = %d\n", rc);
3884 goto unregister_usb;
3885 }
3886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003887 rc = power_supply_register(chip->dev, &chip->batt_psy);
3888 if (rc < 0) {
3889 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003890 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003891 }
3892
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003893 platform_set_drvdata(pdev, chip);
3894 the_chip = chip;
3895
3896 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003897 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003898 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3899 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003900 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 rc = request_irqs(chip, pdev);
3903 if (rc) {
3904 pr_err("couldn't register interrupts rc=%d\n", rc);
3905 goto unregister_batt;
3906 }
3907
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003908 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3909 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3910 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003911 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3912 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003913 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003914 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003915 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003916 * care for jeita compliance
3917 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003918 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003919 rc = configure_btm(chip);
3920 if (rc) {
3921 pr_err("couldn't register with btm rc=%d\n", rc);
3922 goto free_irq;
3923 }
3924 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 create_debugfs_entries(chip);
3927
3928 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003929 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 /* determine what state the charger is in */
3932 determine_initial_state(chip);
3933
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003934 if (chip->update_time) {
3935 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3936 update_heartbeat);
3937 schedule_delayed_work(&chip->update_heartbeat_work,
3938 round_jiffies_relative(msecs_to_jiffies
3939 (chip->update_time)));
3940 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941 return 0;
3942
3943free_irq:
3944 free_irqs(chip);
3945unregister_batt:
3946 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003947unregister_dc:
3948 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949unregister_usb:
3950 power_supply_unregister(&chip->usb_psy);
3951free_chip:
3952 kfree(chip);
3953 return rc;
3954}
3955
3956static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3957{
3958 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3959
3960 free_irqs(chip);
3961 platform_set_drvdata(pdev, NULL);
3962 the_chip = NULL;
3963 kfree(chip);
3964 return 0;
3965}
David Keitelf2226022011-12-13 15:55:50 -08003966static const struct dev_pm_ops pm8921_pm_ops = {
3967 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003968 .suspend_noirq = pm8921_charger_suspend_noirq,
3969 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003970 .resume = pm8921_charger_resume,
3971};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003972static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003973 .probe = pm8921_charger_probe,
3974 .remove = __devexit_p(pm8921_charger_remove),
3975 .driver = {
3976 .name = PM8921_CHARGER_DEV_NAME,
3977 .owner = THIS_MODULE,
3978 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 },
3980};
3981
3982static int __init pm8921_charger_init(void)
3983{
3984 return platform_driver_register(&pm8921_charger_driver);
3985}
3986
3987static void __exit pm8921_charger_exit(void)
3988{
3989 platform_driver_unregister(&pm8921_charger_driver);
3990}
3991
3992late_initcall(pm8921_charger_init);
3993module_exit(pm8921_charger_exit);
3994
3995MODULE_LICENSE("GPL v2");
3996MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3997MODULE_VERSION("1.0");
3998MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);