blob: f84e3ac62dc5e641c7707dd97a0c577fa107a4ef [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070080#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070081#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070083/* check EOC every 10 seconds */
84#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080085/* check for USB unplug every 200 msecs */
86#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088enum chg_fsm_state {
89 FSM_STATE_OFF_0 = 0,
90 FSM_STATE_BATFETDET_START_12 = 12,
91 FSM_STATE_BATFETDET_END_16 = 16,
92 FSM_STATE_ON_CHG_HIGHI_1 = 1,
93 FSM_STATE_ATC_2A = 2,
94 FSM_STATE_ATC_2B = 18,
95 FSM_STATE_ON_BAT_3 = 3,
96 FSM_STATE_ATC_FAIL_4 = 4 ,
97 FSM_STATE_DELAY_5 = 5,
98 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
99 FSM_STATE_FAST_CHG_7 = 7,
100 FSM_STATE_TRKL_CHG_8 = 8,
101 FSM_STATE_CHG_FAIL_9 = 9,
102 FSM_STATE_EOC_10 = 10,
103 FSM_STATE_ON_CHG_VREGOK_11 = 11,
104 FSM_STATE_ATC_PAUSE_13 = 13,
105 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
106 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
107 FSM_STATE_START_BOOT = 20,
108 FSM_STATE_FLCB_VREGOK = 21,
109 FSM_STATE_FLCB = 22,
110};
111
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700112struct fsm_state_to_batt_status {
113 enum chg_fsm_state fsm_state;
114 int batt_state;
115};
116
117static struct fsm_state_to_batt_status map[] = {
118 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
119 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
120 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
121 /*
122 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
123 * too hot/cold, charger too hot
124 */
125 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
126 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
127 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
128 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
129 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
130 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
131 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
134 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
135 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
136 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
141 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
142 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
143};
144
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700145enum chg_regulation_loop {
146 VDD_LOOP = BIT(3),
147 BAT_CURRENT_LOOP = BIT(2),
148 INPUT_CURRENT_LOOP = BIT(1),
149 INPUT_VOLTAGE_LOOP = BIT(0),
150 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
151 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
152};
153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154enum pmic_chg_interrupts {
155 USBIN_VALID_IRQ = 0,
156 USBIN_OV_IRQ,
157 BATT_INSERTED_IRQ,
158 VBATDET_LOW_IRQ,
159 USBIN_UV_IRQ,
160 VBAT_OV_IRQ,
161 CHGWDOG_IRQ,
162 VCP_IRQ,
163 ATCDONE_IRQ,
164 ATCFAIL_IRQ,
165 CHGDONE_IRQ,
166 CHGFAIL_IRQ,
167 CHGSTATE_IRQ,
168 LOOP_CHANGE_IRQ,
169 FASTCHG_IRQ,
170 TRKLCHG_IRQ,
171 BATT_REMOVED_IRQ,
172 BATTTEMP_HOT_IRQ,
173 CHGHOT_IRQ,
174 BATTTEMP_COLD_IRQ,
175 CHG_GONE_IRQ,
176 BAT_TEMP_OK_IRQ,
177 COARSE_DET_LOW_IRQ,
178 VDD_LOOP_IRQ,
179 VREG_OV_IRQ,
180 VBATDET_IRQ,
181 BATFET_IRQ,
182 PSI_IRQ,
183 DCIN_VALID_IRQ,
184 DCIN_OV_IRQ,
185 DCIN_UV_IRQ,
186 PM_CHG_MAX_INTS,
187};
188
189struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700190 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 int is_charging;
192 struct work_struct work;
193};
194
195/**
196 * struct pm8921_chg_chip -device information
197 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 * @usb_present: present status of usb
199 * @dc_present: present status of dc
200 * @usb_charger_current: usb current to charge the battery with used when
201 * the usb path is enabled or charging is resumed
202 * @safety_time: max time for which charging will happen
203 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800204 * @max_voltage_mv: the max volts the batt should be charged up to
205 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700206 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800207 * @cool_temp_dc: the cool temp threshold in deciCelcius
208 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700209 * @resume_voltage_delta: the voltage delta from vdd max at which the
210 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 * @term_current: The charging based term current
212 *
213 */
214struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700215 struct device *dev;
216 unsigned int usb_present;
217 unsigned int dc_present;
218 unsigned int usb_charger_current;
219 unsigned int max_bat_chg_current;
220 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
221 unsigned int safety_time;
222 unsigned int ttrkl_time;
223 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800224 unsigned int max_voltage_mv;
225 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700226 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800227 int cool_temp_dc;
228 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700229 unsigned int temp_check_period;
230 unsigned int cool_bat_chg_current;
231 unsigned int warm_bat_chg_current;
232 unsigned int cool_bat_voltage;
233 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700234 unsigned int is_bat_cool;
235 unsigned int is_bat_warm;
236 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700237 unsigned int term_current;
238 unsigned int vbat_channel;
239 unsigned int batt_temp_channel;
240 unsigned int batt_id_channel;
241 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800242 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800243 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700244 struct power_supply batt_psy;
245 struct dentry *dent;
246 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800247 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200248 bool ext_charging;
249 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700250 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700252 struct work_struct battery_id_valid_work;
253 int64_t batt_id_min;
254 int64_t batt_id_max;
255 int trkl_voltage;
256 int weak_voltage;
257 int trkl_current;
258 int weak_current;
259 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800260 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700261 int thermal_levels;
262 struct delayed_work update_heartbeat_work;
263 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800264 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800265 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700266 struct wake_lock eoc_wake_lock;
267 enum pm8921_chg_cold_thr cold_thr;
268 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800269 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700270 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700271 bool host_mode;
David Keitel6ccbf132012-05-30 14:21:24 -0700272 u8 active_path;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273};
274
David Keitelacf57c82012-03-07 18:48:50 -0800275/* user space parameter to limit usb current */
276static unsigned int usb_max_current;
277/*
278 * usb_target_ma is used for wall charger
279 * adaptive input current limiting only. Use
280 * pm_iusbmax_get() to get current maximum usb current setting.
281 */
282static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700284static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285
286static struct pm8921_chg_chip *the_chip;
287
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700288static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
291 u8 mask, u8 val)
292{
293 int rc;
294 u8 reg;
295
296 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
297 if (rc) {
298 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
299 return rc;
300 }
301 reg &= ~mask;
302 reg |= val & mask;
303 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
304 if (rc) {
305 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
306 return rc;
307 }
308 return 0;
309}
310
David Keitelcf867232012-01-27 18:40:12 -0800311static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
312{
313 return pm8xxx_read_irq_stat(chip->dev->parent,
314 chip->pmic_chg_irq[irq_id]);
315}
316
317/* Treat OverVoltage/UnderVoltage as source missing */
318static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
319{
320 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
321}
322
323/* Treat OverVoltage/UnderVoltage as source missing */
324static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
325{
326 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
327}
328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329#define CAPTURE_FSM_STATE_CMD 0xC2
330#define READ_BANK_7 0x70
331#define READ_BANK_4 0x40
332static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
333{
334 u8 temp;
335 int err, ret = 0;
336
337 temp = CAPTURE_FSM_STATE_CMD;
338 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
339 if (err) {
340 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
341 return err;
342 }
343
344 temp = READ_BANK_7;
345 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
346 if (err) {
347 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
348 return err;
349 }
350
351 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
352 if (err) {
353 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
354 return err;
355 }
356 /* get the lower 4 bits */
357 ret = temp & 0xF;
358
359 temp = READ_BANK_4;
360 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
361 if (err) {
362 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
363 return err;
364 }
365
366 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
367 if (err) {
368 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
369 return err;
370 }
371 /* get the upper 1 bit */
372 ret |= (temp & 0x1) << 4;
373 return ret;
374}
375
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700376#define READ_BANK_6 0x60
377static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
378{
379 u8 temp;
380 int err;
381
382 temp = READ_BANK_6;
383 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
384 if (err) {
385 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
386 return err;
387 }
388
389 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
390 if (err) {
391 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
392 return err;
393 }
394
395 /* return the lower 4 bits */
396 return temp & CHG_ALL_LOOPS;
397}
398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399#define CHG_USB_SUSPEND_BIT BIT(2)
400static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
401{
402 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
403 enable ? CHG_USB_SUSPEND_BIT : 0);
404}
405
406#define CHG_EN_BIT BIT(7)
407static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
408{
409 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
410 enable ? CHG_EN_BIT : 0);
411}
412
David Keitel753ec8d2011-11-02 10:56:37 -0700413#define CHG_FAILED_CLEAR BIT(0)
414#define ATC_FAILED_CLEAR BIT(1)
415static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
416{
417 int rc;
418
419 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
420 clear ? ATC_FAILED_CLEAR : 0);
421 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
422 clear ? CHG_FAILED_CLEAR : 0);
423 return rc;
424}
425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426#define CHG_CHARGE_DIS_BIT BIT(1)
427static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
428{
429 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
430 disable ? CHG_CHARGE_DIS_BIT : 0);
431}
432
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800433static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
434{
435 u8 temp;
436
437 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
438 return temp & CHG_CHARGE_DIS_BIT;
439}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440#define PM8921_CHG_V_MIN_MV 3240
441#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800442#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443#define PM8921_CHG_VDDMAX_MAX 4500
444#define PM8921_CHG_VDDMAX_MIN 3400
445#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800446static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800448 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800449 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800451 if (voltage < PM8921_CHG_VDDMAX_MIN
452 || voltage > PM8921_CHG_VDDMAX_MAX) {
453 pr_err("bad mV=%d asked to set\n", voltage);
454 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 }
David Keitelcf867232012-01-27 18:40:12 -0800456
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800457 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
458
459 remainder = voltage % 20;
460 if (remainder >= 10) {
461 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
462 }
463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800465 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466}
467
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700468static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
469{
470 u8 temp;
471 int rc;
472
473 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
474 if (rc) {
475 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700476 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700477 return rc;
478 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800479 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
480 + PM8921_CHG_V_MIN_MV;
481 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
482 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700483 return 0;
484}
485
David Keitelcf867232012-01-27 18:40:12 -0800486static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
487{
488 int current_mv, ret, steps, i;
489 bool increase;
490
491 ret = 0;
492
493 if (voltage < PM8921_CHG_VDDMAX_MIN
494 || voltage > PM8921_CHG_VDDMAX_MAX) {
495 pr_err("bad mV=%d asked to set\n", voltage);
496 return -EINVAL;
497 }
498
499 ret = pm_chg_vddmax_get(chip, &current_mv);
500 if (ret) {
501 pr_err("Failed to read vddmax rc=%d\n", ret);
502 return -EINVAL;
503 }
504 if (current_mv == voltage)
505 return 0;
506
507 /* Only change in increments when USB is present */
508 if (is_usb_chg_plugged_in(chip)) {
509 if (current_mv < voltage) {
510 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
511 increase = true;
512 } else {
513 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
514 increase = false;
515 }
516 for (i = 0; i < steps; i++) {
517 if (increase)
518 current_mv += PM8921_CHG_V_STEP_MV;
519 else
520 current_mv -= PM8921_CHG_V_STEP_MV;
521 ret |= __pm_chg_vddmax_set(chip, current_mv);
522 }
523 }
524 ret |= __pm_chg_vddmax_set(chip, voltage);
525 return ret;
526}
527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528#define PM8921_CHG_VDDSAFE_MIN 3400
529#define PM8921_CHG_VDDSAFE_MAX 4500
530static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
531{
532 u8 temp;
533
534 if (voltage < PM8921_CHG_VDDSAFE_MIN
535 || voltage > PM8921_CHG_VDDSAFE_MAX) {
536 pr_err("bad mV=%d asked to set\n", voltage);
537 return -EINVAL;
538 }
539 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
540 pr_debug("voltage=%d setting %02x\n", voltage, temp);
541 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
542}
543
544#define PM8921_CHG_VBATDET_MIN 3240
545#define PM8921_CHG_VBATDET_MAX 5780
546static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
547{
548 u8 temp;
549
550 if (voltage < PM8921_CHG_VBATDET_MIN
551 || voltage > PM8921_CHG_VBATDET_MAX) {
552 pr_err("bad mV=%d asked to set\n", voltage);
553 return -EINVAL;
554 }
555 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
556 pr_debug("voltage=%d setting %02x\n", voltage, temp);
557 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
558}
559
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700560#define PM8921_CHG_VINMIN_MIN_MV 3800
561#define PM8921_CHG_VINMIN_STEP_MV 100
562#define PM8921_CHG_VINMIN_USABLE_MAX 6500
563#define PM8921_CHG_VINMIN_USABLE_MIN 4300
564#define PM8921_CHG_VINMIN_MASK 0x1F
565static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
566{
567 u8 temp;
568
569 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
570 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
571 pr_err("bad mV=%d asked to set\n", voltage);
572 return -EINVAL;
573 }
574 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
575 pr_debug("voltage=%d setting %02x\n", voltage, temp);
576 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
577 temp);
578}
579
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800580static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
581{
582 u8 temp;
583 int rc, voltage_mv;
584
585 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
586 temp &= PM8921_CHG_VINMIN_MASK;
587
588 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
589 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
590
591 return voltage_mv;
592}
593
David Keitel0789fc62012-06-07 17:43:27 -0700594#define PM8917_USB_UVD_MIN_MV 3850
595#define PM8917_USB_UVD_MAX_MV 4350
596#define PM8917_USB_UVD_STEP_MV 100
597#define PM8917_USB_UVD_MASK 0x7
598static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
599{
600 u8 temp;
601
602 if (thresh_mv < PM8917_USB_UVD_MIN_MV
603 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
604 pr_err("bad mV=%d asked to set\n", thresh_mv);
605 return -EINVAL;
606 }
607 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
608 return pm_chg_masked_write(chip, OVP_USB_UVD,
609 PM8917_USB_UVD_MASK, temp);
610}
611
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612#define PM8921_CHG_IBATMAX_MIN 325
613#define PM8921_CHG_IBATMAX_MAX 2000
614#define PM8921_CHG_I_MIN_MA 225
615#define PM8921_CHG_I_STEP_MA 50
616#define PM8921_CHG_I_MASK 0x3F
617static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
618{
619 u8 temp;
620
621 if (chg_current < PM8921_CHG_IBATMAX_MIN
622 || chg_current > PM8921_CHG_IBATMAX_MAX) {
623 pr_err("bad mA=%d asked to set\n", chg_current);
624 return -EINVAL;
625 }
626 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
627 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
628}
629
630#define PM8921_CHG_IBATSAFE_MIN 225
631#define PM8921_CHG_IBATSAFE_MAX 3375
632static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
633{
634 u8 temp;
635
636 if (chg_current < PM8921_CHG_IBATSAFE_MIN
637 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
638 pr_err("bad mA=%d asked to set\n", chg_current);
639 return -EINVAL;
640 }
641 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
642 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
643 PM8921_CHG_I_MASK, temp);
644}
645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700647#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648#define PM8921_CHG_ITERM_STEP_MA 10
649#define PM8921_CHG_ITERM_MASK 0xF
650static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
651{
652 u8 temp;
653
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700654 if (chg_current < PM8921_CHG_ITERM_MIN_MA
655 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 pr_err("bad mA=%d asked to set\n", chg_current);
657 return -EINVAL;
658 }
659
660 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
661 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700662 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 temp);
664}
665
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700666static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
667{
668 u8 temp;
669 int rc;
670
671 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
672 if (rc) {
673 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700674 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700675 return rc;
676 }
677 temp &= PM8921_CHG_ITERM_MASK;
678 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
679 + PM8921_CHG_ITERM_MIN_MA;
680 return 0;
681}
682
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800683struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700684 int usb_ma;
685 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800686};
687
688static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700689 {100, 0x0},
690 {200, 0x1},
691 {500, 0x2},
692 {600, 0x3},
693 {700, 0x4},
694 {800, 0x5},
695 {850, 0x6},
696 {900, 0x8},
697 {950, 0x7},
698 {1000, 0x9},
699 {1100, 0xA},
700 {1200, 0xB},
701 {1300, 0xC},
702 {1400, 0xD},
703 {1500, 0xE},
704 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800705};
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700708#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709#define PM8921_CHG_IUSB_MAX 7
710#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700711#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700712static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713{
David Keitel38bdd4f2012-04-19 15:39:13 -0700714 u8 temp, fineres;
715 int rc;
716
717 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
718 reg_val = usb_ma_table[reg_val].value >> 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700720 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
721 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 return -EINVAL;
723 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700724 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
725
726 /* IUSB_FINE_RES */
727 if (chip->iusb_fine_res) {
728 /* Clear IUSB_FINE_RES bit to avoid overshoot */
729 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
730 PM8917_IUSB_FINE_RES, 0);
731
732 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
733 PM8921_CHG_IUSB_MASK, temp);
734
735 if (rc) {
736 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
737 return rc;
738 }
739
740 if (fineres) {
741 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
742 PM8917_IUSB_FINE_RES, fineres);
743 if (rc)
744 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
745 rc);
746 }
747 } else {
748 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
749 PM8921_CHG_IUSB_MASK, temp);
750 if (rc)
751 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
752 }
753
754 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755}
756
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800757static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
758{
David Keitel38bdd4f2012-04-19 15:39:13 -0700759 u8 temp, fineres;
760 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800761
David Keitel38bdd4f2012-04-19 15:39:13 -0700762 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800763 *mA = 0;
764 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
765 if (rc) {
766 pr_err("err=%d reading PBL_ACCESS2\n", rc);
767 return rc;
768 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700769
770 if (chip->iusb_fine_res) {
771 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
772 if (rc) {
773 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
774 return rc;
775 }
776 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800777 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -0700778 temp = temp >> PM8921_CHG_IUSB_SHIFT;
779
780 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
781 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
782 if (usb_ma_table[i].value == temp)
783 break;
784 }
785
786 *mA = usb_ma_table[i].usb_ma;
787
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800788 return rc;
789}
790
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791#define PM8921_CHG_WD_MASK 0x1F
792static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
793{
794 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700795 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
796}
797
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700798#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700799#define PM8921_CHG_TCHG_MIN 4
800#define PM8921_CHG_TCHG_MAX 512
801#define PM8921_CHG_TCHG_STEP 4
802static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
803{
804 u8 temp;
805
806 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
807 pr_err("bad max minutes =%d asked to set\n", minutes);
808 return -EINVAL;
809 }
810
811 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
812 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
813 temp);
814}
815
816#define PM8921_CHG_TTRKL_MASK 0x1F
817#define PM8921_CHG_TTRKL_MIN 1
818#define PM8921_CHG_TTRKL_MAX 64
819static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
820{
821 u8 temp;
822
823 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
824 pr_err("bad max minutes =%d asked to set\n", minutes);
825 return -EINVAL;
826 }
827
828 temp = minutes - 1;
829 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
830 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831}
832
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700833#define PM8921_CHG_VTRKL_MIN_MV 2050
834#define PM8921_CHG_VTRKL_MAX_MV 2800
835#define PM8921_CHG_VTRKL_STEP_MV 50
836#define PM8921_CHG_VTRKL_SHIFT 4
837#define PM8921_CHG_VTRKL_MASK 0xF0
838static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
839{
840 u8 temp;
841
842 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
843 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
844 pr_err("bad voltage = %dmV asked to set\n", millivolts);
845 return -EINVAL;
846 }
847
848 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
849 temp = temp << PM8921_CHG_VTRKL_SHIFT;
850 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
851 temp);
852}
853
854#define PM8921_CHG_VWEAK_MIN_MV 2100
855#define PM8921_CHG_VWEAK_MAX_MV 3600
856#define PM8921_CHG_VWEAK_STEP_MV 100
857#define PM8921_CHG_VWEAK_MASK 0x0F
858static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
859{
860 u8 temp;
861
862 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
863 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
864 pr_err("bad voltage = %dmV asked to set\n", millivolts);
865 return -EINVAL;
866 }
867
868 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
869 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
870 temp);
871}
872
873#define PM8921_CHG_ITRKL_MIN_MA 50
874#define PM8921_CHG_ITRKL_MAX_MA 200
875#define PM8921_CHG_ITRKL_MASK 0x0F
876#define PM8921_CHG_ITRKL_STEP_MA 10
877static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
878{
879 u8 temp;
880
881 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
882 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
883 pr_err("bad current = %dmA asked to set\n", milliamps);
884 return -EINVAL;
885 }
886
887 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
888
889 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
890 temp);
891}
892
893#define PM8921_CHG_IWEAK_MIN_MA 325
894#define PM8921_CHG_IWEAK_MAX_MA 525
895#define PM8921_CHG_IWEAK_SHIFT 7
896#define PM8921_CHG_IWEAK_MASK 0x80
897static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
898{
899 u8 temp;
900
901 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
902 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
903 pr_err("bad current = %dmA asked to set\n", milliamps);
904 return -EINVAL;
905 }
906
907 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
908 temp = 0;
909 else
910 temp = 1;
911
912 temp = temp << PM8921_CHG_IWEAK_SHIFT;
913 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
914 temp);
915}
916
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700917#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
918#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
919static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
920 enum pm8921_chg_cold_thr cold_thr)
921{
922 u8 temp;
923
924 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
925 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
926 return pm_chg_masked_write(chip, CHG_CNTRL_2,
927 PM8921_CHG_BATT_TEMP_THR_COLD,
928 temp);
929}
930
931#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
932#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
933static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
934 enum pm8921_chg_hot_thr hot_thr)
935{
936 u8 temp;
937
938 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
939 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
940 return pm_chg_masked_write(chip, CHG_CNTRL_2,
941 PM8921_CHG_BATT_TEMP_THR_HOT,
942 temp);
943}
944
Jay Chokshid674a512012-03-15 14:06:04 -0700945#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
946#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
947static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
948 enum pm8921_chg_led_src_config led_src_config)
949{
950 u8 temp;
951
952 if (led_src_config < LED_SRC_GND ||
953 led_src_config > LED_SRC_BYPASS)
954 return -EINVAL;
955
956 if (led_src_config == LED_SRC_BYPASS)
957 return 0;
958
959 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
960
961 return pm_chg_masked_write(chip, CHG_CNTRL_3,
962 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
963}
964
David Keitel8c5201a2012-02-24 16:08:54 -0800965static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
966{
967 u8 temp;
968 int rc;
969
970 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
971 if (rc) {
972 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
973 return;
974 }
975 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
976 if (rc) {
977 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
978 return;
979 }
980 /* set the input voltage disable bit and the write bit */
981 temp |= 0x81;
982 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
983 if (rc) {
984 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
985 return;
986 }
987}
988
989static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
990{
991 u8 temp;
992 int rc;
993
994 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
995 if (rc) {
996 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
997 return;
998 }
999 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
1000 if (rc) {
1001 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
1002 return;
1003 }
1004 /* unset the input voltage disable bit */
1005 temp &= 0xFE;
1006 /* set the write bit */
1007 temp |= 0x80;
1008 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1009 if (rc) {
1010 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
1011 return;
1012 }
1013}
1014
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001015static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1016{
1017 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001018 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001019
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001020 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001021 if (rc) {
1022 pr_err("error reading batt id channel = %d, rc = %d\n",
1023 chip->vbat_channel, rc);
1024 return rc;
1025 }
1026 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1027 result.measurement);
1028 return result.physical;
1029}
1030
1031static int is_battery_valid(struct pm8921_chg_chip *chip)
1032{
1033 int64_t rc;
1034
1035 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1036 return 1;
1037
1038 rc = read_battery_id(chip);
1039 if (rc < 0) {
1040 pr_err("error reading batt id channel = %d, rc = %lld\n",
1041 chip->vbat_channel, rc);
1042 /* assume battery id is valid when adc error happens */
1043 return 1;
1044 }
1045
1046 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1047 pr_err("batt_id phy =%lld is not valid\n", rc);
1048 return 0;
1049 }
1050 return 1;
1051}
1052
1053static void check_battery_valid(struct pm8921_chg_chip *chip)
1054{
1055 if (is_battery_valid(chip) == 0) {
1056 pr_err("batt_id not valid, disbling charging\n");
1057 pm_chg_auto_enable(chip, 0);
1058 } else {
1059 pm_chg_auto_enable(chip, !charging_disabled);
1060 }
1061}
1062
1063static void battery_id_valid(struct work_struct *work)
1064{
1065 struct pm8921_chg_chip *chip = container_of(work,
1066 struct pm8921_chg_chip, battery_id_valid_work);
1067
1068 check_battery_valid(chip);
1069}
1070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1072{
1073 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1074 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1075 enable_irq(chip->pmic_chg_irq[interrupt]);
1076 }
1077}
1078
1079static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1080{
1081 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1082 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1083 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1084 }
1085}
1086
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001087static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1088{
1089 return test_bit(interrupt, chip->enabled_irqs);
1090}
1091
Amir Samuelovd31ef502011-10-26 14:41:36 +02001092static bool is_ext_charging(struct pm8921_chg_chip *chip)
1093{
David Keitel88e1b572012-01-11 11:57:14 -08001094 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001095
David Keitel88e1b572012-01-11 11:57:14 -08001096 if (!chip->ext_psy)
1097 return false;
1098 if (chip->ext_psy->get_property(chip->ext_psy,
1099 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1100 return false;
1101 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1102 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001103
1104 return false;
1105}
1106
1107static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1108{
David Keitel88e1b572012-01-11 11:57:14 -08001109 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001110
David Keitel88e1b572012-01-11 11:57:14 -08001111 if (!chip->ext_psy)
1112 return false;
1113 if (chip->ext_psy->get_property(chip->ext_psy,
1114 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1115 return false;
1116 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001117 return true;
1118
1119 return false;
1120}
1121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122static int is_battery_charging(int fsm_state)
1123{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001124 if (is_ext_charging(the_chip))
1125 return 1;
1126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 switch (fsm_state) {
1128 case FSM_STATE_ATC_2A:
1129 case FSM_STATE_ATC_2B:
1130 case FSM_STATE_ON_CHG_AND_BAT_6:
1131 case FSM_STATE_FAST_CHG_7:
1132 case FSM_STATE_TRKL_CHG_8:
1133 return 1;
1134 }
1135 return 0;
1136}
1137
1138static void bms_notify(struct work_struct *work)
1139{
1140 struct bms_notify *n = container_of(work, struct bms_notify, work);
1141
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001142 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001144 } else {
1145 pm8921_bms_charging_end(n->is_battery_full);
1146 n->is_battery_full = 0;
1147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148}
1149
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001150static void bms_notify_check(struct pm8921_chg_chip *chip)
1151{
1152 int fsm_state, new_is_charging;
1153
1154 fsm_state = pm_chg_get_fsm_state(chip);
1155 new_is_charging = is_battery_charging(fsm_state);
1156
1157 if (chip->bms_notify.is_charging ^ new_is_charging) {
1158 chip->bms_notify.is_charging = new_is_charging;
1159 schedule_work(&(chip->bms_notify.work));
1160 }
1161}
1162
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001163static enum power_supply_property pm_power_props_usb[] = {
1164 POWER_SUPPLY_PROP_PRESENT,
1165 POWER_SUPPLY_PROP_ONLINE,
1166 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001167 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001168};
1169
1170static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001172 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173};
1174
1175static char *pm_power_supplied_to[] = {
1176 "battery",
1177};
1178
David Keitel6ed71a52012-01-30 12:42:18 -08001179#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001180static int pm_power_get_property_mains(struct power_supply *psy,
1181 enum power_supply_property psp,
1182 union power_supply_propval *val)
1183{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001184 /* Check if called before init */
1185 if (!the_chip)
1186 return -EINVAL;
1187
1188 switch (psp) {
1189 case POWER_SUPPLY_PROP_PRESENT:
1190 case POWER_SUPPLY_PROP_ONLINE:
1191 val->intval = 0;
1192 if (charging_disabled)
1193 return 0;
1194
1195 /* check external charger first before the dc path */
1196 if (is_ext_charging(the_chip)) {
1197 val->intval = 1;
1198 return 0;
1199 }
1200
1201 if (pm_is_chg_charge_dis(the_chip)) {
1202 val->intval = 0;
1203 return 0;
1204 }
1205
1206 if (the_chip->dc_present) {
1207 val->intval = 1;
1208 return 0;
1209 }
1210
1211 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001212 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001213 val->intval = is_usb_chg_plugged_in(the_chip);
1214 return 0;
1215
1216 break;
1217 default:
1218 return -EINVAL;
1219 }
1220 return 0;
1221}
1222
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001223static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1224{
1225 int rc;
1226
1227 if (!chip->host_mode)
1228 return 0;
1229
1230 /* enable usbin valid comparator and remove force usb ovp fet off */
1231 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB2);
1232 if (rc < 0) {
1233 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1234 return rc;
1235 }
1236
1237 chip->host_mode = 0;
1238
1239 return 0;
1240}
1241
1242static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1243{
1244 int rc;
1245
1246 if (chip->host_mode)
1247 return 0;
1248
1249 /* disable usbin valid comparator and force usb ovp fet off */
1250 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB3);
1251 if (rc < 0) {
1252 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1253 return rc;
1254 }
1255
1256 chip->host_mode = 1;
1257
1258 return 0;
1259}
1260
1261static int pm_power_set_property_usb(struct power_supply *psy,
1262 enum power_supply_property psp,
1263 const union power_supply_propval *val)
1264{
1265 /* Check if called before init */
1266 if (!the_chip)
1267 return -EINVAL;
1268
1269 switch (psp) {
1270 case POWER_SUPPLY_PROP_SCOPE:
1271 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
1272 return switch_usb_to_host_mode(the_chip);
1273 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
1274 return switch_usb_to_charge_mode(the_chip);
1275 else
1276 return -EINVAL;
1277 break;
1278 default:
1279 return -EINVAL;
1280 }
1281 return 0;
1282}
1283
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001284static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285 enum power_supply_property psp,
1286 union power_supply_propval *val)
1287{
David Keitel6ed71a52012-01-30 12:42:18 -08001288 int current_max;
1289
1290 /* Check if called before init */
1291 if (!the_chip)
1292 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293
1294 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001295 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001296 if (pm_is_chg_charge_dis(the_chip)) {
1297 val->intval = 0;
1298 } else {
1299 pm_chg_iusbmax_get(the_chip, &current_max);
1300 val->intval = current_max;
1301 }
David Keitel6ed71a52012-01-30 12:42:18 -08001302 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001304 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001305 val->intval = 0;
1306 if (charging_disabled)
1307 return 0;
1308
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001309 /*
1310 * if drawing any current from usb is disabled behave
1311 * as if no usb cable is connected
1312 */
1313 if (pm_is_chg_charge_dis(the_chip))
1314 return 0;
1315
David Keitel63f71662012-02-08 20:30:00 -08001316 /* USB charging */
David Keitelaf515712012-04-13 17:25:31 -07001317 if (usb_target_ma < USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001318 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001319 else
1320 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001321 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001322
1323 case POWER_SUPPLY_PROP_SCOPE:
1324 if (the_chip->host_mode)
1325 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1326 else
1327 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1328 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329 default:
1330 return -EINVAL;
1331 }
1332 return 0;
1333}
1334
1335static enum power_supply_property msm_batt_power_props[] = {
1336 POWER_SUPPLY_PROP_STATUS,
1337 POWER_SUPPLY_PROP_CHARGE_TYPE,
1338 POWER_SUPPLY_PROP_HEALTH,
1339 POWER_SUPPLY_PROP_PRESENT,
1340 POWER_SUPPLY_PROP_TECHNOLOGY,
1341 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1342 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1343 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1344 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001345 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001346 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001347 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348};
1349
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001350static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351{
1352 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001353 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001355 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 if (rc) {
1357 pr_err("error reading adc channel = %d, rc = %d\n",
1358 chip->vbat_channel, rc);
1359 return rc;
1360 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001361 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 result.measurement);
1363 return (int)result.physical;
1364}
1365
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001366static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1367{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001368 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1369 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1370 unsigned int low_voltage = chip->min_voltage_mv;
1371 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001372
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001373 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001374 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001375 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001376 return 100;
1377 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001378 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001379 / (high_voltage - low_voltage);
1380}
1381
David Keitel4f9397b2012-04-16 11:46:16 -07001382static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1383{
1384 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1385}
1386
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1388{
David Keitel4f9397b2012-04-16 11:46:16 -07001389 int percent_soc;
1390
1391 if (!get_prop_batt_present(chip))
1392 percent_soc = voltage_based_capacity(chip);
1393 else
1394 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001395
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001396 if (percent_soc == -ENXIO)
1397 percent_soc = voltage_based_capacity(chip);
1398
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001399 if (percent_soc <= 10)
1400 pr_warn("low battery charge = %d%%\n", percent_soc);
1401
1402 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403}
1404
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001405static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1406{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001407 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001408
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001409 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001410 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001411 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001412 }
1413
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001414 if (rc) {
1415 pr_err("unable to get batt current rc = %d\n", rc);
1416 return rc;
1417 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001418 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001419 }
1420}
1421
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001422static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1423{
1424 int rc;
1425
1426 rc = pm8921_bms_get_fcc();
1427 if (rc < 0)
1428 pr_err("unable to get batt fcc rc = %d\n", rc);
1429 return rc;
1430}
1431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1433{
1434 int temp;
1435
1436 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1437 if (temp)
1438 return POWER_SUPPLY_HEALTH_OVERHEAT;
1439
1440 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1441 if (temp)
1442 return POWER_SUPPLY_HEALTH_COLD;
1443
1444 return POWER_SUPPLY_HEALTH_GOOD;
1445}
1446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1448{
1449 int temp;
1450
Amir Samuelovd31ef502011-10-26 14:41:36 +02001451 if (!get_prop_batt_present(chip))
1452 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1453
1454 if (is_ext_trickle_charging(chip))
1455 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1456
1457 if (is_ext_charging(chip))
1458 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1461 if (temp)
1462 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1463
1464 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1465 if (temp)
1466 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1467
1468 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1469}
1470
1471static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1472{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001473 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1474 int fsm_state = pm_chg_get_fsm_state(chip);
1475 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476
David Keitel88e1b572012-01-11 11:57:14 -08001477 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001478 if (chip->ext_charge_done)
1479 return POWER_SUPPLY_STATUS_FULL;
1480 if (chip->ext_charging)
1481 return POWER_SUPPLY_STATUS_CHARGING;
1482 }
1483
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001484 for (i = 0; i < ARRAY_SIZE(map); i++)
1485 if (map[i].fsm_state == fsm_state)
1486 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001487
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001488 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1489 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1490 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001491 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1492 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001493
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001494 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001495 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001496 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497}
1498
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001499#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001500static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1501{
1502 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001503 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001504
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001505 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001506 if (rc) {
1507 pr_err("error reading adc channel = %d, rc = %d\n",
1508 chip->vbat_channel, rc);
1509 return rc;
1510 }
1511 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1512 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001513 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1514 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1515 (int) result.physical);
1516
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001517 return (int)result.physical;
1518}
1519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520static int pm_batt_power_get_property(struct power_supply *psy,
1521 enum power_supply_property psp,
1522 union power_supply_propval *val)
1523{
1524 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1525 batt_psy);
1526
1527 switch (psp) {
1528 case POWER_SUPPLY_PROP_STATUS:
1529 val->intval = get_prop_batt_status(chip);
1530 break;
1531 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1532 val->intval = get_prop_charge_type(chip);
1533 break;
1534 case POWER_SUPPLY_PROP_HEALTH:
1535 val->intval = get_prop_batt_health(chip);
1536 break;
1537 case POWER_SUPPLY_PROP_PRESENT:
1538 val->intval = get_prop_batt_present(chip);
1539 break;
1540 case POWER_SUPPLY_PROP_TECHNOLOGY:
1541 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1542 break;
1543 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001544 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 break;
1546 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001547 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 break;
1549 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001550 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 break;
1552 case POWER_SUPPLY_PROP_CAPACITY:
1553 val->intval = get_prop_batt_capacity(chip);
1554 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001555 case POWER_SUPPLY_PROP_CURRENT_NOW:
1556 val->intval = get_prop_batt_current(chip);
1557 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001558 case POWER_SUPPLY_PROP_TEMP:
1559 val->intval = get_prop_batt_temp(chip);
1560 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001561 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001562 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001563 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 default:
1565 return -EINVAL;
1566 }
1567
1568 return 0;
1569}
1570
1571static void (*notify_vbus_state_func_ptr)(int);
1572static int usb_chg_current;
1573static DEFINE_SPINLOCK(vbus_lock);
1574
1575int pm8921_charger_register_vbus_sn(void (*callback)(int))
1576{
1577 pr_debug("%p\n", callback);
1578 notify_vbus_state_func_ptr = callback;
1579 return 0;
1580}
1581EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1582
1583/* this is passed to the hsusb via platform_data msm_otg_pdata */
1584void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1585{
1586 pr_debug("%p\n", callback);
1587 notify_vbus_state_func_ptr = NULL;
1588}
1589EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1590
1591static void notify_usb_of_the_plugin_event(int plugin)
1592{
1593 plugin = !!plugin;
1594 if (notify_vbus_state_func_ptr) {
1595 pr_debug("notifying plugin\n");
1596 (*notify_vbus_state_func_ptr) (plugin);
1597 } else {
1598 pr_debug("unable to notify plugin\n");
1599 }
1600}
1601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602/* assumes vbus_lock is held */
1603static void __pm8921_charger_vbus_draw(unsigned int mA)
1604{
1605 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001606 if (!the_chip) {
1607 pr_err("called before init\n");
1608 return;
1609 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610
David Keitel38bdd4f2012-04-19 15:39:13 -07001611 if (mA >= 0 && mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001612 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001613 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001615 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 }
1617 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1618 if (rc)
1619 pr_err("fail to set suspend bit rc=%d\n", rc);
1620 } else {
1621 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1622 if (rc)
1623 pr_err("fail to reset suspend bit rc=%d\n", rc);
1624 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1625 if (usb_ma_table[i].usb_ma <= mA)
1626 break;
1627 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001628
1629 /* Check if IUSB_FINE_RES is available */
1630 if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
1631 && !the_chip->iusb_fine_res)
1632 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 if (i < 0)
1634 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001635 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001637 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 }
1639 }
1640}
1641
1642/* USB calls these to tell us how much max usb current the system can draw */
1643void pm8921_charger_vbus_draw(unsigned int mA)
1644{
1645 unsigned long flags;
1646
1647 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001648
David Keitel62c6a4b2012-05-17 12:54:59 -07001649 if (!the_chip) {
1650 pr_err("chip not yet initalized\n");
1651 return;
1652 }
1653
1654 /*
1655 * Reject VBUS requests if USB connection is the only available
1656 * power source. This makes sure that if booting without
1657 * battery the iusb_max value is not decreased avoiding potential
1658 * brown_outs.
1659 *
1660 * This would also apply when the battery has been
1661 * removed from the running system.
1662 */
1663 if (!get_prop_batt_present(the_chip)
1664 && !is_dc_chg_plugged_in(the_chip)) {
1665 pr_err("rejected: no other power source connected\n");
1666 return;
1667 }
1668
David Keitelacf57c82012-03-07 18:48:50 -08001669 if (usb_max_current && mA > usb_max_current) {
1670 pr_warn("restricting usb current to %d instead of %d\n",
1671 usb_max_current, mA);
1672 mA = usb_max_current;
1673 }
1674 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1675 usb_target_ma = mA;
1676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 spin_lock_irqsave(&vbus_lock, flags);
1678 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001679 if (mA > USB_WALL_THRESHOLD_MA)
1680 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1681 else
1682 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 } else {
1684 /*
1685 * called before pmic initialized,
1686 * save this value and use it at probe
1687 */
David Keitelacf57c82012-03-07 18:48:50 -08001688 if (mA > USB_WALL_THRESHOLD_MA)
1689 usb_chg_current = USB_WALL_THRESHOLD_MA;
1690 else
1691 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 }
1693 spin_unlock_irqrestore(&vbus_lock, flags);
1694}
1695EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1696
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001697int pm8921_charger_enable(bool enable)
1698{
1699 int rc;
1700
1701 if (!the_chip) {
1702 pr_err("called before init\n");
1703 return -EINVAL;
1704 }
1705 enable = !!enable;
1706 rc = pm_chg_auto_enable(the_chip, enable);
1707 if (rc)
1708 pr_err("Failed rc=%d\n", rc);
1709 return rc;
1710}
1711EXPORT_SYMBOL(pm8921_charger_enable);
1712
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001713int pm8921_is_usb_chg_plugged_in(void)
1714{
1715 if (!the_chip) {
1716 pr_err("called before init\n");
1717 return -EINVAL;
1718 }
1719 return is_usb_chg_plugged_in(the_chip);
1720}
1721EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1722
1723int pm8921_is_dc_chg_plugged_in(void)
1724{
1725 if (!the_chip) {
1726 pr_err("called before init\n");
1727 return -EINVAL;
1728 }
1729 return is_dc_chg_plugged_in(the_chip);
1730}
1731EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1732
1733int pm8921_is_battery_present(void)
1734{
1735 if (!the_chip) {
1736 pr_err("called before init\n");
1737 return -EINVAL;
1738 }
1739 return get_prop_batt_present(the_chip);
1740}
1741EXPORT_SYMBOL(pm8921_is_battery_present);
1742
David Keitel012deef2011-12-02 11:49:33 -08001743/*
1744 * Disabling the charge current limit causes current
1745 * current limits to have no monitoring. An adequate charger
1746 * capable of supplying high current while sustaining VIN_MIN
1747 * is required if the limiting is disabled.
1748 */
1749int pm8921_disable_input_current_limit(bool disable)
1750{
1751 if (!the_chip) {
1752 pr_err("called before init\n");
1753 return -EINVAL;
1754 }
1755 if (disable) {
1756 pr_warn("Disabling input current limit!\n");
1757
1758 return pm8xxx_writeb(the_chip->dev->parent,
1759 CHG_BUCK_CTRL_TEST3, 0xF2);
1760 }
1761 return 0;
1762}
1763EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1764
David Keitel0789fc62012-06-07 17:43:27 -07001765int pm8917_set_under_voltage_detection_threshold(int mv)
1766{
1767 if (!the_chip) {
1768 pr_err("called before init\n");
1769 return -EINVAL;
1770 }
1771 return pm_chg_uvd_threshold_set(the_chip, mv);
1772}
1773EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
1774
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001775int pm8921_set_max_battery_charge_current(int ma)
1776{
1777 if (!the_chip) {
1778 pr_err("called before init\n");
1779 return -EINVAL;
1780 }
1781 return pm_chg_ibatmax_set(the_chip, ma);
1782}
1783EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1784
1785int pm8921_disable_source_current(bool disable)
1786{
1787 if (!the_chip) {
1788 pr_err("called before init\n");
1789 return -EINVAL;
1790 }
1791 if (disable)
1792 pr_warn("current drawn from chg=0, battery provides current\n");
1793 return pm_chg_charge_dis(the_chip, disable);
1794}
1795EXPORT_SYMBOL(pm8921_disable_source_current);
1796
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001797int pm8921_regulate_input_voltage(int voltage)
1798{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001799 int rc;
1800
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001801 if (!the_chip) {
1802 pr_err("called before init\n");
1803 return -EINVAL;
1804 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001805 rc = pm_chg_vinmin_set(the_chip, voltage);
1806
1807 if (rc == 0)
1808 the_chip->vin_min = voltage;
1809
1810 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001811}
1812
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001813#define USB_OV_THRESHOLD_MASK 0x60
1814#define USB_OV_THRESHOLD_SHIFT 5
1815int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1816{
1817 u8 temp;
1818
1819 if (!the_chip) {
1820 pr_err("called before init\n");
1821 return -EINVAL;
1822 }
1823
1824 if (ov > PM_USB_OV_7V) {
1825 pr_err("limiting to over voltage threshold to 7volts\n");
1826 ov = PM_USB_OV_7V;
1827 }
1828
1829 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1830
1831 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1832 USB_OV_THRESHOLD_MASK, temp);
1833}
1834EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1835
1836#define USB_DEBOUNCE_TIME_MASK 0x06
1837#define USB_DEBOUNCE_TIME_SHIFT 1
1838int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1839{
1840 u8 temp;
1841
1842 if (!the_chip) {
1843 pr_err("called before init\n");
1844 return -EINVAL;
1845 }
1846
1847 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1848 pr_err("limiting debounce to 80.5ms\n");
1849 ms = PM_USB_DEBOUNCE_80P5MS;
1850 }
1851
1852 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1853
1854 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1855 USB_DEBOUNCE_TIME_MASK, temp);
1856}
1857EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1858
1859#define USB_OVP_DISABLE_MASK 0x80
1860int pm8921_usb_ovp_disable(int disable)
1861{
1862 u8 temp = 0;
1863
1864 if (!the_chip) {
1865 pr_err("called before init\n");
1866 return -EINVAL;
1867 }
1868
1869 if (disable)
1870 temp = USB_OVP_DISABLE_MASK;
1871
1872 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1873 USB_OVP_DISABLE_MASK, temp);
1874}
1875
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001876bool pm8921_is_battery_charging(int *source)
1877{
1878 int fsm_state, is_charging, dc_present, usb_present;
1879
1880 if (!the_chip) {
1881 pr_err("called before init\n");
1882 return -EINVAL;
1883 }
1884 fsm_state = pm_chg_get_fsm_state(the_chip);
1885 is_charging = is_battery_charging(fsm_state);
1886 if (is_charging == 0) {
1887 *source = PM8921_CHG_SRC_NONE;
1888 return is_charging;
1889 }
1890
1891 if (source == NULL)
1892 return is_charging;
1893
1894 /* the battery is charging, the source is requested, find it */
1895 dc_present = is_dc_chg_plugged_in(the_chip);
1896 usb_present = is_usb_chg_plugged_in(the_chip);
1897
1898 if (dc_present && !usb_present)
1899 *source = PM8921_CHG_SRC_DC;
1900
1901 if (usb_present && !dc_present)
1902 *source = PM8921_CHG_SRC_USB;
1903
1904 if (usb_present && dc_present)
1905 /*
1906 * The system always chooses dc for charging since it has
1907 * higher priority.
1908 */
1909 *source = PM8921_CHG_SRC_DC;
1910
1911 return is_charging;
1912}
1913EXPORT_SYMBOL(pm8921_is_battery_charging);
1914
David Keitel86034022012-04-18 12:33:58 -07001915int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1916{
1917 if (!the_chip) {
1918 pr_err("called before init\n");
1919 return -EINVAL;
1920 }
1921
1922 if (type < POWER_SUPPLY_TYPE_USB)
1923 return -EINVAL;
1924
1925 the_chip->usb_psy.type = type;
1926 power_supply_changed(&the_chip->usb_psy);
1927 power_supply_changed(&the_chip->dc_psy);
1928 return 0;
1929}
1930EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1931
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001932int pm8921_batt_temperature(void)
1933{
1934 if (!the_chip) {
1935 pr_err("called before init\n");
1936 return -EINVAL;
1937 }
1938 return get_prop_batt_temp(the_chip);
1939}
1940
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1942{
1943 int usb_present;
1944
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001945 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 usb_present = is_usb_chg_plugged_in(chip);
1947 if (chip->usb_present ^ usb_present) {
1948 notify_usb_of_the_plugin_event(usb_present);
1949 chip->usb_present = usb_present;
1950 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001951 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001952 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001954 if (usb_present) {
1955 schedule_delayed_work(&chip->unplug_check_work,
1956 round_jiffies_relative(msecs_to_jiffies
1957 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001958 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1959 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001960 /* USB unplugged reset target current */
1961 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001962 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001963 }
David Keitel8c5201a2012-02-24 16:08:54 -08001964 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001965 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966}
1967
Amir Samuelovd31ef502011-10-26 14:41:36 +02001968static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1969{
David Keitel88e1b572012-01-11 11:57:14 -08001970 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001971 pr_debug("external charger not registered.\n");
1972 return;
1973 }
1974
1975 if (!chip->ext_charging) {
1976 pr_debug("already not charging.\n");
1977 return;
1978 }
1979
David Keitel88e1b572012-01-11 11:57:14 -08001980 power_supply_set_charge_type(chip->ext_psy,
1981 POWER_SUPPLY_CHARGE_TYPE_NONE);
1982 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001983 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001984 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001985 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001986 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03001987 /* Update battery charging LEDs and user space battery info */
1988 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001989}
1990
1991static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1992{
1993 int dc_present;
1994 int batt_present;
1995 int batt_temp_ok;
1996 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001997 unsigned long delay =
1998 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1999
David Keitel88e1b572012-01-11 11:57:14 -08002000 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002001 pr_debug("external charger not registered.\n");
2002 return;
2003 }
2004
2005 if (chip->ext_charging) {
2006 pr_debug("already charging.\n");
2007 return;
2008 }
2009
David Keitel88e1b572012-01-11 11:57:14 -08002010 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002011 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2012 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002013
2014 if (!dc_present) {
2015 pr_warn("%s. dc not present.\n", __func__);
2016 return;
2017 }
2018 if (!batt_present) {
2019 pr_warn("%s. battery not present.\n", __func__);
2020 return;
2021 }
2022 if (!batt_temp_ok) {
2023 pr_warn("%s. battery temperature not ok.\n", __func__);
2024 return;
2025 }
David Keitel88e1b572012-01-11 11:57:14 -08002026 pm8921_disable_source_current(true); /* Force BATFET=ON */
2027 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002028 if (vbat_ov) {
2029 pr_warn("%s. battery over voltage.\n", __func__);
2030 return;
2031 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02002032
David Keitel6ccbf132012-05-30 14:21:24 -07002033 schedule_delayed_work(&chip->unplug_check_work,
2034 round_jiffies_relative(msecs_to_jiffies
2035 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2036 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2037
David Keitel63f71662012-02-08 20:30:00 -08002038 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002039 power_supply_set_charge_type(chip->ext_psy,
2040 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08002041 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002042 chip->ext_charging = true;
2043 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002044 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002045 /* Start BMS */
2046 schedule_delayed_work(&chip->eoc_work, delay);
2047 wake_lock(&chip->eoc_wake_lock);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002048 /* Update battery charging LEDs and user space battery info */
2049 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002050}
2051
David Keitel6ccbf132012-05-30 14:21:24 -07002052static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002053{
2054 u8 temp;
2055 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002056
David Keitel6ccbf132012-05-30 14:21:24 -07002057 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002058 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002059 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002060 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002061 }
David Keitel6ccbf132012-05-30 14:21:24 -07002062 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002063 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002064 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002065 return;
2066 }
2067 /* set ovp fet disable bit and the write bit */
2068 temp |= 0x81;
David Keitel6ccbf132012-05-30 14:21:24 -07002069 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002070 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002071 pr_err("Failed to write 0x%x OVP_TEST rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002072 return;
2073 }
2074}
2075
David Keitel6ccbf132012-05-30 14:21:24 -07002076static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002077{
2078 u8 temp;
2079 int rc;
2080
David Keitel6ccbf132012-05-30 14:21:24 -07002081 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002082 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002083 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002084 return;
2085 }
David Keitel6ccbf132012-05-30 14:21:24 -07002086 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002087 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002088 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002089 return;
2090 }
2091 /* unset ovp fet disable bit and set the write bit */
2092 temp &= 0xFE;
2093 temp |= 0x80;
David Keitel6ccbf132012-05-30 14:21:24 -07002094 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002095 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002096 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002097 temp, rc);
2098 return;
2099 }
2100}
2101
2102static int param_open_ovp_counter = 10;
2103module_param(param_open_ovp_counter, int, 0644);
2104
David Keitel6ccbf132012-05-30 14:21:24 -07002105#define USB_ACTIVE_BIT BIT(5)
2106#define DC_ACTIVE_BIT BIT(6)
2107static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2108 u8 active_chg_mask)
2109{
2110 if (active_chg_mask & USB_ACTIVE_BIT)
2111 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2112 else if (active_chg_mask & DC_ACTIVE_BIT)
2113 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2114 else
2115 return 0;
2116}
2117
David Keitel8c5201a2012-02-24 16:08:54 -08002118#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002119#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002120static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002121{
David Keitel6ccbf132012-05-30 14:21:24 -07002122 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002123 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002124 u8 active_mask = 0;
2125 u16 ovpreg, ovptestreg;
2126
2127 if (is_usb_chg_plugged_in(chip) &&
2128 (chip->active_path & USB_ACTIVE_BIT)) {
2129 ovpreg = USB_OVP_CONTROL;
2130 ovptestreg = USB_OVP_TEST;
2131 active_mask = USB_ACTIVE_BIT;
2132 } else if (is_dc_chg_plugged_in(chip) &&
2133 (chip->active_path & DC_ACTIVE_BIT)) {
2134 ovpreg = DC_OVP_CONTROL;
2135 ovptestreg = DC_OVP_TEST;
2136 active_mask = DC_ACTIVE_BIT;
2137 } else {
2138 return;
2139 }
David Keitel8c5201a2012-02-24 16:08:54 -08002140
2141 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002142 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002143 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002144 active_chg_plugged_in
2145 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002146 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002147 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2148 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002149
2150 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002151 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002152 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002153 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002154
2155 msleep(20);
2156
David Keitel6ccbf132012-05-30 14:21:24 -07002157 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002158 } else {
David Keitel712782e2012-03-29 14:11:47 -07002159 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002160 }
2161 }
David Keitel6ccbf132012-05-30 14:21:24 -07002162 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2163 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2164 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002165 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002166}
David Keitelacf57c82012-03-07 18:48:50 -08002167
2168static int find_usb_ma_value(int value)
2169{
2170 int i;
2171
2172 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2173 if (value >= usb_ma_table[i].usb_ma)
2174 break;
2175 }
2176
2177 return i;
2178}
2179
2180static void decrease_usb_ma_value(int *value)
2181{
2182 int i;
2183
2184 if (value) {
2185 i = find_usb_ma_value(*value);
2186 if (i > 0)
2187 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002188 while (!the_chip->iusb_fine_res && i > 0
2189 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2190 i--;
David Keitelacf57c82012-03-07 18:48:50 -08002191 *value = usb_ma_table[i].usb_ma;
2192 }
2193}
2194
2195static void increase_usb_ma_value(int *value)
2196{
2197 int i;
2198
2199 if (value) {
2200 i = find_usb_ma_value(*value);
2201
2202 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2203 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002204 /* Get next correct entry if IUSB_FINE_RES is not available */
2205 while (!the_chip->iusb_fine_res
2206 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2207 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2208 i++;
2209
David Keitelacf57c82012-03-07 18:48:50 -08002210 *value = usb_ma_table[i].usb_ma;
2211 }
2212}
2213
2214static void vin_collapse_check_worker(struct work_struct *work)
2215{
2216 struct delayed_work *dwork = to_delayed_work(work);
2217 struct pm8921_chg_chip *chip = container_of(dwork,
2218 struct pm8921_chg_chip, vin_collapse_check_work);
2219
2220 /* AICL only for wall-chargers */
2221 if (is_usb_chg_plugged_in(chip) &&
2222 usb_target_ma > USB_WALL_THRESHOLD_MA) {
2223 /* decrease usb_target_ma */
2224 decrease_usb_ma_value(&usb_target_ma);
2225 /* reset here, increase in unplug_check_worker */
2226 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2227 pr_debug("usb_now=%d, usb_target = %d\n",
2228 USB_WALL_THRESHOLD_MA, usb_target_ma);
2229 } else {
2230 handle_usb_insertion_removal(chip);
2231 }
2232}
2233
2234#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2236{
David Keitelacf57c82012-03-07 18:48:50 -08002237 if (usb_target_ma)
2238 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2239 round_jiffies_relative(msecs_to_jiffies
2240 (VIN_MIN_COLLAPSE_CHECK_MS)));
2241 else
2242 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 return IRQ_HANDLED;
2244}
2245
2246static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
2247{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002248 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 return IRQ_HANDLED;
2250}
2251
2252static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2253{
2254 struct pm8921_chg_chip *chip = data;
2255 int status;
2256
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002257 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2258 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002259 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260 pr_debug("battery present=%d", status);
2261 power_supply_changed(&chip->batt_psy);
2262 return IRQ_HANDLED;
2263}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002264
2265/*
2266 * this interrupt used to restart charging a battery.
2267 *
2268 * Note: When DC-inserted the VBAT can't go low.
2269 * VPH_PWR is provided by the ext-charger.
2270 * After End-Of-Charging from DC, charging can be resumed only
2271 * if DC is removed and then inserted after the battery was in use.
2272 * Therefore the handle_start_ext_chg() is not called.
2273 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2275{
2276 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002277 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002279 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002280
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002281 if (high_transition) {
2282 /* enable auto charging */
2283 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002284 pr_info("batt fell below resume voltage %s\n",
2285 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002286 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 power_supply_changed(&chip->batt_psy);
2290 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002291 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 return IRQ_HANDLED;
2294}
2295
2296static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2297{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002298 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 return IRQ_HANDLED;
2300}
2301
2302static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2303{
2304 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2305 return IRQ_HANDLED;
2306}
2307
2308static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2309{
2310 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2311 return IRQ_HANDLED;
2312}
2313
2314static irqreturn_t vcp_irq_handler(int irq, void *data)
2315{
David Keitel8c5201a2012-02-24 16:08:54 -08002316 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 return IRQ_HANDLED;
2318}
2319
2320static irqreturn_t atcdone_irq_handler(int irq, void *data)
2321{
2322 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2323 return IRQ_HANDLED;
2324}
2325
2326static irqreturn_t atcfail_irq_handler(int irq, void *data)
2327{
2328 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2329 return IRQ_HANDLED;
2330}
2331
2332static irqreturn_t chgdone_irq_handler(int irq, void *data)
2333{
2334 struct pm8921_chg_chip *chip = data;
2335
2336 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002337
2338 handle_stop_ext_chg(chip);
2339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 power_supply_changed(&chip->batt_psy);
2341 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002342 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002343
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002344 bms_notify_check(chip);
2345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 return IRQ_HANDLED;
2347}
2348
2349static irqreturn_t chgfail_irq_handler(int irq, void *data)
2350{
2351 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002352 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353
David Keitel753ec8d2011-11-02 10:56:37 -07002354 ret = pm_chg_failed_clear(chip, 1);
2355 if (ret)
2356 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2357
2358 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2359 get_prop_batt_present(chip),
2360 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2361 pm_chg_get_fsm_state(data));
2362
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 power_supply_changed(&chip->batt_psy);
2364 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002365 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 return IRQ_HANDLED;
2367}
2368
2369static irqreturn_t chgstate_irq_handler(int irq, void *data)
2370{
2371 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372
2373 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2374 power_supply_changed(&chip->batt_psy);
2375 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002376 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002377
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002378 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002379
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380 return IRQ_HANDLED;
2381}
2382
David Keitel8c5201a2012-02-24 16:08:54 -08002383static int param_vin_disable_counter = 5;
2384module_param(param_vin_disable_counter, int, 0644);
2385
2386static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2387 int count, int usb_ma)
2388{
David Keitel6ccbf132012-05-30 14:21:24 -07002389 if (usb_ma)
2390 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002391 pr_debug("count = %d iusb=500mA\n", count);
2392 disable_input_voltage_regulation(chip);
2393 pr_debug("count = %d disable_input_regulation\n", count);
2394
2395 msleep(20);
2396
2397 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2398 count,
2399 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2400 is_usb_chg_plugged_in(chip));
2401 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2402 count, usb_ma);
2403 enable_input_voltage_regulation(chip);
David Keitel6ccbf132012-05-30 14:21:24 -07002404 if (usb_ma)
2405 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002406}
2407
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002408#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002409#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2410#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002411static void unplug_check_worker(struct work_struct *work)
2412{
2413 struct delayed_work *dwork = to_delayed_work(work);
2414 struct pm8921_chg_chip *chip = container_of(dwork,
2415 struct pm8921_chg_chip, unplug_check_work);
David Keitel6ccbf132012-05-30 14:21:24 -07002416 u8 reg_loop, active_path;
2417 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002418 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002419
David Keitelacf57c82012-03-07 18:48:50 -08002420 reg_loop = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002421
2422 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2423 if (rc) {
2424 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2425 return;
2426 }
2427 chip->active_path = active_path;
2428
2429 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
2430 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2431 active_path, active_chg_plugged_in);
2432 if (active_path & USB_ACTIVE_BIT) {
2433 pr_debug("USB charger active\n");
2434
2435 pm_chg_iusbmax_get(chip, &usb_ma);
2436 if (usb_ma == 500 && !usb_target_ma) {
2437 pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
2438 disable_input_voltage_regulation(chip);
2439 return;
2440 }
2441
2442 if (usb_ma <= 100) {
2443 pr_debug(
2444 "Unenumerated or suspended usb_ma = %d skip\n",
2445 usb_ma);
2446 goto check_again_later;
2447 }
2448 } else if (active_path & DC_ACTIVE_BIT) {
2449 pr_debug("DC charger active\n");
2450 } else {
2451 /* No charger active */
2452 if (!(is_usb_chg_plugged_in(chip)
2453 && !(is_dc_chg_plugged_in(chip)))) {
2454 pr_debug(
2455 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2456 pm_chg_get_regulation_loop(chip),
2457 pm_chg_get_fsm_state(chip),
2458 get_prop_batt_current(chip)
2459 );
2460 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002461 return;
2462 }
David Keitel8c5201a2012-02-24 16:08:54 -08002463
David Keitel6ccbf132012-05-30 14:21:24 -07002464 if (active_path & USB_ACTIVE_BIT) {
2465 reg_loop = pm_chg_get_regulation_loop(chip);
2466 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2467 if ((reg_loop & VIN_ACTIVE_BIT) &&
2468 (usb_ma > USB_WALL_THRESHOLD_MA)) {
2469 decrease_usb_ma_value(&usb_ma);
2470 usb_target_ma = usb_ma;
2471 /* end AICL here */
2472 __pm8921_charger_vbus_draw(usb_ma);
2473 pr_debug("usb_now=%d, usb_target = %d\n",
2474 usb_ma, usb_target_ma);
2475 }
David Keitelacf57c82012-03-07 18:48:50 -08002476 }
2477
2478 reg_loop = pm_chg_get_regulation_loop(chip);
2479 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2480
David Keitel6ccbf132012-05-30 14:21:24 -07002481 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002482 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002483
2484 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2485 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2486 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002487 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002488
David Keitel8c5201a2012-02-24 16:08:54 -08002489 while (count++ < param_vin_disable_counter
David Keitel6ccbf132012-05-30 14:21:24 -07002490 && active_chg_plugged_in == 1) {
2491 if (active_path & USB_ACTIVE_BIT)
2492 attempt_reverse_boost_fix(chip,
2493 count, usb_ma);
2494 else
2495 attempt_reverse_boost_fix(chip,
2496 count, 0);
2497 /* after reverse boost fix check if the active
2498 * charger was detected as removed */
2499 active_chg_plugged_in
2500 = is_active_chg_plugged_in(chip,
2501 active_path);
2502 pr_debug("active_chg_plugged_in = %d\n",
2503 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002504 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002505 }
2506 }
2507
David Keitel6ccbf132012-05-30 14:21:24 -07002508 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
2509 pr_debug("active_path = 0x%x, active_chg = %d\n",
2510 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002511 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2512
David Keitel6ccbf132012-05-30 14:21:24 -07002513 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2514 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2515 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002516 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002517 }
2518
David Keitel6ccbf132012-05-30 14:21:24 -07002519 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)) {
David Keitelacf57c82012-03-07 18:48:50 -08002520 /* only increase iusb_max if vin loop not active */
2521 if (usb_ma < usb_target_ma) {
2522 increase_usb_ma_value(&usb_ma);
2523 __pm8921_charger_vbus_draw(usb_ma);
2524 pr_debug("usb_now=%d, usb_target = %d\n",
2525 usb_ma, usb_target_ma);
2526 } else {
2527 usb_target_ma = usb_ma;
2528 }
2529 }
David Keitel8c5201a2012-02-24 16:08:54 -08002530check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002531 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002532 schedule_delayed_work(&chip->unplug_check_work,
2533 round_jiffies_relative(msecs_to_jiffies
2534 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2535}
2536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537static irqreturn_t loop_change_irq_handler(int irq, void *data)
2538{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002539 struct pm8921_chg_chip *chip = data;
2540
2541 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2542 pm_chg_get_fsm_state(data),
2543 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002544 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 return IRQ_HANDLED;
2546}
2547
2548static irqreturn_t fastchg_irq_handler(int irq, void *data)
2549{
2550 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002551 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002553 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2554 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2555 wake_lock(&chip->eoc_wake_lock);
2556 schedule_delayed_work(&chip->eoc_work,
2557 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002558 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002559 }
2560 power_supply_changed(&chip->batt_psy);
2561 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 return IRQ_HANDLED;
2563}
2564
2565static irqreturn_t trklchg_irq_handler(int irq, void *data)
2566{
2567 struct pm8921_chg_chip *chip = data;
2568
2569 power_supply_changed(&chip->batt_psy);
2570 return IRQ_HANDLED;
2571}
2572
2573static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2574{
2575 struct pm8921_chg_chip *chip = data;
2576 int status;
2577
2578 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2579 pr_debug("battery present=%d state=%d", !status,
2580 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002581 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582 power_supply_changed(&chip->batt_psy);
2583 return IRQ_HANDLED;
2584}
2585
2586static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2587{
2588 struct pm8921_chg_chip *chip = data;
2589
Amir Samuelovd31ef502011-10-26 14:41:36 +02002590 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591 power_supply_changed(&chip->batt_psy);
2592 return IRQ_HANDLED;
2593}
2594
2595static irqreturn_t chghot_irq_handler(int irq, void *data)
2596{
2597 struct pm8921_chg_chip *chip = data;
2598
2599 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2600 power_supply_changed(&chip->batt_psy);
2601 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002602 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 return IRQ_HANDLED;
2604}
2605
2606static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2607{
2608 struct pm8921_chg_chip *chip = data;
2609
2610 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002611 handle_stop_ext_chg(chip);
2612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002613 power_supply_changed(&chip->batt_psy);
2614 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 return IRQ_HANDLED;
2616}
2617
2618static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2619{
2620 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002621 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002622
2623 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2624 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2625
2626 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002627 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 power_supply_changed(&chip->batt_psy);
2630 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002631 return IRQ_HANDLED;
2632}
David Keitel52fda532011-11-10 10:43:44 -08002633/*
2634 *
2635 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2636 * fire for two cases:
2637 *
2638 * If the interrupt line switches to high temperature is okay
2639 * and thus charging begins.
2640 * If bat_temp_ok is low this means the temperature is now
2641 * too hot or cold, so charging is stopped.
2642 *
2643 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2645{
David Keitel52fda532011-11-10 10:43:44 -08002646 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002647 struct pm8921_chg_chip *chip = data;
2648
David Keitel52fda532011-11-10 10:43:44 -08002649 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2650
2651 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2652 bat_temp_ok, pm_chg_get_fsm_state(data));
2653
2654 if (bat_temp_ok)
2655 handle_start_ext_chg(chip);
2656 else
2657 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659 power_supply_changed(&chip->batt_psy);
2660 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002661 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 return IRQ_HANDLED;
2663}
2664
2665static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2666{
2667 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2668 return IRQ_HANDLED;
2669}
2670
2671static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2672{
2673 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2674 return IRQ_HANDLED;
2675}
2676
2677static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2678{
2679 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2680 return IRQ_HANDLED;
2681}
2682
2683static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2684{
2685 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2686 return IRQ_HANDLED;
2687}
2688
2689static irqreturn_t batfet_irq_handler(int irq, void *data)
2690{
2691 struct pm8921_chg_chip *chip = data;
2692
2693 pr_debug("vreg ov\n");
2694 power_supply_changed(&chip->batt_psy);
2695 return IRQ_HANDLED;
2696}
2697
2698static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2699{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002700 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002701 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002702
David Keitel88e1b572012-01-11 11:57:14 -08002703 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2704 if (chip->ext_psy)
2705 power_supply_set_online(chip->ext_psy, dc_present);
2706 chip->dc_present = dc_present;
2707 if (dc_present)
2708 handle_start_ext_chg(chip);
2709 else
2710 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711 return IRQ_HANDLED;
2712}
2713
2714static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2715{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002716 struct pm8921_chg_chip *chip = data;
2717
Amir Samuelovd31ef502011-10-26 14:41:36 +02002718 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719 return IRQ_HANDLED;
2720}
2721
2722static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2723{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002724 struct pm8921_chg_chip *chip = data;
2725
Amir Samuelovd31ef502011-10-26 14:41:36 +02002726 handle_stop_ext_chg(chip);
2727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728 return IRQ_HANDLED;
2729}
2730
David Keitel88e1b572012-01-11 11:57:14 -08002731static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2732{
2733 struct power_supply *psy = &the_chip->batt_psy;
2734 struct power_supply *epsy = dev_get_drvdata(dev);
2735 int i, dcin_irq;
2736
2737 /* Only search for external supply if none is registered */
2738 if (!the_chip->ext_psy) {
2739 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2740 for (i = 0; i < epsy->num_supplicants; i++) {
2741 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2742 if (!strncmp(epsy->name, "dc", 2)) {
2743 the_chip->ext_psy = epsy;
2744 dcin_valid_irq_handler(dcin_irq,
2745 the_chip);
2746 }
2747 }
2748 }
2749 }
2750 return 0;
2751}
2752
2753static void pm_batt_external_power_changed(struct power_supply *psy)
2754{
2755 /* Only look for an external supply if it hasn't been registered */
2756 if (!the_chip->ext_psy)
2757 class_for_each_device(power_supply_class, NULL, psy,
2758 __pm_batt_external_power_changed_work);
2759}
2760
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002761/**
2762 * update_heartbeat - internal function to update userspace
2763 * per update_time minutes
2764 *
2765 */
2766static void update_heartbeat(struct work_struct *work)
2767{
2768 struct delayed_work *dwork = to_delayed_work(work);
2769 struct pm8921_chg_chip *chip = container_of(dwork,
2770 struct pm8921_chg_chip, update_heartbeat_work);
2771
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002772 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002773 power_supply_changed(&chip->batt_psy);
2774 schedule_delayed_work(&chip->update_heartbeat_work,
2775 round_jiffies_relative(msecs_to_jiffies
2776 (chip->update_time)));
2777}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002778#define VDD_LOOP_ACTIVE_BIT BIT(3)
2779#define VDD_MAX_INCREASE_MV 400
2780static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2781module_param(vdd_max_increase_mv, int, 0644);
2782
2783static int ichg_threshold_ua = -400000;
2784module_param(ichg_threshold_ua, int, 0644);
2785static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2786{
2787 int ichg_meas_ua, vbat_uv;
2788 int ichg_meas_ma;
2789 int adj_vdd_max_mv, programmed_vdd_max;
2790 int vbat_batt_terminal_uv;
2791 int vbat_batt_terminal_mv;
2792 int reg_loop;
2793 int delta_mv = 0;
2794
2795 if (chip->rconn_mohm == 0) {
2796 pr_debug("Exiting as rconn_mohm is 0\n");
2797 return;
2798 }
2799 /* adjust vdd_max only in normal temperature zone */
2800 if (chip->is_bat_cool || chip->is_bat_warm) {
2801 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2802 chip->is_bat_cool, chip->is_bat_warm);
2803 return;
2804 }
2805
2806 reg_loop = pm_chg_get_regulation_loop(chip);
2807 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2808 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2809 reg_loop);
2810 return;
2811 }
2812
2813 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2814 &vbat_uv);
2815 if (ichg_meas_ua >= 0) {
2816 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2817 return;
2818 }
2819 if (ichg_meas_ua <= ichg_threshold_ua) {
2820 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2821 ichg_meas_ua, ichg_threshold_ua);
2822 return;
2823 }
2824 ichg_meas_ma = ichg_meas_ua / 1000;
2825
2826 /* rconn_mohm is in milliOhms */
2827 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2828 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2829 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2830
2831 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2832
2833 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2834 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2835 delta_mv,
2836 programmed_vdd_max,
2837 adj_vdd_max_mv);
2838
2839 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2840 pr_debug("adj vdd_max lower than default max voltage\n");
2841 return;
2842 }
2843
2844 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2845 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2846
2847 pr_debug("adjusting vdd_max_mv to %d to make "
2848 "vbat_batt_termial_uv = %d to %d\n",
2849 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2850 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2851}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002852
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002853enum {
2854 CHG_IN_PROGRESS,
2855 CHG_NOT_IN_PROGRESS,
2856 CHG_FINISHED,
2857};
2858
2859#define VBAT_TOLERANCE_MV 70
2860#define CHG_DISABLE_MSLEEP 100
2861static int is_charging_finished(struct pm8921_chg_chip *chip)
2862{
2863 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2864 int ichg_meas_ma, iterm_programmed;
2865 int regulation_loop, fast_chg, vcp;
2866 int rc;
2867 static int last_vbat_programmed = -EINVAL;
2868
2869 if (!is_ext_charging(chip)) {
2870 /* return if the battery is not being fastcharged */
2871 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2872 pr_debug("fast_chg = %d\n", fast_chg);
2873 if (fast_chg == 0)
2874 return CHG_NOT_IN_PROGRESS;
2875
2876 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2877 pr_debug("vcp = %d\n", vcp);
2878 if (vcp == 1)
2879 return CHG_IN_PROGRESS;
2880
2881 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2882 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2883 if (vbatdet_low == 1)
2884 return CHG_IN_PROGRESS;
2885
2886 /* reset count if battery is hot/cold */
2887 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2888 pr_debug("batt_temp_ok = %d\n", rc);
2889 if (rc == 0)
2890 return CHG_IN_PROGRESS;
2891
2892 /* reset count if battery voltage is less than vddmax */
2893 vbat_meas_uv = get_prop_battery_uvolts(chip);
2894 if (vbat_meas_uv < 0)
2895 return CHG_IN_PROGRESS;
2896 vbat_meas_mv = vbat_meas_uv / 1000;
2897
2898 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2899 if (rc) {
2900 pr_err("couldnt read vddmax rc = %d\n", rc);
2901 return CHG_IN_PROGRESS;
2902 }
2903 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2904 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002905
2906 if (last_vbat_programmed == -EINVAL)
2907 last_vbat_programmed = vbat_programmed;
2908 if (last_vbat_programmed != vbat_programmed) {
2909 /* vddmax changed, reset and check again */
2910 pr_debug("vddmax = %d last_vdd_max=%d\n",
2911 vbat_programmed, last_vbat_programmed);
2912 last_vbat_programmed = vbat_programmed;
2913 return CHG_IN_PROGRESS;
2914 }
2915
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002916 regulation_loop = pm_chg_get_regulation_loop(chip);
2917 if (regulation_loop < 0) {
2918 pr_err("couldnt read the regulation loop err=%d\n",
2919 regulation_loop);
2920 return CHG_IN_PROGRESS;
2921 }
2922 pr_debug("regulation_loop=%d\n", regulation_loop);
2923
2924 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2925 return CHG_IN_PROGRESS;
2926 } /* !is_ext_charging */
2927
2928 /* reset count if battery chg current is more than iterm */
2929 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2930 if (rc) {
2931 pr_err("couldnt read iterm rc = %d\n", rc);
2932 return CHG_IN_PROGRESS;
2933 }
2934
2935 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2936 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2937 iterm_programmed, ichg_meas_ma);
2938 /*
2939 * ichg_meas_ma < 0 means battery is drawing current
2940 * ichg_meas_ma > 0 means battery is providing current
2941 */
2942 if (ichg_meas_ma > 0)
2943 return CHG_IN_PROGRESS;
2944
2945 if (ichg_meas_ma * -1 > iterm_programmed)
2946 return CHG_IN_PROGRESS;
2947
2948 return CHG_FINISHED;
2949}
2950
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002951/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002952 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002953 * has happened
2954 *
2955 * If all conditions favouring, if the charge current is
2956 * less than the term current for three consecutive times
2957 * an EOC has happened.
2958 * The wakelock is released if there is no need to reshedule
2959 * - this happens when the battery is removed or EOC has
2960 * happened
2961 */
2962#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002963static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002964{
2965 struct delayed_work *dwork = to_delayed_work(work);
2966 struct pm8921_chg_chip *chip = container_of(dwork,
2967 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002968 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002969 int end;
2970
2971 pm_chg_failed_clear(chip, 1);
2972 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002973
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002974 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002975 count = 0;
2976 wake_unlock(&chip->eoc_wake_lock);
2977 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002978 }
2979
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002980 if (end == CHG_FINISHED) {
2981 count++;
2982 } else {
2983 count = 0;
2984 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002985
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002986 if (count == CONSECUTIVE_COUNT) {
2987 count = 0;
2988 pr_info("End of Charging\n");
2989
2990 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002991
Amir Samuelovd31ef502011-10-26 14:41:36 +02002992 if (is_ext_charging(chip))
2993 chip->ext_charge_done = true;
2994
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002995 if (chip->is_bat_warm || chip->is_bat_cool)
2996 chip->bms_notify.is_battery_full = 0;
2997 else
2998 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002999 /* declare end of charging by invoking chgdone interrupt */
3000 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
3001 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003002 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003003 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003004 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003005 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003006 round_jiffies_relative(msecs_to_jiffies
3007 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003008 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003009}
3010
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003011static void btm_configure_work(struct work_struct *work)
3012{
3013 int rc;
3014
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003015 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003016 if (rc)
3017 pr_err("failed to configure btm rc=%d", rc);
3018}
3019
3020DECLARE_WORK(btm_config_work, btm_configure_work);
3021
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003022static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3023{
3024 unsigned int chg_current = chip->max_bat_chg_current;
3025
3026 if (chip->is_bat_cool)
3027 chg_current = min(chg_current, chip->cool_bat_chg_current);
3028
3029 if (chip->is_bat_warm)
3030 chg_current = min(chg_current, chip->warm_bat_chg_current);
3031
David Keitelfdef3a42011-12-14 19:02:54 -08003032 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003033 chg_current = min(chg_current,
3034 chip->thermal_mitigation[thermal_mitigation]);
3035
3036 pm_chg_ibatmax_set(the_chip, chg_current);
3037}
3038
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003039#define TEMP_HYSTERISIS_DEGC 2
3040static void battery_cool(bool enter)
3041{
3042 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003043 if (enter == the_chip->is_bat_cool)
3044 return;
3045 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003046 if (enter) {
3047 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003048 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003049 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003050 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003051 pm_chg_vbatdet_set(the_chip,
3052 the_chip->cool_bat_voltage
3053 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003054 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003055 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003056 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003057 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003058 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003059 the_chip->max_voltage_mv
3060 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003061 }
3062 schedule_work(&btm_config_work);
3063}
3064
3065static void battery_warm(bool enter)
3066{
3067 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003068 if (enter == the_chip->is_bat_warm)
3069 return;
3070 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003071 if (enter) {
3072 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003073 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003074 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003075 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003076 pm_chg_vbatdet_set(the_chip,
3077 the_chip->warm_bat_voltage
3078 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003079 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003080 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003081 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003082 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003083 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003084 the_chip->max_voltage_mv
3085 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003086 }
3087 schedule_work(&btm_config_work);
3088}
3089
3090static int configure_btm(struct pm8921_chg_chip *chip)
3091{
3092 int rc;
3093
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003094 if (chip->warm_temp_dc != INT_MIN)
3095 btm_config.btm_warm_fn = battery_warm;
3096 else
3097 btm_config.btm_warm_fn = NULL;
3098
3099 if (chip->cool_temp_dc != INT_MIN)
3100 btm_config.btm_cool_fn = battery_cool;
3101 else
3102 btm_config.btm_cool_fn = NULL;
3103
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003104 btm_config.low_thr_temp = chip->cool_temp_dc;
3105 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003106 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003107 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003108 if (rc)
3109 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003110 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003111 if (rc)
3112 pr_err("failed to start btm rc = %d\n", rc);
3113
3114 return rc;
3115}
3116
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003117/**
3118 * set_disable_status_param -
3119 *
3120 * Internal function to disable battery charging and also disable drawing
3121 * any current from the source. The device is forced to run on a battery
3122 * after this.
3123 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124static int set_disable_status_param(const char *val, struct kernel_param *kp)
3125{
3126 int ret;
3127 struct pm8921_chg_chip *chip = the_chip;
3128
3129 ret = param_set_int(val, kp);
3130 if (ret) {
3131 pr_err("error setting value %d\n", ret);
3132 return ret;
3133 }
3134 pr_info("factory set disable param to %d\n", charging_disabled);
3135 if (chip) {
3136 pm_chg_auto_enable(chip, !charging_disabled);
3137 pm_chg_charge_dis(chip, charging_disabled);
3138 }
3139 return 0;
3140}
3141module_param_call(disabled, set_disable_status_param, param_get_uint,
3142 &charging_disabled, 0644);
3143
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003144static int rconn_mohm;
3145static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3146{
3147 int ret;
3148 struct pm8921_chg_chip *chip = the_chip;
3149
3150 ret = param_set_int(val, kp);
3151 if (ret) {
3152 pr_err("error setting value %d\n", ret);
3153 return ret;
3154 }
3155 if (chip)
3156 chip->rconn_mohm = rconn_mohm;
3157 return 0;
3158}
3159module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3160 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003161/**
3162 * set_thermal_mitigation_level -
3163 *
3164 * Internal function to control battery charging current to reduce
3165 * temperature
3166 */
3167static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3168{
3169 int ret;
3170 struct pm8921_chg_chip *chip = the_chip;
3171
3172 ret = param_set_int(val, kp);
3173 if (ret) {
3174 pr_err("error setting value %d\n", ret);
3175 return ret;
3176 }
3177
3178 if (!chip) {
3179 pr_err("called before init\n");
3180 return -EINVAL;
3181 }
3182
3183 if (!chip->thermal_mitigation) {
3184 pr_err("no thermal mitigation\n");
3185 return -EINVAL;
3186 }
3187
3188 if (thermal_mitigation < 0
3189 || thermal_mitigation >= chip->thermal_levels) {
3190 pr_err("out of bound level selected\n");
3191 return -EINVAL;
3192 }
3193
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003194 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003195 return ret;
3196}
3197module_param_call(thermal_mitigation, set_therm_mitigation_level,
3198 param_get_uint,
3199 &thermal_mitigation, 0644);
3200
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003201static int set_usb_max_current(const char *val, struct kernel_param *kp)
3202{
3203 int ret, mA;
3204 struct pm8921_chg_chip *chip = the_chip;
3205
3206 ret = param_set_int(val, kp);
3207 if (ret) {
3208 pr_err("error setting value %d\n", ret);
3209 return ret;
3210 }
3211 if (chip) {
3212 pr_warn("setting current max to %d\n", usb_max_current);
3213 pm_chg_iusbmax_get(chip, &mA);
3214 if (mA > usb_max_current)
3215 pm8921_charger_vbus_draw(usb_max_current);
3216 return 0;
3217 }
3218 return -EINVAL;
3219}
David Keitelacf57c82012-03-07 18:48:50 -08003220module_param_call(usb_max_current, set_usb_max_current,
3221 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223static void free_irqs(struct pm8921_chg_chip *chip)
3224{
3225 int i;
3226
3227 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3228 if (chip->pmic_chg_irq[i]) {
3229 free_irq(chip->pmic_chg_irq[i], chip);
3230 chip->pmic_chg_irq[i] = 0;
3231 }
3232}
3233
David Keitel88e1b572012-01-11 11:57:14 -08003234/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3236{
3237 unsigned long flags;
3238 int fsm_state;
3239
3240 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3241 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3242
3243 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003244 if (chip->usb_present) {
3245 schedule_delayed_work(&chip->unplug_check_work,
3246 round_jiffies_relative(msecs_to_jiffies
3247 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08003248 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003249 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250
3251 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3252 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3253 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003254 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
3255 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
3256 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
3257 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3258 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003259 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003260 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3261 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08003262 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263
3264 spin_lock_irqsave(&vbus_lock, flags);
3265 if (usb_chg_current) {
3266 /* reissue a vbus draw call */
3267 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003268 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 }
3270 spin_unlock_irqrestore(&vbus_lock, flags);
3271
3272 fsm_state = pm_chg_get_fsm_state(chip);
3273 if (is_battery_charging(fsm_state)) {
3274 chip->bms_notify.is_charging = 1;
3275 pm8921_bms_charging_began();
3276 }
3277
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003278 check_battery_valid(chip);
3279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3281 chip->usb_present,
3282 chip->dc_present,
3283 get_prop_batt_present(chip),
3284 fsm_state);
3285}
3286
3287struct pm_chg_irq_init_data {
3288 unsigned int irq_id;
3289 char *name;
3290 unsigned long flags;
3291 irqreturn_t (*handler)(int, void *);
3292};
3293
3294#define CHG_IRQ(_id, _flags, _handler) \
3295{ \
3296 .irq_id = _id, \
3297 .name = #_id, \
3298 .flags = _flags, \
3299 .handler = _handler, \
3300}
3301struct pm_chg_irq_init_data chg_irq_data[] = {
3302 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3303 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003304 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3306 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003307 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3308 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3310 usbin_uv_irq_handler),
3311 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3312 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3313 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3314 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3315 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3316 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3317 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3318 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3319 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003320 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3321 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3323 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3324 batt_removed_irq_handler),
3325 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3326 batttemp_hot_irq_handler),
3327 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3328 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3329 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003330 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3331 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003332 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3333 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003334 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3335 coarse_det_low_irq_handler),
3336 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3337 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3338 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3339 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3340 batfet_irq_handler),
3341 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3342 dcin_valid_irq_handler),
3343 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3344 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003345 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003346};
3347
3348static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3349 struct platform_device *pdev)
3350{
3351 struct resource *res;
3352 int ret, i;
3353
3354 ret = 0;
3355 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3356
3357 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3358 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3359 chg_irq_data[i].name);
3360 if (res == NULL) {
3361 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3362 goto err_out;
3363 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003364 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003365 ret = request_irq(res->start, chg_irq_data[i].handler,
3366 chg_irq_data[i].flags,
3367 chg_irq_data[i].name, chip);
3368 if (ret < 0) {
3369 pr_err("couldn't request %d (%s) %d\n", res->start,
3370 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003371 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372 goto err_out;
3373 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3375 }
3376 return 0;
3377
3378err_out:
3379 free_irqs(chip);
3380 return -EINVAL;
3381}
3382
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003383static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3384{
3385 int err;
3386 u8 temp;
3387
3388 temp = 0xD1;
3389 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3390 if (err) {
3391 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3392 return;
3393 }
3394
3395 temp = 0xD3;
3396 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3397 if (err) {
3398 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3399 return;
3400 }
3401
3402 temp = 0xD1;
3403 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3404 if (err) {
3405 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3406 return;
3407 }
3408
3409 temp = 0xD5;
3410 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3411 if (err) {
3412 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3413 return;
3414 }
3415
3416 udelay(183);
3417
3418 temp = 0xD1;
3419 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3420 if (err) {
3421 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3422 return;
3423 }
3424
3425 temp = 0xD0;
3426 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3427 if (err) {
3428 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3429 return;
3430 }
3431 udelay(32);
3432
3433 temp = 0xD1;
3434 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3435 if (err) {
3436 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3437 return;
3438 }
3439
3440 temp = 0xD3;
3441 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3442 if (err) {
3443 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3444 return;
3445 }
3446}
3447
3448static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3449{
3450 int err;
3451 u8 temp;
3452
3453 temp = 0xD1;
3454 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3455 if (err) {
3456 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3457 return;
3458 }
3459
3460 temp = 0xD0;
3461 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3462 if (err) {
3463 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3464 return;
3465 }
3466}
3467
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003468#define VREF_BATT_THERM_FORCE_ON BIT(7)
3469static void detect_battery_removal(struct pm8921_chg_chip *chip)
3470{
3471 u8 temp;
3472
3473 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3474 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3475
3476 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3477 /*
3478 * batt therm force on bit is battery backed and is default 0
3479 * The charger sets this bit at init time. If this bit is found
3480 * 0 that means the battery was removed. Tell the bms about it
3481 */
3482 pm8921_bms_invalidate_shutdown_soc();
3483}
3484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485#define ENUM_TIMER_STOP_BIT BIT(1)
3486#define BOOT_DONE_BIT BIT(6)
David Keitelb157ff72012-06-14 11:22:30 -07003487#define BOOT_TIMER_EN_BIT BIT(1)
3488#define BOOT_DONE_MASK (BOOT_DONE_BIT | BOOT_TIMER_EN_BIT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489#define CHG_BATFET_ON_BIT BIT(3)
3490#define CHG_VCP_EN BIT(0)
3491#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3492#define SAFE_CURRENT_MA 1500
3493static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3494{
3495 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003496 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07003498 /* forcing 19p2mhz before accessing any charger registers */
3499 pm8921_chg_force_19p2mhz_clk(chip);
3500
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003501 detect_battery_removal(chip);
3502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003503 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
David Keitelb157ff72012-06-14 11:22:30 -07003504 BOOT_DONE_MASK, BOOT_DONE_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505 if (rc) {
3506 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3507 return rc;
3508 }
3509
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003510 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3511
3512 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3513 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3514
3515 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517 if (rc) {
3518 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003519 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003520 return rc;
3521 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003522 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003523 chip->max_voltage_mv
3524 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003525 if (rc) {
3526 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003527 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003528 return rc;
3529 }
3530
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003531 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003532 if (rc) {
3533 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003534 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003535 return rc;
3536 }
3537 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3538 if (rc) {
3539 pr_err("Failed to set max voltage to %d rc=%d\n",
3540 SAFE_CURRENT_MA, rc);
3541 return rc;
3542 }
3543
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003544 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545 if (rc) {
3546 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3547 return rc;
3548 }
3549
3550 rc = pm_chg_iterm_set(chip, chip->term_current);
3551 if (rc) {
3552 pr_err("Failed to set term current to %d rc=%d\n",
3553 chip->term_current, rc);
3554 return rc;
3555 }
3556
3557 /* Disable the ENUM TIMER */
3558 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3559 ENUM_TIMER_STOP_BIT);
3560 if (rc) {
3561 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3562 return rc;
3563 }
3564
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003565 if (chip->safety_time != 0) {
3566 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3567 if (rc) {
3568 pr_err("Failed to set max time to %d minutes rc=%d\n",
3569 chip->safety_time, rc);
3570 return rc;
3571 }
3572 }
3573
3574 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003575 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003576 if (rc) {
3577 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3578 chip->safety_time, rc);
3579 return rc;
3580 }
3581 }
3582
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003583 if (chip->vin_min != 0) {
3584 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3585 if (rc) {
3586 pr_err("Failed to set vin min to %d mV rc=%d\n",
3587 chip->vin_min, rc);
3588 return rc;
3589 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003590 } else {
3591 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003592 }
3593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003594 rc = pm_chg_disable_wd(chip);
3595 if (rc) {
3596 pr_err("Failed to disable wd rc=%d\n", rc);
3597 return rc;
3598 }
3599
3600 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3601 CHG_BAT_TEMP_DIS_BIT, 0);
3602 if (rc) {
3603 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3604 return rc;
3605 }
3606 /* switch to a 3.2Mhz for the buck */
3607 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3608 if (rc) {
3609 pr_err("Failed to switch buck clk rc=%d\n", rc);
3610 return rc;
3611 }
3612
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003613 if (chip->trkl_voltage != 0) {
3614 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3615 if (rc) {
3616 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3617 chip->trkl_voltage, rc);
3618 return rc;
3619 }
3620 }
3621
3622 if (chip->weak_voltage != 0) {
3623 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3624 if (rc) {
3625 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3626 chip->weak_voltage, rc);
3627 return rc;
3628 }
3629 }
3630
3631 if (chip->trkl_current != 0) {
3632 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3633 if (rc) {
3634 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3635 chip->trkl_voltage, rc);
3636 return rc;
3637 }
3638 }
3639
3640 if (chip->weak_current != 0) {
3641 rc = pm_chg_iweak_set(chip, chip->weak_current);
3642 if (rc) {
3643 pr_err("Failed to set weak current to %dmA rc=%d\n",
3644 chip->weak_current, rc);
3645 return rc;
3646 }
3647 }
3648
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003649 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3650 if (rc) {
3651 pr_err("Failed to set cold config %d rc=%d\n",
3652 chip->cold_thr, rc);
3653 }
3654
3655 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3656 if (rc) {
3657 pr_err("Failed to set hot config %d rc=%d\n",
3658 chip->hot_thr, rc);
3659 }
3660
Jay Chokshid674a512012-03-15 14:06:04 -07003661 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3662 if (rc) {
3663 pr_err("Failed to set charger LED src config %d rc=%d\n",
3664 chip->led_src_config, rc);
3665 }
3666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003667 /* Workarounds for die 1.1 and 1.0 */
3668 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3669 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3671 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003672
3673 /* software workaround for correct battery_id detection */
3674 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3675 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3676 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3677 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3678 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3679 udelay(100);
3680 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003681 }
3682
David Keitelb51995e2011-11-18 17:03:31 -08003683 /* Workarounds for die 3.0 */
3684 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3685 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3686
David Keitel38bdd4f2012-04-19 15:39:13 -07003687 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel0789fc62012-06-07 17:43:27 -07003688 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
David Keitel38bdd4f2012-04-19 15:39:13 -07003689 chip->iusb_fine_res = true;
David Keitel0789fc62012-06-07 17:43:27 -07003690 if (chip->uvd_voltage_mv)
3691 rc = pm_chg_uvd_threshold_set(chip,
3692 chip->uvd_voltage_mv);
3693 if (rc) {
3694 pr_err("Failed to set UVD threshold %drc=%d\n",
3695 chip->uvd_voltage_mv, rc);
3696 return rc;
3697 }
3698 }
David Keitel38bdd4f2012-04-19 15:39:13 -07003699
David Keitelb51995e2011-11-18 17:03:31 -08003700 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3701
David Keitela3c0d822011-11-03 14:18:52 -07003702 /* Disable EOC FSM processing */
3703 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3704
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003705 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3706 VREF_BATT_THERM_FORCE_ON);
3707 if (rc)
3708 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003710 rc = pm_chg_charge_dis(chip, charging_disabled);
3711 if (rc) {
3712 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3713 return rc;
3714 }
3715
3716 rc = pm_chg_auto_enable(chip, !charging_disabled);
3717 if (rc) {
3718 pr_err("Failed to enable charging rc=%d\n", rc);
3719 return rc;
3720 }
3721
3722 return 0;
3723}
3724
3725static int get_rt_status(void *data, u64 * val)
3726{
3727 int i = (int)data;
3728 int ret;
3729
3730 /* global irq number is passed in via data */
3731 ret = pm_chg_get_rt_status(the_chip, i);
3732 *val = ret;
3733 return 0;
3734}
3735DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3736
3737static int get_fsm_status(void *data, u64 * val)
3738{
3739 u8 temp;
3740
3741 temp = pm_chg_get_fsm_state(the_chip);
3742 *val = temp;
3743 return 0;
3744}
3745DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3746
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003747static int get_reg_loop(void *data, u64 * val)
3748{
3749 u8 temp;
3750
3751 if (!the_chip) {
3752 pr_err("%s called before init\n", __func__);
3753 return -EINVAL;
3754 }
3755 temp = pm_chg_get_regulation_loop(the_chip);
3756 *val = temp;
3757 return 0;
3758}
3759DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003761static int get_reg(void *data, u64 * val)
3762{
3763 int addr = (int)data;
3764 int ret;
3765 u8 temp;
3766
3767 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3768 if (ret) {
3769 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3770 addr, temp, ret);
3771 return -EAGAIN;
3772 }
3773 *val = temp;
3774 return 0;
3775}
3776
3777static int set_reg(void *data, u64 val)
3778{
3779 int addr = (int)data;
3780 int ret;
3781 u8 temp;
3782
3783 temp = (u8) val;
3784 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3785 if (ret) {
3786 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3787 addr, temp, ret);
3788 return -EAGAIN;
3789 }
3790 return 0;
3791}
3792DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3793
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003794enum {
3795 BAT_WARM_ZONE,
3796 BAT_COOL_ZONE,
3797};
3798static int get_warm_cool(void *data, u64 * val)
3799{
3800 if (!the_chip) {
3801 pr_err("%s called before init\n", __func__);
3802 return -EINVAL;
3803 }
3804 if ((int)data == BAT_WARM_ZONE)
3805 *val = the_chip->is_bat_warm;
3806 if ((int)data == BAT_COOL_ZONE)
3807 *val = the_chip->is_bat_cool;
3808 return 0;
3809}
3810DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3813{
3814 int i;
3815
3816 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3817
3818 if (IS_ERR(chip->dent)) {
3819 pr_err("pmic charger couldnt create debugfs dir\n");
3820 return;
3821 }
3822
3823 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3824 (void *)CHG_CNTRL, &reg_fops);
3825 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3826 (void *)CHG_CNTRL_2, &reg_fops);
3827 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3828 (void *)CHG_CNTRL_3, &reg_fops);
3829 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3830 (void *)PBL_ACCESS1, &reg_fops);
3831 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3832 (void *)PBL_ACCESS2, &reg_fops);
3833 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3834 (void *)SYS_CONFIG_1, &reg_fops);
3835 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3836 (void *)SYS_CONFIG_2, &reg_fops);
3837 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3838 (void *)CHG_VDD_MAX, &reg_fops);
3839 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3840 (void *)CHG_VDD_SAFE, &reg_fops);
3841 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3842 (void *)CHG_VBAT_DET, &reg_fops);
3843 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3844 (void *)CHG_IBAT_MAX, &reg_fops);
3845 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3846 (void *)CHG_IBAT_SAFE, &reg_fops);
3847 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3848 (void *)CHG_VIN_MIN, &reg_fops);
3849 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3850 (void *)CHG_VTRICKLE, &reg_fops);
3851 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3852 (void *)CHG_ITRICKLE, &reg_fops);
3853 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3854 (void *)CHG_ITERM, &reg_fops);
3855 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3856 (void *)CHG_TCHG_MAX, &reg_fops);
3857 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3858 (void *)CHG_TWDOG, &reg_fops);
3859 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3860 (void *)CHG_TEMP_THRESH, &reg_fops);
3861 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3862 (void *)CHG_COMP_OVR, &reg_fops);
3863 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3864 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3865 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3866 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3867 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3868 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3869 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3870 (void *)CHG_TEST, &reg_fops);
3871
3872 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3873 &fsm_fops);
3874
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003875 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3876 &reg_loop_fops);
3877
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003878 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3879 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3880 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3881 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3884 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3885 debugfs_create_file(chg_irq_data[i].name, 0444,
3886 chip->dent,
3887 (void *)chg_irq_data[i].irq_id,
3888 &rt_fops);
3889 }
3890}
3891
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003892static int pm8921_charger_suspend_noirq(struct device *dev)
3893{
3894 int rc;
3895 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3896
3897 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3898 if (rc)
3899 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3900 pm8921_chg_set_hw_clk_switching(chip);
3901 return 0;
3902}
3903
3904static int pm8921_charger_resume_noirq(struct device *dev)
3905{
3906 int rc;
3907 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3908
3909 pm8921_chg_force_19p2mhz_clk(chip);
3910
3911 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3912 VREF_BATT_THERM_FORCE_ON);
3913 if (rc)
3914 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3915 return 0;
3916}
3917
David Keitelf2226022011-12-13 15:55:50 -08003918static int pm8921_charger_resume(struct device *dev)
3919{
3920 int rc;
3921 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3922
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003923 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003924 && !(chip->keep_btm_on_suspend)) {
3925 rc = pm8xxx_adc_btm_configure(&btm_config);
3926 if (rc)
3927 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3928
3929 rc = pm8xxx_adc_btm_start();
3930 if (rc)
3931 pr_err("couldn't restart btm rc=%d\n", rc);
3932 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003933 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3934 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3935 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3936 }
David Keitelf2226022011-12-13 15:55:50 -08003937 return 0;
3938}
3939
3940static int pm8921_charger_suspend(struct device *dev)
3941{
3942 int rc;
3943 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3944
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003945 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003946 && !(chip->keep_btm_on_suspend)) {
3947 rc = pm8xxx_adc_btm_end();
3948 if (rc)
3949 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3950 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003951
3952 if (is_usb_chg_plugged_in(chip)) {
3953 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3954 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3955 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003956
David Keitelf2226022011-12-13 15:55:50 -08003957 return 0;
3958}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3960{
3961 int rc = 0;
3962 struct pm8921_chg_chip *chip;
3963 const struct pm8921_charger_platform_data *pdata
3964 = pdev->dev.platform_data;
3965
3966 if (!pdata) {
3967 pr_err("missing platform data\n");
3968 return -EINVAL;
3969 }
3970
3971 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3972 GFP_KERNEL);
3973 if (!chip) {
3974 pr_err("Cannot allocate pm_chg_chip\n");
3975 return -ENOMEM;
3976 }
3977
3978 chip->dev = &pdev->dev;
3979 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003980 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003982 chip->max_voltage_mv = pdata->max_voltage;
3983 chip->min_voltage_mv = pdata->min_voltage;
David Keitel0789fc62012-06-07 17:43:27 -07003984 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003985 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003986 chip->term_current = pdata->term_current;
3987 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003988 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003989 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3990 chip->batt_id_min = pdata->batt_id_min;
3991 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003992 if (pdata->cool_temp != INT_MIN)
3993 chip->cool_temp_dc = pdata->cool_temp * 10;
3994 else
3995 chip->cool_temp_dc = INT_MIN;
3996
3997 if (pdata->warm_temp != INT_MIN)
3998 chip->warm_temp_dc = pdata->warm_temp * 10;
3999 else
4000 chip->warm_temp_dc = INT_MIN;
4001
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004002 chip->temp_check_period = pdata->temp_check_period;
4003 chip->max_bat_chg_current = pdata->max_bat_chg_current;
4004 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4005 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4006 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4007 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08004008 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004009 chip->trkl_voltage = pdata->trkl_voltage;
4010 chip->weak_voltage = pdata->weak_voltage;
4011 chip->trkl_current = pdata->trkl_current;
4012 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004013 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004014 chip->thermal_mitigation = pdata->thermal_mitigation;
4015 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004016
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004017 chip->cold_thr = pdata->cold_thr;
4018 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004019 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004020 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004022 rc = pm8921_chg_hw_init(chip);
4023 if (rc) {
4024 pr_err("couldn't init hardware rc=%d\n", rc);
4025 goto free_chip;
4026 }
4027
4028 chip->usb_psy.name = "usb",
4029 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4030 chip->usb_psy.supplied_to = pm_power_supplied_to,
4031 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004032 chip->usb_psy.properties = pm_power_props_usb,
4033 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4034 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004035 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036
David Keitel6ed71a52012-01-30 12:42:18 -08004037 chip->dc_psy.name = "pm8921-dc",
4038 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4039 chip->dc_psy.supplied_to = pm_power_supplied_to,
4040 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004041 chip->dc_psy.properties = pm_power_props_mains,
4042 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4043 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045 chip->batt_psy.name = "battery",
4046 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4047 chip->batt_psy.properties = msm_batt_power_props,
4048 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4049 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004050 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 rc = power_supply_register(chip->dev, &chip->usb_psy);
4052 if (rc < 0) {
4053 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004054 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055 }
4056
David Keitel6ed71a52012-01-30 12:42:18 -08004057 rc = power_supply_register(chip->dev, &chip->dc_psy);
4058 if (rc < 0) {
4059 pr_err("power_supply_register usb failed rc = %d\n", rc);
4060 goto unregister_usb;
4061 }
4062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 rc = power_supply_register(chip->dev, &chip->batt_psy);
4064 if (rc < 0) {
4065 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004066 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 }
4068
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004069 platform_set_drvdata(pdev, chip);
4070 the_chip = chip;
4071
4072 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004073 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004074 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4075 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004076 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004078 rc = request_irqs(chip, pdev);
4079 if (rc) {
4080 pr_err("couldn't register interrupts rc=%d\n", rc);
4081 goto unregister_batt;
4082 }
4083
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004084 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
4085 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
4086 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004087 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
4088 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004089 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004090 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004091 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004092 * care for jeita compliance
4093 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004094 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004095 rc = configure_btm(chip);
4096 if (rc) {
4097 pr_err("couldn't register with btm rc=%d\n", rc);
4098 goto free_irq;
4099 }
4100 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 create_debugfs_entries(chip);
4103
4104 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004105 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 /* determine what state the charger is in */
4108 determine_initial_state(chip);
4109
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004110 if (chip->update_time) {
4111 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
4112 update_heartbeat);
4113 schedule_delayed_work(&chip->update_heartbeat_work,
4114 round_jiffies_relative(msecs_to_jiffies
4115 (chip->update_time)));
4116 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 return 0;
4118
4119free_irq:
4120 free_irqs(chip);
4121unregister_batt:
4122 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004123unregister_dc:
4124 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125unregister_usb:
4126 power_supply_unregister(&chip->usb_psy);
4127free_chip:
4128 kfree(chip);
4129 return rc;
4130}
4131
4132static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4133{
4134 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4135
4136 free_irqs(chip);
4137 platform_set_drvdata(pdev, NULL);
4138 the_chip = NULL;
4139 kfree(chip);
4140 return 0;
4141}
David Keitelf2226022011-12-13 15:55:50 -08004142static const struct dev_pm_ops pm8921_pm_ops = {
4143 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004144 .suspend_noirq = pm8921_charger_suspend_noirq,
4145 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004146 .resume = pm8921_charger_resume,
4147};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004149 .probe = pm8921_charger_probe,
4150 .remove = __devexit_p(pm8921_charger_remove),
4151 .driver = {
4152 .name = PM8921_CHARGER_DEV_NAME,
4153 .owner = THIS_MODULE,
4154 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004155 },
4156};
4157
4158static int __init pm8921_charger_init(void)
4159{
4160 return platform_driver_register(&pm8921_charger_driver);
4161}
4162
4163static void __exit pm8921_charger_exit(void)
4164{
4165 platform_driver_unregister(&pm8921_charger_driver);
4166}
4167
4168late_initcall(pm8921_charger_init);
4169module_exit(pm8921_charger_exit);
4170
4171MODULE_LICENSE("GPL v2");
4172MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4173MODULE_VERSION("1.0");
4174MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);