blob: 55fec1532c89e5fb02cb84a0e31cf3dad306ef2d [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>
Ajay Dudani11aeb7b2012-06-28 19:14:30 -070030#include <linux/mfd/pm8xxx/batt-alarm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
32#include <mach/msm_xo.h>
33#include <mach/msm_hsusb.h>
34
35#define CHG_BUCK_CLOCK_CTRL 0x14
36
37#define PBL_ACCESS1 0x04
38#define PBL_ACCESS2 0x05
39#define SYS_CONFIG_1 0x06
40#define SYS_CONFIG_2 0x07
41#define CHG_CNTRL 0x204
42#define CHG_IBAT_MAX 0x205
43#define CHG_TEST 0x206
44#define CHG_BUCK_CTRL_TEST1 0x207
45#define CHG_BUCK_CTRL_TEST2 0x208
46#define CHG_BUCK_CTRL_TEST3 0x209
47#define COMPARATOR_OVERRIDE 0x20A
48#define PSI_TXRX_SAMPLE_DATA_0 0x20B
49#define PSI_TXRX_SAMPLE_DATA_1 0x20C
50#define PSI_TXRX_SAMPLE_DATA_2 0x20D
51#define PSI_TXRX_SAMPLE_DATA_3 0x20E
52#define PSI_CONFIG_STATUS 0x20F
53#define CHG_IBAT_SAFE 0x210
54#define CHG_ITRICKLE 0x211
55#define CHG_CNTRL_2 0x212
56#define CHG_VBAT_DET 0x213
57#define CHG_VTRICKLE 0x214
58#define CHG_ITERM 0x215
59#define CHG_CNTRL_3 0x216
60#define CHG_VIN_MIN 0x217
61#define CHG_TWDOG 0x218
62#define CHG_TTRKL_MAX 0x219
63#define CHG_TEMP_THRESH 0x21A
64#define CHG_TCHG_MAX 0x21B
65#define USB_OVP_CONTROL 0x21C
66#define DC_OVP_CONTROL 0x21D
67#define USB_OVP_TEST 0x21E
68#define DC_OVP_TEST 0x21F
69#define CHG_VDD_MAX 0x220
70#define CHG_VDD_SAFE 0x221
71#define CHG_VBAT_BOOT_THRESH 0x222
72#define USB_OVP_TRIM 0x355
73#define BUCK_CONTROL_TRIM1 0x356
74#define BUCK_CONTROL_TRIM2 0x357
75#define BUCK_CONTROL_TRIM3 0x358
76#define BUCK_CONTROL_TRIM4 0x359
77#define CHG_DEFAULTS_TRIM 0x35A
78#define CHG_ITRIM 0x35B
79#define CHG_TTRIM 0x35C
80#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070081#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070082#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070084/* check EOC every 10 seconds */
85#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080086/* check for USB unplug every 200 msecs */
87#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089enum chg_fsm_state {
90 FSM_STATE_OFF_0 = 0,
91 FSM_STATE_BATFETDET_START_12 = 12,
92 FSM_STATE_BATFETDET_END_16 = 16,
93 FSM_STATE_ON_CHG_HIGHI_1 = 1,
94 FSM_STATE_ATC_2A = 2,
95 FSM_STATE_ATC_2B = 18,
96 FSM_STATE_ON_BAT_3 = 3,
97 FSM_STATE_ATC_FAIL_4 = 4 ,
98 FSM_STATE_DELAY_5 = 5,
99 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
100 FSM_STATE_FAST_CHG_7 = 7,
101 FSM_STATE_TRKL_CHG_8 = 8,
102 FSM_STATE_CHG_FAIL_9 = 9,
103 FSM_STATE_EOC_10 = 10,
104 FSM_STATE_ON_CHG_VREGOK_11 = 11,
105 FSM_STATE_ATC_PAUSE_13 = 13,
106 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
107 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
108 FSM_STATE_START_BOOT = 20,
109 FSM_STATE_FLCB_VREGOK = 21,
110 FSM_STATE_FLCB = 22,
111};
112
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700113struct fsm_state_to_batt_status {
114 enum chg_fsm_state fsm_state;
115 int batt_state;
116};
117
Ajay Dudani11aeb7b2012-06-28 19:14:30 -0700118static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
119 unsigned long status, void *unused);
120
121static struct notifier_block alarm_notifier = {
122 .notifier_call = pm8921_battery_gauge_alarm_notify,
123};
124
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700125static struct fsm_state_to_batt_status map[] = {
126 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
127 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
128 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
129 /*
130 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
131 * too hot/cold, charger too hot
132 */
133 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
134 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
135 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
136 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
137 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
138 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
139 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
140 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
141 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
142 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
143 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
144 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
146 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
147 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
149 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
150 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
151};
152
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700153enum chg_regulation_loop {
154 VDD_LOOP = BIT(3),
155 BAT_CURRENT_LOOP = BIT(2),
156 INPUT_CURRENT_LOOP = BIT(1),
157 INPUT_VOLTAGE_LOOP = BIT(0),
158 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
159 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
160};
161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162enum pmic_chg_interrupts {
163 USBIN_VALID_IRQ = 0,
164 USBIN_OV_IRQ,
165 BATT_INSERTED_IRQ,
166 VBATDET_LOW_IRQ,
167 USBIN_UV_IRQ,
168 VBAT_OV_IRQ,
169 CHGWDOG_IRQ,
170 VCP_IRQ,
171 ATCDONE_IRQ,
172 ATCFAIL_IRQ,
173 CHGDONE_IRQ,
174 CHGFAIL_IRQ,
175 CHGSTATE_IRQ,
176 LOOP_CHANGE_IRQ,
177 FASTCHG_IRQ,
178 TRKLCHG_IRQ,
179 BATT_REMOVED_IRQ,
180 BATTTEMP_HOT_IRQ,
181 CHGHOT_IRQ,
182 BATTTEMP_COLD_IRQ,
183 CHG_GONE_IRQ,
184 BAT_TEMP_OK_IRQ,
185 COARSE_DET_LOW_IRQ,
186 VDD_LOOP_IRQ,
187 VREG_OV_IRQ,
188 VBATDET_IRQ,
189 BATFET_IRQ,
190 PSI_IRQ,
191 DCIN_VALID_IRQ,
192 DCIN_OV_IRQ,
193 DCIN_UV_IRQ,
194 PM_CHG_MAX_INTS,
195};
196
197struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700198 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 int is_charging;
200 struct work_struct work;
201};
202
203/**
204 * struct pm8921_chg_chip -device information
205 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 * @usb_present: present status of usb
207 * @dc_present: present status of dc
208 * @usb_charger_current: usb current to charge the battery with used when
209 * the usb path is enabled or charging is resumed
210 * @safety_time: max time for which charging will happen
211 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800212 * @max_voltage_mv: the max volts the batt should be charged up to
213 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700214 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Ajay Dudani11aeb7b2012-06-28 19:14:30 -0700215 * @alarm_voltage_mv: the battery alarm voltage
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800216 * @cool_temp_dc: the cool temp threshold in deciCelcius
217 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700218 * @resume_voltage_delta: the voltage delta from vdd max at which the
219 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 * @term_current: The charging based term current
221 *
222 */
223struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700224 struct device *dev;
225 unsigned int usb_present;
226 unsigned int dc_present;
227 unsigned int usb_charger_current;
228 unsigned int max_bat_chg_current;
229 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
230 unsigned int safety_time;
231 unsigned int ttrkl_time;
232 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800233 unsigned int max_voltage_mv;
234 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700235 unsigned int uvd_voltage_mv;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -0700236 unsigned int alarm_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800237 int cool_temp_dc;
238 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700239 unsigned int temp_check_period;
240 unsigned int cool_bat_chg_current;
241 unsigned int warm_bat_chg_current;
242 unsigned int cool_bat_voltage;
243 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700244 unsigned int is_bat_cool;
245 unsigned int is_bat_warm;
246 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 unsigned int term_current;
248 unsigned int vbat_channel;
249 unsigned int batt_temp_channel;
250 unsigned int batt_id_channel;
251 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800252 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800253 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700254 struct power_supply batt_psy;
255 struct dentry *dent;
256 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800257 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200258 bool ext_charging;
259 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700260 bool iusb_fine_res;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -0700261 bool dc_unplug_check;
262 bool disable_hw_clock_switching;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700264 struct work_struct battery_id_valid_work;
265 int64_t batt_id_min;
266 int64_t batt_id_max;
267 int trkl_voltage;
268 int weak_voltage;
269 int trkl_current;
270 int weak_current;
271 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800272 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700273 int thermal_levels;
274 struct delayed_work update_heartbeat_work;
275 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800276 struct delayed_work unplug_check_work;
Devin Kim69f17302012-09-12 20:30:28 -0700277 struct delayed_work unplug_usbcheck_work;
David Keitelacf57c82012-03-07 18:48:50 -0800278 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700279 struct wake_lock eoc_wake_lock;
280 enum pm8921_chg_cold_thr cold_thr;
281 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800282 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700283 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700284 bool host_mode;
David Keitel6ccbf132012-05-30 14:21:24 -0700285 u8 active_path;
Devin Kim32599592012-08-22 11:40:44 -0700286 int ext_batt_health;
287 int ext_batt_temp_monitor;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700288 int recent_reported_soc;
choongryeol.lee45ccbb52012-08-25 00:15:42 -0700289 unsigned int ext_warm_i_limit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290};
291
David Keitelacf57c82012-03-07 18:48:50 -0800292/* user space parameter to limit usb current */
293static unsigned int usb_max_current;
294/*
295 * usb_target_ma is used for wall charger
296 * adaptive input current limiting only. Use
297 * pm_iusbmax_get() to get current maximum usb current setting.
298 */
299static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700301static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302
303static struct pm8921_chg_chip *the_chip;
304
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700305static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700306
kyungtae.oh1ff608a2012-07-19 14:31:54 +0900307#ifdef CONFIG_WIRELESS_CHARGER
308static int wireless_charging;
309#endif
310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
312 u8 mask, u8 val)
313{
314 int rc;
315 u8 reg;
316
317 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
318 if (rc) {
319 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
320 return rc;
321 }
322 reg &= ~mask;
323 reg |= val & mask;
324 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
325 if (rc) {
326 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
327 return rc;
328 }
329 return 0;
330}
331
David Keitelcf867232012-01-27 18:40:12 -0800332static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
333{
334 return pm8xxx_read_irq_stat(chip->dev->parent,
335 chip->pmic_chg_irq[irq_id]);
336}
337
338/* Treat OverVoltage/UnderVoltage as source missing */
339static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
340{
341 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
342}
343
344/* Treat OverVoltage/UnderVoltage as source missing */
345static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
346{
347 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
348}
349
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700350static int is_batfet_closed(struct pm8921_chg_chip *chip)
351{
352 return pm_chg_get_rt_status(chip, BATFET_IRQ);
353}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354#define CAPTURE_FSM_STATE_CMD 0xC2
355#define READ_BANK_7 0x70
356#define READ_BANK_4 0x40
357static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
358{
359 u8 temp;
360 int err, ret = 0;
361
362 temp = CAPTURE_FSM_STATE_CMD;
363 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
364 if (err) {
365 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
366 return err;
367 }
368
369 temp = READ_BANK_7;
370 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
371 if (err) {
372 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
373 return err;
374 }
375
376 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
377 if (err) {
378 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
379 return err;
380 }
381 /* get the lower 4 bits */
382 ret = temp & 0xF;
383
384 temp = READ_BANK_4;
385 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
386 if (err) {
387 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
388 return err;
389 }
390
391 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
392 if (err) {
393 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
394 return err;
395 }
396 /* get the upper 1 bit */
397 ret |= (temp & 0x1) << 4;
398 return ret;
399}
400
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700401#define READ_BANK_6 0x60
402static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
403{
404 u8 temp;
405 int err;
406
407 temp = READ_BANK_6;
408 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
409 if (err) {
410 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
411 return err;
412 }
413
414 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
415 if (err) {
416 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
417 return err;
418 }
419
420 /* return the lower 4 bits */
421 return temp & CHG_ALL_LOOPS;
422}
423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424#define CHG_USB_SUSPEND_BIT BIT(2)
425static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
426{
427 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
428 enable ? CHG_USB_SUSPEND_BIT : 0);
429}
430
431#define CHG_EN_BIT BIT(7)
432static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
433{
434 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
435 enable ? CHG_EN_BIT : 0);
436}
437
David Keitel753ec8d2011-11-02 10:56:37 -0700438#define CHG_FAILED_CLEAR BIT(0)
439#define ATC_FAILED_CLEAR BIT(1)
440static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
441{
442 int rc;
443
444 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
445 clear ? ATC_FAILED_CLEAR : 0);
446 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
447 clear ? CHG_FAILED_CLEAR : 0);
448 return rc;
449}
450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451#define CHG_CHARGE_DIS_BIT BIT(1)
452static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
453{
454 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
455 disable ? CHG_CHARGE_DIS_BIT : 0);
456}
457
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800458static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
459{
460 u8 temp;
461
462 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
463 return temp & CHG_CHARGE_DIS_BIT;
464}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465#define PM8921_CHG_V_MIN_MV 3240
466#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800467#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468#define PM8921_CHG_VDDMAX_MAX 4500
469#define PM8921_CHG_VDDMAX_MIN 3400
470#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800471static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800473 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800474 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800476 if (voltage < PM8921_CHG_VDDMAX_MIN
477 || voltage > PM8921_CHG_VDDMAX_MAX) {
478 pr_err("bad mV=%d asked to set\n", voltage);
479 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 }
David Keitelcf867232012-01-27 18:40:12 -0800481
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800482 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
483
484 remainder = voltage % 20;
485 if (remainder >= 10) {
486 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
487 }
488
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800490 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491}
492
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700493static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
494{
495 u8 temp;
496 int rc;
497
498 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
499 if (rc) {
500 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700501 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700502 return rc;
503 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800504 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
505 + PM8921_CHG_V_MIN_MV;
506 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
507 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700508 return 0;
509}
510
David Keitelcf867232012-01-27 18:40:12 -0800511static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
512{
513 int current_mv, ret, steps, i;
514 bool increase;
515
516 ret = 0;
517
518 if (voltage < PM8921_CHG_VDDMAX_MIN
519 || voltage > PM8921_CHG_VDDMAX_MAX) {
520 pr_err("bad mV=%d asked to set\n", voltage);
521 return -EINVAL;
522 }
523
524 ret = pm_chg_vddmax_get(chip, &current_mv);
525 if (ret) {
526 pr_err("Failed to read vddmax rc=%d\n", ret);
527 return -EINVAL;
528 }
529 if (current_mv == voltage)
530 return 0;
531
532 /* Only change in increments when USB is present */
533 if (is_usb_chg_plugged_in(chip)) {
534 if (current_mv < voltage) {
535 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
536 increase = true;
537 } else {
538 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
539 increase = false;
540 }
541 for (i = 0; i < steps; i++) {
542 if (increase)
543 current_mv += PM8921_CHG_V_STEP_MV;
544 else
545 current_mv -= PM8921_CHG_V_STEP_MV;
546 ret |= __pm_chg_vddmax_set(chip, current_mv);
547 }
548 }
549 ret |= __pm_chg_vddmax_set(chip, voltage);
550 return ret;
551}
552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553#define PM8921_CHG_VDDSAFE_MIN 3400
554#define PM8921_CHG_VDDSAFE_MAX 4500
555static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
556{
557 u8 temp;
558
559 if (voltage < PM8921_CHG_VDDSAFE_MIN
560 || voltage > PM8921_CHG_VDDSAFE_MAX) {
561 pr_err("bad mV=%d asked to set\n", voltage);
562 return -EINVAL;
563 }
564 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
565 pr_debug("voltage=%d setting %02x\n", voltage, temp);
566 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
567}
568
569#define PM8921_CHG_VBATDET_MIN 3240
570#define PM8921_CHG_VBATDET_MAX 5780
571static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
572{
573 u8 temp;
574
575 if (voltage < PM8921_CHG_VBATDET_MIN
576 || voltage > PM8921_CHG_VBATDET_MAX) {
577 pr_err("bad mV=%d asked to set\n", voltage);
578 return -EINVAL;
579 }
580 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
581 pr_debug("voltage=%d setting %02x\n", voltage, temp);
582 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
583}
584
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700585#define PM8921_CHG_VINMIN_MIN_MV 3800
586#define PM8921_CHG_VINMIN_STEP_MV 100
587#define PM8921_CHG_VINMIN_USABLE_MAX 6500
588#define PM8921_CHG_VINMIN_USABLE_MIN 4300
589#define PM8921_CHG_VINMIN_MASK 0x1F
590static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
591{
592 u8 temp;
593
594 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
595 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
596 pr_err("bad mV=%d asked to set\n", voltage);
597 return -EINVAL;
598 }
599 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
600 pr_debug("voltage=%d setting %02x\n", voltage, temp);
601 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
602 temp);
603}
604
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800605static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
606{
607 u8 temp;
608 int rc, voltage_mv;
609
610 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
611 temp &= PM8921_CHG_VINMIN_MASK;
612
613 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
614 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
615
616 return voltage_mv;
617}
618
David Keitel0789fc62012-06-07 17:43:27 -0700619#define PM8917_USB_UVD_MIN_MV 3850
620#define PM8917_USB_UVD_MAX_MV 4350
621#define PM8917_USB_UVD_STEP_MV 100
622#define PM8917_USB_UVD_MASK 0x7
623static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
624{
625 u8 temp;
626
627 if (thresh_mv < PM8917_USB_UVD_MIN_MV
628 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
629 pr_err("bad mV=%d asked to set\n", thresh_mv);
630 return -EINVAL;
631 }
632 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
633 return pm_chg_masked_write(chip, OVP_USB_UVD,
634 PM8917_USB_UVD_MASK, temp);
635}
636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637#define PM8921_CHG_IBATMAX_MIN 325
638#define PM8921_CHG_IBATMAX_MAX 2000
639#define PM8921_CHG_I_MIN_MA 225
640#define PM8921_CHG_I_STEP_MA 50
641#define PM8921_CHG_I_MASK 0x3F
642static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
643{
644 u8 temp;
645
646 if (chg_current < PM8921_CHG_IBATMAX_MIN
647 || chg_current > PM8921_CHG_IBATMAX_MAX) {
648 pr_err("bad mA=%d asked to set\n", chg_current);
649 return -EINVAL;
650 }
651 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
652 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
653}
654
655#define PM8921_CHG_IBATSAFE_MIN 225
656#define PM8921_CHG_IBATSAFE_MAX 3375
657static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
658{
659 u8 temp;
660
661 if (chg_current < PM8921_CHG_IBATSAFE_MIN
662 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
663 pr_err("bad mA=%d asked to set\n", chg_current);
664 return -EINVAL;
665 }
666 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
667 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
668 PM8921_CHG_I_MASK, temp);
669}
670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700672#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673#define PM8921_CHG_ITERM_STEP_MA 10
674#define PM8921_CHG_ITERM_MASK 0xF
675static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
676{
677 u8 temp;
678
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700679 if (chg_current < PM8921_CHG_ITERM_MIN_MA
680 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 pr_err("bad mA=%d asked to set\n", chg_current);
682 return -EINVAL;
683 }
684
685 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
686 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700687 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 temp);
689}
690
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700691static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
692{
693 u8 temp;
694 int rc;
695
696 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
697 if (rc) {
698 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700699 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700700 return rc;
701 }
702 temp &= PM8921_CHG_ITERM_MASK;
703 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
704 + PM8921_CHG_ITERM_MIN_MA;
705 return 0;
706}
707
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800708struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700709 int usb_ma;
710 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800711};
712
713static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700714 {100, 0x0},
715 {200, 0x1},
716 {500, 0x2},
717 {600, 0x3},
718 {700, 0x4},
719 {800, 0x5},
720 {850, 0x6},
721 {900, 0x8},
722 {950, 0x7},
723 {1000, 0x9},
724 {1100, 0xA},
725 {1200, 0xB},
726 {1300, 0xC},
727 {1400, 0xD},
728 {1500, 0xE},
729 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800730};
731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700733#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734#define PM8921_CHG_IUSB_MAX 7
735#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700736#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700737static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738{
David Keitel38bdd4f2012-04-19 15:39:13 -0700739 u8 temp, fineres;
740 int rc;
741
742 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
743 reg_val = usb_ma_table[reg_val].value >> 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700745 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
746 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747 return -EINVAL;
748 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700749 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
750
751 /* IUSB_FINE_RES */
752 if (chip->iusb_fine_res) {
753 /* Clear IUSB_FINE_RES bit to avoid overshoot */
754 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
755 PM8917_IUSB_FINE_RES, 0);
756
757 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
758 PM8921_CHG_IUSB_MASK, temp);
759
760 if (rc) {
761 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
762 return rc;
763 }
764
765 if (fineres) {
766 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
767 PM8917_IUSB_FINE_RES, fineres);
768 if (rc)
769 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
770 rc);
771 }
772 } else {
773 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
774 PM8921_CHG_IUSB_MASK, temp);
775 if (rc)
776 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
777 }
778
779 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780}
781
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800782static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
783{
David Keitel38bdd4f2012-04-19 15:39:13 -0700784 u8 temp, fineres;
785 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800786
David Keitel38bdd4f2012-04-19 15:39:13 -0700787 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800788 *mA = 0;
789 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
790 if (rc) {
791 pr_err("err=%d reading PBL_ACCESS2\n", rc);
792 return rc;
793 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700794
795 if (chip->iusb_fine_res) {
796 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
797 if (rc) {
798 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
799 return rc;
800 }
801 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800802 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -0700803 temp = temp >> PM8921_CHG_IUSB_SHIFT;
804
805 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
806 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
807 if (usb_ma_table[i].value == temp)
808 break;
809 }
810
811 *mA = usb_ma_table[i].usb_ma;
812
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800813 return rc;
814}
815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816#define PM8921_CHG_WD_MASK 0x1F
817static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
818{
819 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700820 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
821}
822
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700823#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700824#define PM8921_CHG_TCHG_MIN 4
825#define PM8921_CHG_TCHG_MAX 512
826#define PM8921_CHG_TCHG_STEP 4
827static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
828{
829 u8 temp;
830
831 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
832 pr_err("bad max minutes =%d asked to set\n", minutes);
833 return -EINVAL;
834 }
835
836 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
837 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
838 temp);
839}
840
841#define PM8921_CHG_TTRKL_MASK 0x1F
842#define PM8921_CHG_TTRKL_MIN 1
843#define PM8921_CHG_TTRKL_MAX 64
844static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
845{
846 u8 temp;
847
848 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
849 pr_err("bad max minutes =%d asked to set\n", minutes);
850 return -EINVAL;
851 }
852
853 temp = minutes - 1;
854 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
855 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856}
857
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700858#define PM8921_CHG_VTRKL_MIN_MV 2050
859#define PM8921_CHG_VTRKL_MAX_MV 2800
860#define PM8921_CHG_VTRKL_STEP_MV 50
861#define PM8921_CHG_VTRKL_SHIFT 4
862#define PM8921_CHG_VTRKL_MASK 0xF0
863static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
864{
865 u8 temp;
866
867 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
868 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
869 pr_err("bad voltage = %dmV asked to set\n", millivolts);
870 return -EINVAL;
871 }
872
873 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
874 temp = temp << PM8921_CHG_VTRKL_SHIFT;
875 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
876 temp);
877}
878
879#define PM8921_CHG_VWEAK_MIN_MV 2100
880#define PM8921_CHG_VWEAK_MAX_MV 3600
881#define PM8921_CHG_VWEAK_STEP_MV 100
882#define PM8921_CHG_VWEAK_MASK 0x0F
883static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
884{
885 u8 temp;
886
887 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
888 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
889 pr_err("bad voltage = %dmV asked to set\n", millivolts);
890 return -EINVAL;
891 }
892
893 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
894 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
895 temp);
896}
897
898#define PM8921_CHG_ITRKL_MIN_MA 50
899#define PM8921_CHG_ITRKL_MAX_MA 200
900#define PM8921_CHG_ITRKL_MASK 0x0F
901#define PM8921_CHG_ITRKL_STEP_MA 10
902static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
903{
904 u8 temp;
905
906 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
907 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
908 pr_err("bad current = %dmA asked to set\n", milliamps);
909 return -EINVAL;
910 }
911
912 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
913
914 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
915 temp);
916}
917
918#define PM8921_CHG_IWEAK_MIN_MA 325
919#define PM8921_CHG_IWEAK_MAX_MA 525
920#define PM8921_CHG_IWEAK_SHIFT 7
921#define PM8921_CHG_IWEAK_MASK 0x80
922static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
923{
924 u8 temp;
925
926 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
927 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
928 pr_err("bad current = %dmA asked to set\n", milliamps);
929 return -EINVAL;
930 }
931
932 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
933 temp = 0;
934 else
935 temp = 1;
936
937 temp = temp << PM8921_CHG_IWEAK_SHIFT;
938 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
939 temp);
940}
941
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700942#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
943#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
944static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
945 enum pm8921_chg_cold_thr cold_thr)
946{
947 u8 temp;
948
949 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
950 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
951 return pm_chg_masked_write(chip, CHG_CNTRL_2,
952 PM8921_CHG_BATT_TEMP_THR_COLD,
953 temp);
954}
955
956#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
957#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
958static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
959 enum pm8921_chg_hot_thr hot_thr)
960{
961 u8 temp;
962
963 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
964 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
965 return pm_chg_masked_write(chip, CHG_CNTRL_2,
966 PM8921_CHG_BATT_TEMP_THR_HOT,
967 temp);
968}
969
Jay Chokshid674a512012-03-15 14:06:04 -0700970#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
971#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
972static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
973 enum pm8921_chg_led_src_config led_src_config)
974{
975 u8 temp;
976
977 if (led_src_config < LED_SRC_GND ||
978 led_src_config > LED_SRC_BYPASS)
979 return -EINVAL;
980
981 if (led_src_config == LED_SRC_BYPASS)
982 return 0;
983
984 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
985
986 return pm_chg_masked_write(chip, CHG_CNTRL_3,
987 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
988}
989
David Keitel8c5201a2012-02-24 16:08:54 -0800990static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
991{
992 u8 temp;
993 int rc;
994
995 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
996 if (rc) {
997 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
998 return;
999 }
1000 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
1001 if (rc) {
1002 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
1003 return;
1004 }
1005 /* set the input voltage disable bit and the write bit */
1006 temp |= 0x81;
1007 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1008 if (rc) {
1009 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
1010 return;
1011 }
1012}
1013
1014static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
1015{
1016 u8 temp;
1017 int rc;
1018
1019 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
1020 if (rc) {
1021 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
1022 return;
1023 }
1024 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
1025 if (rc) {
1026 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
1027 return;
1028 }
1029 /* unset the input voltage disable bit */
1030 temp &= 0xFE;
1031 /* set the write bit */
1032 temp |= 0x80;
1033 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1034 if (rc) {
1035 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
1036 return;
1037 }
1038}
1039
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001040static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1041{
1042 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001043 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001044
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001045 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001046 if (rc) {
1047 pr_err("error reading batt id channel = %d, rc = %d\n",
1048 chip->vbat_channel, rc);
1049 return rc;
1050 }
1051 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1052 result.measurement);
1053 return result.physical;
1054}
1055
1056static int is_battery_valid(struct pm8921_chg_chip *chip)
1057{
1058 int64_t rc;
1059
1060 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1061 return 1;
1062
1063 rc = read_battery_id(chip);
1064 if (rc < 0) {
1065 pr_err("error reading batt id channel = %d, rc = %lld\n",
1066 chip->vbat_channel, rc);
1067 /* assume battery id is valid when adc error happens */
1068 return 1;
1069 }
1070
1071 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1072 pr_err("batt_id phy =%lld is not valid\n", rc);
1073 return 0;
1074 }
1075 return 1;
1076}
1077
1078static void check_battery_valid(struct pm8921_chg_chip *chip)
1079{
1080 if (is_battery_valid(chip) == 0) {
1081 pr_err("batt_id not valid, disbling charging\n");
1082 pm_chg_auto_enable(chip, 0);
1083 } else {
1084 pm_chg_auto_enable(chip, !charging_disabled);
1085 }
1086}
1087
1088static void battery_id_valid(struct work_struct *work)
1089{
1090 struct pm8921_chg_chip *chip = container_of(work,
1091 struct pm8921_chg_chip, battery_id_valid_work);
1092
1093 check_battery_valid(chip);
1094}
1095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1097{
1098 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1099 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1100 enable_irq(chip->pmic_chg_irq[interrupt]);
1101 }
1102}
1103
1104static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1105{
1106 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1107 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1108 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1109 }
1110}
1111
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001112static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1113{
1114 return test_bit(interrupt, chip->enabled_irqs);
1115}
1116
Amir Samuelovd31ef502011-10-26 14:41:36 +02001117static bool is_ext_charging(struct pm8921_chg_chip *chip)
1118{
David Keitel88e1b572012-01-11 11:57:14 -08001119 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001120
David Keitel88e1b572012-01-11 11:57:14 -08001121 if (!chip->ext_psy)
1122 return false;
1123 if (chip->ext_psy->get_property(chip->ext_psy,
1124 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1125 return false;
1126 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1127 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001128
1129 return false;
1130}
1131
1132static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1133{
David Keitel88e1b572012-01-11 11:57:14 -08001134 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001135
David Keitel88e1b572012-01-11 11:57:14 -08001136 if (!chip->ext_psy)
1137 return false;
1138 if (chip->ext_psy->get_property(chip->ext_psy,
1139 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1140 return false;
1141 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001142 return true;
1143
1144 return false;
1145}
1146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147static int is_battery_charging(int fsm_state)
1148{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001149 if (is_ext_charging(the_chip))
1150 return 1;
1151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152 switch (fsm_state) {
1153 case FSM_STATE_ATC_2A:
1154 case FSM_STATE_ATC_2B:
1155 case FSM_STATE_ON_CHG_AND_BAT_6:
1156 case FSM_STATE_FAST_CHG_7:
1157 case FSM_STATE_TRKL_CHG_8:
1158 return 1;
1159 }
1160 return 0;
1161}
1162
1163static void bms_notify(struct work_struct *work)
1164{
1165 struct bms_notify *n = container_of(work, struct bms_notify, work);
1166
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001167 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001169 } else {
1170 pm8921_bms_charging_end(n->is_battery_full);
1171 n->is_battery_full = 0;
1172 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001173}
1174
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001175static void bms_notify_check(struct pm8921_chg_chip *chip)
1176{
1177 int fsm_state, new_is_charging;
1178
1179 fsm_state = pm_chg_get_fsm_state(chip);
1180 new_is_charging = is_battery_charging(fsm_state);
1181
1182 if (chip->bms_notify.is_charging ^ new_is_charging) {
1183 chip->bms_notify.is_charging = new_is_charging;
1184 schedule_work(&(chip->bms_notify.work));
1185 }
1186}
1187
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001188static enum power_supply_property pm_power_props_usb[] = {
1189 POWER_SUPPLY_PROP_PRESENT,
1190 POWER_SUPPLY_PROP_ONLINE,
1191 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001192 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001193};
1194
1195static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001197 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198};
1199
1200static char *pm_power_supplied_to[] = {
1201 "battery",
1202};
1203
David Keitel6ed71a52012-01-30 12:42:18 -08001204#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001205static int pm_power_get_property_mains(struct power_supply *psy,
1206 enum power_supply_property psp,
1207 union power_supply_propval *val)
1208{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001209 /* Check if called before init */
1210 if (!the_chip)
1211 return -EINVAL;
1212
1213 switch (psp) {
1214 case POWER_SUPPLY_PROP_PRESENT:
1215 case POWER_SUPPLY_PROP_ONLINE:
1216 val->intval = 0;
1217 if (charging_disabled)
1218 return 0;
1219
1220 /* check external charger first before the dc path */
1221 if (is_ext_charging(the_chip)) {
1222 val->intval = 1;
1223 return 0;
1224 }
1225
1226 if (pm_is_chg_charge_dis(the_chip)) {
1227 val->intval = 0;
1228 return 0;
1229 }
1230
1231 if (the_chip->dc_present) {
1232 val->intval = 1;
1233 return 0;
1234 }
1235
1236 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001237 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001238 val->intval = is_usb_chg_plugged_in(the_chip);
1239 return 0;
1240
1241 break;
1242 default:
1243 return -EINVAL;
1244 }
1245 return 0;
1246}
1247
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001248static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1249{
1250 int rc;
1251
1252 if (!chip->host_mode)
1253 return 0;
1254
1255 /* enable usbin valid comparator and remove force usb ovp fet off */
1256 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB2);
1257 if (rc < 0) {
1258 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1259 return rc;
1260 }
1261
1262 chip->host_mode = 0;
1263
1264 return 0;
1265}
1266
1267static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1268{
1269 int rc;
1270
1271 if (chip->host_mode)
1272 return 0;
1273
1274 /* disable usbin valid comparator and force usb ovp fet off */
1275 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB3);
1276 if (rc < 0) {
1277 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1278 return rc;
1279 }
1280
1281 chip->host_mode = 1;
1282
1283 return 0;
1284}
1285
1286static int pm_power_set_property_usb(struct power_supply *psy,
1287 enum power_supply_property psp,
1288 const union power_supply_propval *val)
1289{
Devin Kim81265542012-09-01 05:06:22 -07001290 struct pm8921_chg_chip *chip = the_chip;
1291
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001292 /* Check if called before init */
Devin Kim81265542012-09-01 05:06:22 -07001293 if (!chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001294 return -EINVAL;
1295
1296 switch (psp) {
Devin Kim81265542012-09-01 05:06:22 -07001297 case POWER_SUPPLY_PROP_CURRENT_MAX:
1298 if (val->intval &&
1299 val->intval <= (USB_WALL_THRESHOLD_MA*1000)) {
1300 usb_target_ma = 0;
1301 } else {
1302 usb_target_ma = val->intval/1000;
1303 if (!delayed_work_pending(&chip->unplug_check_work)) {
1304 schedule_delayed_work(
1305 &chip->unplug_check_work,
1306 round_jiffies_relative(msecs_to_jiffies
1307 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1308 }
1309 }
1310 pr_info("usb_target_ma %d\n", usb_target_ma);
1311 break;
1312 case POWER_SUPPLY_PROP_PRESENT:
1313 case POWER_SUPPLY_PROP_ONLINE:
1314 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001315 case POWER_SUPPLY_PROP_SCOPE:
1316 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Devin Kim81265542012-09-01 05:06:22 -07001317 return switch_usb_to_host_mode(chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001318 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Devin Kim81265542012-09-01 05:06:22 -07001319 return switch_usb_to_charge_mode(chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001320 else
1321 return -EINVAL;
1322 break;
1323 default:
1324 return -EINVAL;
1325 }
1326 return 0;
1327}
1328
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001329static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 enum power_supply_property psp,
1331 union power_supply_propval *val)
1332{
David Keitel6ed71a52012-01-30 12:42:18 -08001333 int current_max;
1334
1335 /* Check if called before init */
1336 if (!the_chip)
1337 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338
1339 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001340 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001341 if (pm_is_chg_charge_dis(the_chip)) {
1342 val->intval = 0;
1343 } else {
1344 pm_chg_iusbmax_get(the_chip, &current_max);
1345 val->intval = current_max;
1346 }
David Keitel6ed71a52012-01-30 12:42:18 -08001347 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001349 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001350 val->intval = 0;
1351 if (charging_disabled)
1352 return 0;
1353
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001354 /*
1355 * if drawing any current from usb is disabled behave
1356 * as if no usb cable is connected
1357 */
1358 if (pm_is_chg_charge_dis(the_chip))
1359 return 0;
1360
David Keitel63f71662012-02-08 20:30:00 -08001361 /* USB charging */
Devin Kim2073afb2012-09-05 13:01:51 -07001362 if (usb_target_ma == 0)
1363 val->intval = the_chip->usb_present;
1364 else if (usb_target_ma <= USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001365 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001366 else
Devin Kim81265542012-09-01 05:06:22 -07001367 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001369
1370 case POWER_SUPPLY_PROP_SCOPE:
1371 if (the_chip->host_mode)
1372 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1373 else
1374 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1375 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 default:
1377 return -EINVAL;
1378 }
1379 return 0;
1380}
1381
1382static enum power_supply_property msm_batt_power_props[] = {
1383 POWER_SUPPLY_PROP_STATUS,
1384 POWER_SUPPLY_PROP_CHARGE_TYPE,
1385 POWER_SUPPLY_PROP_HEALTH,
1386 POWER_SUPPLY_PROP_PRESENT,
1387 POWER_SUPPLY_PROP_TECHNOLOGY,
1388 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1389 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1390 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1391 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001392 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001393 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001394 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395};
1396
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001397static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398{
1399 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001400 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001402 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 if (rc) {
1404 pr_err("error reading adc channel = %d, rc = %d\n",
1405 chip->vbat_channel, rc);
1406 return rc;
1407 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001408 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 result.measurement);
1410 return (int)result.physical;
1411}
1412
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001413static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1414{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001415 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1416 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1417 unsigned int low_voltage = chip->min_voltage_mv;
1418 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001419
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001420 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001421 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001422 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001423 return 100;
1424 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001425 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001426 / (high_voltage - low_voltage);
1427}
1428
David Keitel4f9397b2012-04-16 11:46:16 -07001429static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1430{
1431 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1432}
1433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1435{
David Keitel4f9397b2012-04-16 11:46:16 -07001436 int percent_soc;
1437
1438 if (!get_prop_batt_present(chip))
1439 percent_soc = voltage_based_capacity(chip);
1440 else
1441 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001442
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001443 if (percent_soc == -ENXIO)
1444 percent_soc = voltage_based_capacity(chip);
1445
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001446 if (percent_soc <= 10)
1447 pr_warn("low battery charge = %d%%\n", percent_soc);
1448
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001449 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001450 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451}
1452
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001453static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1454{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001455 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001456
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001457 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001458 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001459 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001460 }
1461
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001462 if (rc) {
1463 pr_err("unable to get batt current rc = %d\n", rc);
1464 return rc;
1465 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001466 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001467 }
1468}
1469
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001470static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1471{
1472 int rc;
1473
1474 rc = pm8921_bms_get_fcc();
1475 if (rc < 0)
1476 pr_err("unable to get batt fcc rc = %d\n", rc);
1477 return rc;
1478}
1479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1481{
1482 int temp;
1483
Devin Kim32599592012-08-22 11:40:44 -07001484 if (chip->ext_batt_temp_monitor) {
1485 return chip->ext_batt_health;
1486 } else {
1487 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1488 if (temp)
1489 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490
Devin Kim32599592012-08-22 11:40:44 -07001491 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1492 if (temp)
1493 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494
Devin Kim32599592012-08-22 11:40:44 -07001495 return POWER_SUPPLY_HEALTH_GOOD;
1496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497}
1498
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1500{
1501 int temp;
1502
Amir Samuelovd31ef502011-10-26 14:41:36 +02001503 if (!get_prop_batt_present(chip))
1504 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1505
1506 if (is_ext_trickle_charging(chip))
1507 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1508
1509 if (is_ext_charging(chip))
1510 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1513 if (temp)
1514 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1515
1516 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1517 if (temp)
1518 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1519
1520 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1521}
1522
1523static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1524{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001525 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1526 int fsm_state = pm_chg_get_fsm_state(chip);
1527 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528
David Keitel88e1b572012-01-11 11:57:14 -08001529 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001530 if (chip->ext_charge_done)
1531 return POWER_SUPPLY_STATUS_FULL;
1532 if (chip->ext_charging)
1533 return POWER_SUPPLY_STATUS_CHARGING;
1534 }
1535
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001536 for (i = 0; i < ARRAY_SIZE(map); i++)
1537 if (map[i].fsm_state == fsm_state)
1538 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001539
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001540 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1541 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1542 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001543 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
Devin Kim32599592012-08-22 11:40:44 -07001544 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ)
1545 || (chip->ext_batt_temp_monitor &&
1546 (chip->ext_batt_health == POWER_SUPPLY_HEALTH_OVERHEAT)))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001547
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001548 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001549 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001550 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551}
1552
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001553#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001554static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1555{
1556 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001557 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001558
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001559 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001560 if (rc) {
1561 pr_err("error reading adc channel = %d, rc = %d\n",
1562 chip->vbat_channel, rc);
1563 return rc;
1564 }
1565 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1566 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001567 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1568 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1569 (int) result.physical);
1570
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001571 return (int)result.physical;
1572}
1573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574static int pm_batt_power_get_property(struct power_supply *psy,
1575 enum power_supply_property psp,
1576 union power_supply_propval *val)
1577{
1578 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1579 batt_psy);
1580
1581 switch (psp) {
1582 case POWER_SUPPLY_PROP_STATUS:
kyungtae.oh1ff608a2012-07-19 14:31:54 +09001583#ifdef CONFIG_WIRELESS_CHARGER
1584 if(wireless_charging) {
1585 val->intval = 1; //POWER_SUPPLY_STATUS_CHARGING
1586 break;
1587 }
1588#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 val->intval = get_prop_batt_status(chip);
1590 break;
1591 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1592 val->intval = get_prop_charge_type(chip);
1593 break;
1594 case POWER_SUPPLY_PROP_HEALTH:
1595 val->intval = get_prop_batt_health(chip);
1596 break;
1597 case POWER_SUPPLY_PROP_PRESENT:
1598 val->intval = get_prop_batt_present(chip);
1599 break;
1600 case POWER_SUPPLY_PROP_TECHNOLOGY:
1601 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1602 break;
1603 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001604 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 break;
1606 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001607 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 break;
1609 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001610 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 break;
1612 case POWER_SUPPLY_PROP_CAPACITY:
1613 val->intval = get_prop_batt_capacity(chip);
1614 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001615 case POWER_SUPPLY_PROP_CURRENT_NOW:
1616 val->intval = get_prop_batt_current(chip);
1617 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001618 case POWER_SUPPLY_PROP_TEMP:
1619 val->intval = get_prop_batt_temp(chip);
1620 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001621 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001622 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001623 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624 default:
1625 return -EINVAL;
1626 }
1627
1628 return 0;
1629}
1630
1631static void (*notify_vbus_state_func_ptr)(int);
1632static int usb_chg_current;
1633static DEFINE_SPINLOCK(vbus_lock);
1634
1635int pm8921_charger_register_vbus_sn(void (*callback)(int))
1636{
1637 pr_debug("%p\n", callback);
1638 notify_vbus_state_func_ptr = callback;
1639 return 0;
1640}
1641EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1642
1643/* this is passed to the hsusb via platform_data msm_otg_pdata */
1644void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1645{
1646 pr_debug("%p\n", callback);
1647 notify_vbus_state_func_ptr = NULL;
1648}
1649EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1650
1651static void notify_usb_of_the_plugin_event(int plugin)
1652{
1653 plugin = !!plugin;
1654 if (notify_vbus_state_func_ptr) {
1655 pr_debug("notifying plugin\n");
1656 (*notify_vbus_state_func_ptr) (plugin);
1657 } else {
1658 pr_debug("unable to notify plugin\n");
1659 }
1660}
1661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662/* assumes vbus_lock is held */
1663static void __pm8921_charger_vbus_draw(unsigned int mA)
1664{
1665 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001666 if (!the_chip) {
1667 pr_err("called before init\n");
1668 return;
1669 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670
David Keitel38bdd4f2012-04-19 15:39:13 -07001671 if (mA >= 0 && mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001673 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001675 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676 }
1677 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1678 if (rc)
1679 pr_err("fail to set suspend bit rc=%d\n", rc);
1680 } else {
1681 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1682 if (rc)
1683 pr_err("fail to reset suspend bit rc=%d\n", rc);
1684 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1685 if (usb_ma_table[i].usb_ma <= mA)
1686 break;
1687 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001688
1689 /* Check if IUSB_FINE_RES is available */
1690 if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
1691 && !the_chip->iusb_fine_res)
1692 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001693 if (i < 0)
1694 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001695 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001697 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 }
1699 }
1700}
1701
1702/* USB calls these to tell us how much max usb current the system can draw */
1703void pm8921_charger_vbus_draw(unsigned int mA)
1704{
1705 unsigned long flags;
1706
1707 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001708
David Keitel62c6a4b2012-05-17 12:54:59 -07001709 if (!the_chip) {
1710 pr_err("chip not yet initalized\n");
1711 return;
1712 }
1713
1714 /*
1715 * Reject VBUS requests if USB connection is the only available
1716 * power source. This makes sure that if booting without
1717 * battery the iusb_max value is not decreased avoiding potential
1718 * brown_outs.
1719 *
1720 * This would also apply when the battery has been
1721 * removed from the running system.
1722 */
1723 if (!get_prop_batt_present(the_chip)
1724 && !is_dc_chg_plugged_in(the_chip)) {
1725 pr_err("rejected: no other power source connected\n");
1726 return;
1727 }
1728
David Keitelacf57c82012-03-07 18:48:50 -08001729 if (usb_max_current && mA > usb_max_current) {
1730 pr_warn("restricting usb current to %d instead of %d\n",
1731 usb_max_current, mA);
1732 mA = usb_max_current;
1733 }
Devin Kim2073afb2012-09-05 13:01:51 -07001734 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1735 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 spin_lock_irqsave(&vbus_lock, flags);
1738 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001739 if (mA > USB_WALL_THRESHOLD_MA)
1740 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1741 else
1742 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 } else {
1744 /*
1745 * called before pmic initialized,
1746 * save this value and use it at probe
1747 */
David Keitelacf57c82012-03-07 18:48:50 -08001748 if (mA > USB_WALL_THRESHOLD_MA)
1749 usb_chg_current = USB_WALL_THRESHOLD_MA;
1750 else
1751 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 }
1753 spin_unlock_irqrestore(&vbus_lock, flags);
1754}
1755EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1756
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001757int pm8921_charger_enable(bool enable)
1758{
1759 int rc;
1760
1761 if (!the_chip) {
1762 pr_err("called before init\n");
1763 return -EINVAL;
1764 }
1765 enable = !!enable;
1766 rc = pm_chg_auto_enable(the_chip, enable);
1767 if (rc)
1768 pr_err("Failed rc=%d\n", rc);
1769 return rc;
1770}
1771EXPORT_SYMBOL(pm8921_charger_enable);
1772
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001773int pm8921_is_usb_chg_plugged_in(void)
1774{
1775 if (!the_chip) {
1776 pr_err("called before init\n");
1777 return -EINVAL;
1778 }
1779 return is_usb_chg_plugged_in(the_chip);
1780}
1781EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1782
1783int pm8921_is_dc_chg_plugged_in(void)
1784{
1785 if (!the_chip) {
1786 pr_err("called before init\n");
1787 return -EINVAL;
1788 }
1789 return is_dc_chg_plugged_in(the_chip);
1790}
1791EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1792
1793int pm8921_is_battery_present(void)
1794{
1795 if (!the_chip) {
1796 pr_err("called before init\n");
1797 return -EINVAL;
1798 }
1799 return get_prop_batt_present(the_chip);
1800}
1801EXPORT_SYMBOL(pm8921_is_battery_present);
1802
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07001803int pm8921_is_batfet_closed(void)
1804{
1805 if (!the_chip) {
1806 pr_err("called before init\n");
1807 return -EINVAL;
1808 }
1809 return is_batfet_closed(the_chip);
1810}
1811EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08001812/*
1813 * Disabling the charge current limit causes current
1814 * current limits to have no monitoring. An adequate charger
1815 * capable of supplying high current while sustaining VIN_MIN
1816 * is required if the limiting is disabled.
1817 */
1818int pm8921_disable_input_current_limit(bool disable)
1819{
1820 if (!the_chip) {
1821 pr_err("called before init\n");
1822 return -EINVAL;
1823 }
1824 if (disable) {
1825 pr_warn("Disabling input current limit!\n");
1826
1827 return pm8xxx_writeb(the_chip->dev->parent,
1828 CHG_BUCK_CTRL_TEST3, 0xF2);
1829 }
1830 return 0;
1831}
1832EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1833
David Keitel0789fc62012-06-07 17:43:27 -07001834int pm8917_set_under_voltage_detection_threshold(int mv)
1835{
1836 if (!the_chip) {
1837 pr_err("called before init\n");
1838 return -EINVAL;
1839 }
1840 return pm_chg_uvd_threshold_set(the_chip, mv);
1841}
1842EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
1843
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001844int pm8921_set_max_battery_charge_current(int ma)
1845{
1846 if (!the_chip) {
1847 pr_err("called before init\n");
1848 return -EINVAL;
1849 }
choongryeol.lee45ccbb52012-08-25 00:15:42 -07001850
1851 if (thermal_mitigation != 0 && the_chip->thermal_mitigation)
1852 ma = min((unsigned int)ma,
1853 the_chip->thermal_mitigation[thermal_mitigation]);
1854
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001855 return pm_chg_ibatmax_set(the_chip, ma);
1856}
1857EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1858
1859int pm8921_disable_source_current(bool disable)
1860{
1861 if (!the_chip) {
1862 pr_err("called before init\n");
1863 return -EINVAL;
1864 }
1865 if (disable)
1866 pr_warn("current drawn from chg=0, battery provides current\n");
1867 return pm_chg_charge_dis(the_chip, disable);
1868}
1869EXPORT_SYMBOL(pm8921_disable_source_current);
1870
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001871int pm8921_regulate_input_voltage(int voltage)
1872{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001873 int rc;
1874
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001875 if (!the_chip) {
1876 pr_err("called before init\n");
1877 return -EINVAL;
1878 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001879 rc = pm_chg_vinmin_set(the_chip, voltage);
1880
1881 if (rc == 0)
1882 the_chip->vin_min = voltage;
1883
1884 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001885}
1886
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001887#define USB_OV_THRESHOLD_MASK 0x60
1888#define USB_OV_THRESHOLD_SHIFT 5
1889int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1890{
1891 u8 temp;
1892
1893 if (!the_chip) {
1894 pr_err("called before init\n");
1895 return -EINVAL;
1896 }
1897
1898 if (ov > PM_USB_OV_7V) {
1899 pr_err("limiting to over voltage threshold to 7volts\n");
1900 ov = PM_USB_OV_7V;
1901 }
1902
1903 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1904
1905 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1906 USB_OV_THRESHOLD_MASK, temp);
1907}
1908EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1909
1910#define USB_DEBOUNCE_TIME_MASK 0x06
1911#define USB_DEBOUNCE_TIME_SHIFT 1
1912int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1913{
1914 u8 temp;
1915
1916 if (!the_chip) {
1917 pr_err("called before init\n");
1918 return -EINVAL;
1919 }
1920
1921 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1922 pr_err("limiting debounce to 80.5ms\n");
1923 ms = PM_USB_DEBOUNCE_80P5MS;
1924 }
1925
1926 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1927
1928 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1929 USB_DEBOUNCE_TIME_MASK, temp);
1930}
1931EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1932
1933#define USB_OVP_DISABLE_MASK 0x80
1934int pm8921_usb_ovp_disable(int disable)
1935{
1936 u8 temp = 0;
1937
1938 if (!the_chip) {
1939 pr_err("called before init\n");
1940 return -EINVAL;
1941 }
1942
1943 if (disable)
1944 temp = USB_OVP_DISABLE_MASK;
1945
1946 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1947 USB_OVP_DISABLE_MASK, temp);
1948}
1949
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001950bool pm8921_is_battery_charging(int *source)
1951{
1952 int fsm_state, is_charging, dc_present, usb_present;
1953
1954 if (!the_chip) {
1955 pr_err("called before init\n");
1956 return -EINVAL;
1957 }
1958 fsm_state = pm_chg_get_fsm_state(the_chip);
1959 is_charging = is_battery_charging(fsm_state);
1960 if (is_charging == 0) {
1961 *source = PM8921_CHG_SRC_NONE;
1962 return is_charging;
1963 }
1964
1965 if (source == NULL)
1966 return is_charging;
1967
1968 /* the battery is charging, the source is requested, find it */
1969 dc_present = is_dc_chg_plugged_in(the_chip);
1970 usb_present = is_usb_chg_plugged_in(the_chip);
1971
1972 if (dc_present && !usb_present)
1973 *source = PM8921_CHG_SRC_DC;
1974
1975 if (usb_present && !dc_present)
1976 *source = PM8921_CHG_SRC_USB;
1977
1978 if (usb_present && dc_present)
1979 /*
1980 * The system always chooses dc for charging since it has
1981 * higher priority.
1982 */
1983 *source = PM8921_CHG_SRC_DC;
1984
1985 return is_charging;
1986}
1987EXPORT_SYMBOL(pm8921_is_battery_charging);
1988
David Keitel86034022012-04-18 12:33:58 -07001989int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1990{
1991 if (!the_chip) {
1992 pr_err("called before init\n");
1993 return -EINVAL;
1994 }
1995
1996 if (type < POWER_SUPPLY_TYPE_USB)
1997 return -EINVAL;
1998
1999 the_chip->usb_psy.type = type;
2000 power_supply_changed(&the_chip->usb_psy);
2001 power_supply_changed(&the_chip->dc_psy);
2002 return 0;
2003}
2004EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2005
kyungtae.oh1ff608a2012-07-19 14:31:54 +09002006#ifdef CONFIG_WIRELESS_CHARGER
2007int set_wireless_power_supply_control(int value)
2008{
2009 if (!the_chip) {
2010 pr_err("called before init\n");
2011 return -EINVAL;
2012 }
2013
2014 wireless_charging = value;
2015 power_supply_changed(&the_chip->batt_psy);
2016
2017 return 0;
2018}
2019EXPORT_SYMBOL(set_wireless_power_supply_control);
2020#endif
2021
choongryeol.lee45ccbb52012-08-25 00:15:42 -07002022int pm8921_set_ext_battery_health(int health, int i_limit)
Devin Kim32599592012-08-22 11:40:44 -07002023{
2024 if (!the_chip) {
2025 pr_err("called before init\n");
2026 return -EINVAL;
2027 }
2028
choongryeol.lee45ccbb52012-08-25 00:15:42 -07002029 the_chip->ext_batt_health = health;
2030 the_chip->ext_warm_i_limit = i_limit;
Devin Kim32599592012-08-22 11:40:44 -07002031
choongryeol.lee45ccbb52012-08-25 00:15:42 -07002032 pr_debug("health = %d i_decrease = %d\n", the_chip->ext_batt_health,
2033 the_chip->ext_warm_i_limit);
Devin Kim32599592012-08-22 11:40:44 -07002034 return 0;
2035}
2036EXPORT_SYMBOL(pm8921_set_ext_battery_health);
2037
2038
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002039int pm8921_batt_temperature(void)
2040{
2041 if (!the_chip) {
2042 pr_err("called before init\n");
2043 return -EINVAL;
2044 }
2045 return get_prop_batt_temp(the_chip);
2046}
2047
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002048static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
2049{
2050 int rc = 0;
2051
2052 rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2053 if (!rc)
2054 rc = pm8xxx_batt_alarm_enable(
2055 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2056 if (rc) {
2057 pr_err("unable to set batt alarm state rc=%d\n", rc);
2058 return rc;
2059 }
2060
2061 return rc;
2062}
2063static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
2064{
2065 int rc = 0;
2066
2067 rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2068 if (!rc)
2069 rc = pm8xxx_batt_alarm_disable(
2070 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2071 if (rc) {
2072 pr_err("unable to set batt alarm state rc=%d\n", rc);
2073 return rc;
2074 }
2075
2076 /*
2077 * The batt-alarm driver requires sane values for both min / max,
2078 * regardless of whether they're both activated.
2079 */
2080 rc = pm8xxx_batt_alarm_threshold_set(
2081 PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
2082 chip->alarm_voltage_mv);
2083 /* We only handle the lower limit of the battery alarm, thus
2084 * set a high sane maximum.
2085 */
2086 if (!rc)
2087 rc = pm8xxx_batt_alarm_threshold_set(
2088 PM8XXX_BATT_ALARM_UPPER_COMPARATOR, 5000);
2089 if (rc) {
2090 pr_err("unable to set batt alarm threshold rc=%d\n", rc);
2091 return rc;
2092 }
2093
2094 rc = pm8xxx_batt_alarm_hold_time_set(
2095 PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
2096 if (rc) {
2097 pr_err("unable to set batt alarm hold time rc=%d\n", rc);
2098 return rc;
2099 }
2100
2101 /* PWM enabled at 2Hz */
2102 rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
2103 if (rc) {
2104 pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
2105 return rc;
2106 }
2107
2108 rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
2109 if (rc) {
2110 pr_err("unable to register alarm notifier rc=%d\n", rc);
2111 return rc;
2112 }
2113
2114 return rc;
2115}
2116
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2118{
2119 int usb_present;
2120
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002121 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122 usb_present = is_usb_chg_plugged_in(chip);
2123 if (chip->usb_present ^ usb_present) {
2124 notify_usb_of_the_plugin_event(usb_present);
2125 chip->usb_present = usb_present;
2126 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002127 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002128 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002130 if (usb_present) {
2131 schedule_delayed_work(&chip->unplug_check_work,
2132 round_jiffies_relative(msecs_to_jiffies
2133 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002134 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2135 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002136 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002137 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002138 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002139 }
David Keitel8c5201a2012-02-24 16:08:54 -08002140 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002141 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142}
2143
Amir Samuelovd31ef502011-10-26 14:41:36 +02002144static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2145{
David Keitel88e1b572012-01-11 11:57:14 -08002146 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002147 pr_debug("external charger not registered.\n");
2148 return;
2149 }
2150
2151 if (!chip->ext_charging) {
2152 pr_debug("already not charging.\n");
2153 return;
2154 }
2155
David Keitel88e1b572012-01-11 11:57:14 -08002156 power_supply_set_charge_type(chip->ext_psy,
2157 POWER_SUPPLY_CHARGE_TYPE_NONE);
2158 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002159 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002160 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002161 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002162 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002163 /* Update battery charging LEDs and user space battery info */
2164 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002165}
2166
2167static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2168{
2169 int dc_present;
2170 int batt_present;
2171 int batt_temp_ok;
2172 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002173 unsigned long delay =
2174 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2175
David Keitel88e1b572012-01-11 11:57:14 -08002176 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002177 pr_debug("external charger not registered.\n");
2178 return;
2179 }
2180
2181 if (chip->ext_charging) {
2182 pr_debug("already charging.\n");
2183 return;
2184 }
2185
David Keitel88e1b572012-01-11 11:57:14 -08002186 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002187 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2188 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002189
2190 if (!dc_present) {
2191 pr_warn("%s. dc not present.\n", __func__);
2192 return;
2193 }
2194 if (!batt_present) {
2195 pr_warn("%s. battery not present.\n", __func__);
2196 return;
2197 }
2198 if (!batt_temp_ok) {
2199 pr_warn("%s. battery temperature not ok.\n", __func__);
2200 return;
2201 }
David Keitel88e1b572012-01-11 11:57:14 -08002202 pm8921_disable_source_current(true); /* Force BATFET=ON */
2203 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002204 if (vbat_ov) {
2205 pr_warn("%s. battery over voltage.\n", __func__);
2206 return;
2207 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02002208
David Keitel6ccbf132012-05-30 14:21:24 -07002209 schedule_delayed_work(&chip->unplug_check_work,
2210 round_jiffies_relative(msecs_to_jiffies
2211 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2212 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2213
David Keitel63f71662012-02-08 20:30:00 -08002214 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002215 power_supply_set_charge_type(chip->ext_psy,
2216 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08002217 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002218 chip->ext_charging = true;
2219 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002220 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002221 /* Start BMS */
2222 schedule_delayed_work(&chip->eoc_work, delay);
2223 wake_lock(&chip->eoc_wake_lock);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002224 /* Update battery charging LEDs and user space battery info */
2225 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002226}
2227
David Keitel6ccbf132012-05-30 14:21:24 -07002228static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002229{
2230 u8 temp;
2231 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002232
David Keitel6ccbf132012-05-30 14:21:24 -07002233 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002234 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002235 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002236 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002237 }
David Keitel6ccbf132012-05-30 14:21:24 -07002238 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002239 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002240 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002241 return;
2242 }
2243 /* set ovp fet disable bit and the write bit */
2244 temp |= 0x81;
David Keitel6ccbf132012-05-30 14:21:24 -07002245 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002246 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002247 pr_err("Failed to write 0x%x OVP_TEST rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002248 return;
2249 }
2250}
2251
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002252static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
2253 unsigned long status, void *unused)
2254{
2255 int rc, fsm_state;
2256
2257 pr_info("status: %lu\n", status);
2258
2259 /* Check if called before init */
2260
2261 switch (status) {
2262 case 0:
2263 pr_err("spurious interrupt\n");
2264 break;
2265 /* expected case - trip of low threshold */
2266 case 1:
2267 if (!the_chip) {
2268 pr_err("not initialized\n");
2269 return -EINVAL;
2270 }
2271
2272 fsm_state = pm_chg_get_fsm_state(the_chip);
2273 the_chip->disable_hw_clock_switching = 1;
2274
2275 rc = pm8xxx_batt_alarm_disable(
2276 PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2277 if (!rc)
2278 rc = pm8xxx_batt_alarm_disable(
2279 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2280 if (rc)
2281 pr_err("unable to set alarm state rc=%d\n", rc);
2282 break;
2283 case 2:
2284 pr_err("trip of high threshold\n");
2285 break;
2286 default:
2287 pr_err("error received\n");
2288 };
2289
2290 return 0;
2291}
2292
David Keitel6ccbf132012-05-30 14:21:24 -07002293static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002294{
2295 u8 temp;
2296 int rc;
2297
David Keitel6ccbf132012-05-30 14:21:24 -07002298 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002299 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002300 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002301 return;
2302 }
David Keitel6ccbf132012-05-30 14:21:24 -07002303 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002304 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002305 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002306 return;
2307 }
2308 /* unset ovp fet disable bit and set the write bit */
2309 temp &= 0xFE;
2310 temp |= 0x80;
David Keitel6ccbf132012-05-30 14:21:24 -07002311 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002312 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002313 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002314 temp, rc);
2315 return;
2316 }
2317}
2318
2319static int param_open_ovp_counter = 10;
2320module_param(param_open_ovp_counter, int, 0644);
2321
David Keitel6ccbf132012-05-30 14:21:24 -07002322#define USB_ACTIVE_BIT BIT(5)
2323#define DC_ACTIVE_BIT BIT(6)
2324static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2325 u8 active_chg_mask)
2326{
2327 if (active_chg_mask & USB_ACTIVE_BIT)
2328 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2329 else if (active_chg_mask & DC_ACTIVE_BIT)
2330 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2331 else
2332 return 0;
2333}
2334
David Keitel8c5201a2012-02-24 16:08:54 -08002335#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002336#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002337static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002338{
David Keitel6ccbf132012-05-30 14:21:24 -07002339 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002340 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002341 u8 active_mask = 0;
2342 u16 ovpreg, ovptestreg;
2343
2344 if (is_usb_chg_plugged_in(chip) &&
2345 (chip->active_path & USB_ACTIVE_BIT)) {
2346 ovpreg = USB_OVP_CONTROL;
2347 ovptestreg = USB_OVP_TEST;
2348 active_mask = USB_ACTIVE_BIT;
2349 } else if (is_dc_chg_plugged_in(chip) &&
2350 (chip->active_path & DC_ACTIVE_BIT)) {
2351 ovpreg = DC_OVP_CONTROL;
2352 ovptestreg = DC_OVP_TEST;
2353 active_mask = DC_ACTIVE_BIT;
2354 } else {
2355 return;
2356 }
David Keitel8c5201a2012-02-24 16:08:54 -08002357
2358 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002359 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002360 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002361 active_chg_plugged_in
2362 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002363 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002364 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2365 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002366
2367 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002368 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002369 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002370 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002371
2372 msleep(20);
2373
David Keitel6ccbf132012-05-30 14:21:24 -07002374 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002375 } else {
David Keitel712782e2012-03-29 14:11:47 -07002376 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002377 }
2378 }
David Keitel6ccbf132012-05-30 14:21:24 -07002379 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2380 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2381 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002382 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002383}
David Keitelacf57c82012-03-07 18:48:50 -08002384
2385static int find_usb_ma_value(int value)
2386{
2387 int i;
2388
2389 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2390 if (value >= usb_ma_table[i].usb_ma)
2391 break;
2392 }
2393
2394 return i;
2395}
2396
2397static void decrease_usb_ma_value(int *value)
2398{
2399 int i;
2400
2401 if (value) {
2402 i = find_usb_ma_value(*value);
2403 if (i > 0)
2404 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002405 while (!the_chip->iusb_fine_res && i > 0
2406 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2407 i--;
David Keitelacf57c82012-03-07 18:48:50 -08002408 *value = usb_ma_table[i].usb_ma;
2409 }
2410}
2411
2412static void increase_usb_ma_value(int *value)
2413{
2414 int i;
2415
2416 if (value) {
2417 i = find_usb_ma_value(*value);
2418
2419 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2420 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002421 /* Get next correct entry if IUSB_FINE_RES is not available */
2422 while (!the_chip->iusb_fine_res
2423 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2424 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2425 i++;
2426
David Keitelacf57c82012-03-07 18:48:50 -08002427 *value = usb_ma_table[i].usb_ma;
2428 }
2429}
2430
2431static void vin_collapse_check_worker(struct work_struct *work)
2432{
2433 struct delayed_work *dwork = to_delayed_work(work);
2434 struct pm8921_chg_chip *chip = container_of(dwork,
2435 struct pm8921_chg_chip, vin_collapse_check_work);
2436
2437 /* AICL only for wall-chargers */
2438 if (is_usb_chg_plugged_in(chip) &&
2439 usb_target_ma > USB_WALL_THRESHOLD_MA) {
2440 /* decrease usb_target_ma */
2441 decrease_usb_ma_value(&usb_target_ma);
2442 /* reset here, increase in unplug_check_worker */
2443 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2444 pr_debug("usb_now=%d, usb_target = %d\n",
2445 USB_WALL_THRESHOLD_MA, usb_target_ma);
2446 } else {
2447 handle_usb_insertion_removal(chip);
2448 }
2449}
2450
2451#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2453{
David Keitelacf57c82012-03-07 18:48:50 -08002454 if (usb_target_ma)
2455 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2456 round_jiffies_relative(msecs_to_jiffies
2457 (VIN_MIN_COLLAPSE_CHECK_MS)));
2458 else
2459 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 return IRQ_HANDLED;
2461}
2462
2463static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
2464{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002465 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 return IRQ_HANDLED;
2467}
2468
2469static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2470{
2471 struct pm8921_chg_chip *chip = data;
2472 int status;
2473
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002474 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2475 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002476 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 pr_debug("battery present=%d", status);
2478 power_supply_changed(&chip->batt_psy);
2479 return IRQ_HANDLED;
2480}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002481
2482/*
2483 * this interrupt used to restart charging a battery.
2484 *
2485 * Note: When DC-inserted the VBAT can't go low.
2486 * VPH_PWR is provided by the ext-charger.
2487 * After End-Of-Charging from DC, charging can be resumed only
2488 * if DC is removed and then inserted after the battery was in use.
2489 * Therefore the handle_start_ext_chg() is not called.
2490 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2492{
2493 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002494 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002496 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002497
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002498 if (high_transition) {
2499 /* enable auto charging */
2500 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002501 pr_info("batt fell below resume voltage %s\n",
2502 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002503 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002504 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 power_supply_changed(&chip->batt_psy);
2507 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002508 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510 return IRQ_HANDLED;
2511}
2512
2513static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2514{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002515 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002516 return IRQ_HANDLED;
2517}
2518
2519static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2520{
2521 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2522 return IRQ_HANDLED;
2523}
2524
2525static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2526{
2527 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2528 return IRQ_HANDLED;
2529}
2530
2531static irqreturn_t vcp_irq_handler(int irq, void *data)
2532{
David Keitel8c5201a2012-02-24 16:08:54 -08002533 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 return IRQ_HANDLED;
2535}
2536
2537static irqreturn_t atcdone_irq_handler(int irq, void *data)
2538{
2539 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2540 return IRQ_HANDLED;
2541}
2542
2543static irqreturn_t atcfail_irq_handler(int irq, void *data)
2544{
2545 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2546 return IRQ_HANDLED;
2547}
2548
2549static irqreturn_t chgdone_irq_handler(int irq, void *data)
2550{
2551 struct pm8921_chg_chip *chip = data;
2552
2553 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002554
2555 handle_stop_ext_chg(chip);
2556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557 power_supply_changed(&chip->batt_psy);
2558 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002559 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002560
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002561 bms_notify_check(chip);
2562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 return IRQ_HANDLED;
2564}
2565
2566static irqreturn_t chgfail_irq_handler(int irq, void *data)
2567{
2568 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002569 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570
David Keitel753ec8d2011-11-02 10:56:37 -07002571 ret = pm_chg_failed_clear(chip, 1);
2572 if (ret)
2573 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2574
2575 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2576 get_prop_batt_present(chip),
2577 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2578 pm_chg_get_fsm_state(data));
2579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580 power_supply_changed(&chip->batt_psy);
2581 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002582 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 return IRQ_HANDLED;
2584}
2585
2586static irqreturn_t chgstate_irq_handler(int irq, void *data)
2587{
2588 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589
2590 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2591 power_supply_changed(&chip->batt_psy);
2592 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002593 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002594
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002595 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002597 return IRQ_HANDLED;
2598}
2599
David Keitel8c5201a2012-02-24 16:08:54 -08002600static int param_vin_disable_counter = 5;
2601module_param(param_vin_disable_counter, int, 0644);
2602
2603static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2604 int count, int usb_ma)
2605{
David Keitel6ccbf132012-05-30 14:21:24 -07002606 if (usb_ma)
2607 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002608 pr_debug("count = %d iusb=500mA\n", count);
2609 disable_input_voltage_regulation(chip);
2610 pr_debug("count = %d disable_input_regulation\n", count);
2611
2612 msleep(20);
2613
2614 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2615 count,
2616 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2617 is_usb_chg_plugged_in(chip));
2618 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2619 count, usb_ma);
2620 enable_input_voltage_regulation(chip);
David Keitel6ccbf132012-05-30 14:21:24 -07002621 if (usb_ma)
2622 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002623}
2624
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002625#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002626#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2627#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002628static void unplug_check_worker(struct work_struct *work)
2629{
2630 struct delayed_work *dwork = to_delayed_work(work);
2631 struct pm8921_chg_chip *chip = container_of(dwork,
2632 struct pm8921_chg_chip, unplug_check_work);
David Keitel6ccbf132012-05-30 14:21:24 -07002633 u8 reg_loop, active_path;
2634 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002635 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002636
David Keitelacf57c82012-03-07 18:48:50 -08002637 reg_loop = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002638
2639 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2640 if (rc) {
Devin Kim81265542012-09-01 05:06:22 -07002641 pr_warn("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2642 //return;
David Keitel6ccbf132012-05-30 14:21:24 -07002643 }
2644 chip->active_path = active_path;
Devin Kim81265542012-09-01 05:06:22 -07002645 if (the_chip->usb_present) {
roy.park84cf5a32012-08-17 17:45:58 -07002646 active_path = USB_ACTIVE_BIT;
Devin Kim81265542012-09-01 05:06:22 -07002647 active_chg_plugged_in = the_chip->usb_present;
roy.park84cf5a32012-08-17 17:45:58 -07002648 } else {
2649 active_chg_plugged_in = is_active_chg_plugged_in(chip,
2650 active_path);
2651 }
David Keitel6ccbf132012-05-30 14:21:24 -07002652 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2653 active_path, active_chg_plugged_in);
2654 if (active_path & USB_ACTIVE_BIT) {
2655 pr_debug("USB charger active\n");
2656
2657 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim81265542012-09-01 05:06:22 -07002658 if (!usb_target_ma) {
2659 if (usb_ma > 500) {
2660 usb_ma = 500;
2661 __pm8921_charger_vbus_draw(usb_ma);
2662 pr_info("usb_now=%d, usb_target = %d\n",
2663 usb_ma, 500);
Devin Kim2073afb2012-09-05 13:01:51 -07002664 goto check_again_later;
2665 } else if (usb_ma == 500) {
2666 pr_info("Stopping Unplug Check Worker"
2667 " USB == 500mA\n");
2668 disable_input_voltage_regulation(chip);
2669 return;
2670 }
2671
2672 if (usb_ma <= 100) {
2673 pr_debug(
2674 "Unenumerated or suspended usb_ma = %d"
2675 " skip\n", usb_ma);
2676 goto check_again_later;
Devin Kim81265542012-09-01 05:06:22 -07002677 }
David Keitel6ccbf132012-05-30 14:21:24 -07002678 }
2679 } else if (active_path & DC_ACTIVE_BIT) {
2680 pr_debug("DC charger active\n");
David Keitel5bed4f12012-05-25 18:04:14 -07002681 /* Some board designs are not prone to reverse boost on DC
2682 * charging path */
2683 if (!chip->dc_unplug_check)
Devin Kim2073afb2012-09-05 13:01:51 -07002684 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002685 } else {
2686 /* No charger active */
2687 if (!(is_usb_chg_plugged_in(chip)
2688 && !(is_dc_chg_plugged_in(chip)))) {
Devin Kim81265542012-09-01 05:06:22 -07002689 pr_info(
David Keitel6ccbf132012-05-30 14:21:24 -07002690 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2691 pm_chg_get_regulation_loop(chip),
2692 pm_chg_get_fsm_state(chip),
2693 get_prop_batt_current(chip)
2694 );
2695 }
Devin Kim2073afb2012-09-05 13:01:51 -07002696 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002697 }
David Keitel8c5201a2012-02-24 16:08:54 -08002698
David Keitel6ccbf132012-05-30 14:21:24 -07002699 if (active_path & USB_ACTIVE_BIT) {
2700 reg_loop = pm_chg_get_regulation_loop(chip);
2701 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2702 if ((reg_loop & VIN_ACTIVE_BIT) &&
2703 (usb_ma > USB_WALL_THRESHOLD_MA)) {
2704 decrease_usb_ma_value(&usb_ma);
2705 usb_target_ma = usb_ma;
2706 /* end AICL here */
2707 __pm8921_charger_vbus_draw(usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002708 pr_info("VIN: usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002709 usb_ma, usb_target_ma);
2710 }
David Keitelacf57c82012-03-07 18:48:50 -08002711 }
2712
2713 reg_loop = pm_chg_get_regulation_loop(chip);
2714 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2715
David Keitel6ccbf132012-05-30 14:21:24 -07002716 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002717 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002718
2719 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2720 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2721 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002722 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002723
David Keitel8c5201a2012-02-24 16:08:54 -08002724 while (count++ < param_vin_disable_counter
David Keitel6ccbf132012-05-30 14:21:24 -07002725 && active_chg_plugged_in == 1) {
2726 if (active_path & USB_ACTIVE_BIT)
2727 attempt_reverse_boost_fix(chip,
2728 count, usb_ma);
2729 else
2730 attempt_reverse_boost_fix(chip,
2731 count, 0);
2732 /* after reverse boost fix check if the active
2733 * charger was detected as removed */
2734 active_chg_plugged_in
2735 = is_active_chg_plugged_in(chip,
2736 active_path);
2737 pr_debug("active_chg_plugged_in = %d\n",
2738 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002739 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002740 }
2741 }
roy.park84cf5a32012-08-17 17:45:58 -07002742 if(the_chip->usb_present) {
2743 active_path = USB_ACTIVE_BIT;
2744 active_chg_plugged_in =the_chip->usb_present;
2745 } else {
2746 active_chg_plugged_in = is_active_chg_plugged_in(chip,
2747 active_path);
2748 }
David Keitel6ccbf132012-05-30 14:21:24 -07002749 pr_debug("active_path = 0x%x, active_chg = %d\n",
2750 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002751 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2752
David Keitel6ccbf132012-05-30 14:21:24 -07002753 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2754 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2755 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002756 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002757 }
2758
David Keitel6ccbf132012-05-30 14:21:24 -07002759 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)) {
David Keitelacf57c82012-03-07 18:48:50 -08002760 /* only increase iusb_max if vin loop not active */
2761 if (usb_ma < usb_target_ma) {
2762 increase_usb_ma_value(&usb_ma);
2763 __pm8921_charger_vbus_draw(usb_ma);
Devin Kim81265542012-09-01 05:06:22 -07002764 pr_info("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002765 usb_ma, usb_target_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002766 } else {
2767 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002768 }
2769 }
Devin Kim81265542012-09-01 05:06:22 -07002770
Devin Kim2073afb2012-09-05 13:01:51 -07002771check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002772 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002773 schedule_delayed_work(&chip->unplug_check_work,
2774 round_jiffies_relative(msecs_to_jiffies
2775 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2776}
2777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778static irqreturn_t loop_change_irq_handler(int irq, void *data)
2779{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002780 struct pm8921_chg_chip *chip = data;
2781
2782 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2783 pm_chg_get_fsm_state(data),
2784 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002785 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 return IRQ_HANDLED;
2787}
2788
2789static irqreturn_t fastchg_irq_handler(int irq, void *data)
2790{
2791 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002792 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002794 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2795 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2796 wake_lock(&chip->eoc_wake_lock);
2797 schedule_delayed_work(&chip->eoc_work,
2798 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002799 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002800 }
2801 power_supply_changed(&chip->batt_psy);
2802 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 return IRQ_HANDLED;
2804}
2805
2806static irqreturn_t trklchg_irq_handler(int irq, void *data)
2807{
2808 struct pm8921_chg_chip *chip = data;
2809
2810 power_supply_changed(&chip->batt_psy);
2811 return IRQ_HANDLED;
2812}
2813
2814static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2815{
2816 struct pm8921_chg_chip *chip = data;
2817 int status;
2818
2819 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2820 pr_debug("battery present=%d state=%d", !status,
2821 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002822 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 power_supply_changed(&chip->batt_psy);
2824 return IRQ_HANDLED;
2825}
2826
2827static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2828{
2829 struct pm8921_chg_chip *chip = data;
2830
Amir Samuelovd31ef502011-10-26 14:41:36 +02002831 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 power_supply_changed(&chip->batt_psy);
2833 return IRQ_HANDLED;
2834}
2835
2836static irqreturn_t chghot_irq_handler(int irq, void *data)
2837{
2838 struct pm8921_chg_chip *chip = data;
2839
2840 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2841 power_supply_changed(&chip->batt_psy);
2842 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002843 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 return IRQ_HANDLED;
2845}
2846
2847static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2848{
2849 struct pm8921_chg_chip *chip = data;
2850
2851 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002852 handle_stop_ext_chg(chip);
2853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 power_supply_changed(&chip->batt_psy);
2855 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856 return IRQ_HANDLED;
2857}
2858
Devin Kim69f17302012-09-12 20:30:28 -07002859static void unplug_usbcheck_work(struct work_struct *work)
2860{
2861 int usb_vin;
2862 struct pm8xxx_adc_chan_result vchg;
2863 struct delayed_work *dwork = to_delayed_work(work);
2864 struct pm8921_chg_chip *chip = container_of(dwork,
2865 struct pm8921_chg_chip, unplug_usbcheck_work);
2866
2867 pm8xxx_adc_read(CHANNEL_USBIN, &vchg);
2868 usb_vin = vchg.physical;
2869 pr_info("usb_vin : %d, max_voltage_mv=%d\n", usb_vin, chip->max_voltage_mv);
2870
2871 if (usb_vin/1000 <= chip->max_voltage_mv) {
2872 unplug_ovp_fet_open(chip);
2873 }
2874 pr_debug(" Notify USB update here \n");
2875 power_supply_changed(&chip->batt_psy);
2876 power_supply_changed(&chip->usb_psy);
2877 power_supply_changed(&chip->dc_psy);
2878}
2879
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002880static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2881{
2882 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002883 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002884
2885 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2886 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2887
Devin Kim69f17302012-09-12 20:30:28 -07002888 pr_info("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2889 pr_info("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2890
2891 if (chg_gone && usb_chg_plugged_in) {
2892 pr_info("schedule to check again here\n");
2893 /* schedule to check again later */
2894 schedule_delayed_work(&chip->unplug_usbcheck_work,
2895 round_jiffies_relative(msecs_to_jiffies
2896 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2897 }
David Keitel0873d0f2012-03-29 11:44:49 -07002898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 power_supply_changed(&chip->batt_psy);
2900 power_supply_changed(&chip->usb_psy);
roy.parkd4b1fb52012-08-02 18:11:46 -07002901 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 return IRQ_HANDLED;
2903}
David Keitel52fda532011-11-10 10:43:44 -08002904/*
2905 *
2906 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2907 * fire for two cases:
2908 *
2909 * If the interrupt line switches to high temperature is okay
2910 * and thus charging begins.
2911 * If bat_temp_ok is low this means the temperature is now
2912 * too hot or cold, so charging is stopped.
2913 *
2914 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002915static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2916{
David Keitel52fda532011-11-10 10:43:44 -08002917 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002918 struct pm8921_chg_chip *chip = data;
2919
David Keitel52fda532011-11-10 10:43:44 -08002920 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2921
2922 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2923 bat_temp_ok, pm_chg_get_fsm_state(data));
2924
2925 if (bat_temp_ok)
2926 handle_start_ext_chg(chip);
2927 else
2928 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930 power_supply_changed(&chip->batt_psy);
2931 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002932 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933 return IRQ_HANDLED;
2934}
2935
2936static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2937{
2938 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2939 return IRQ_HANDLED;
2940}
2941
2942static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2943{
2944 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2945 return IRQ_HANDLED;
2946}
2947
2948static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2949{
2950 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2951 return IRQ_HANDLED;
2952}
2953
2954static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2955{
2956 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2957 return IRQ_HANDLED;
2958}
2959
2960static irqreturn_t batfet_irq_handler(int irq, void *data)
2961{
2962 struct pm8921_chg_chip *chip = data;
2963
2964 pr_debug("vreg ov\n");
2965 power_supply_changed(&chip->batt_psy);
2966 return IRQ_HANDLED;
2967}
2968
2969static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2970{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002971 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002972 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002973
David Keitel88e1b572012-01-11 11:57:14 -08002974 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2975 if (chip->ext_psy)
2976 power_supply_set_online(chip->ext_psy, dc_present);
2977 chip->dc_present = dc_present;
2978 if (dc_present)
2979 handle_start_ext_chg(chip);
2980 else
2981 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982 return IRQ_HANDLED;
2983}
2984
2985static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2986{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002987 struct pm8921_chg_chip *chip = data;
2988
Amir Samuelovd31ef502011-10-26 14:41:36 +02002989 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990 return IRQ_HANDLED;
2991}
2992
2993static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2994{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002995 struct pm8921_chg_chip *chip = data;
2996
Amir Samuelovd31ef502011-10-26 14:41:36 +02002997 handle_stop_ext_chg(chip);
2998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999 return IRQ_HANDLED;
3000}
3001
David Keitel88e1b572012-01-11 11:57:14 -08003002static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3003{
3004 struct power_supply *psy = &the_chip->batt_psy;
3005 struct power_supply *epsy = dev_get_drvdata(dev);
3006 int i, dcin_irq;
3007
3008 /* Only search for external supply if none is registered */
3009 if (!the_chip->ext_psy) {
3010 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3011 for (i = 0; i < epsy->num_supplicants; i++) {
3012 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3013 if (!strncmp(epsy->name, "dc", 2)) {
3014 the_chip->ext_psy = epsy;
3015 dcin_valid_irq_handler(dcin_irq,
3016 the_chip);
3017 }
3018 }
3019 }
3020 }
3021 return 0;
3022}
3023
3024static void pm_batt_external_power_changed(struct power_supply *psy)
3025{
3026 /* Only look for an external supply if it hasn't been registered */
3027 if (!the_chip->ext_psy)
3028 class_for_each_device(power_supply_class, NULL, psy,
3029 __pm_batt_external_power_changed_work);
3030}
3031
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003032/**
3033 * update_heartbeat - internal function to update userspace
3034 * per update_time minutes
3035 *
3036 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003037#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003038static void update_heartbeat(struct work_struct *work)
3039{
3040 struct delayed_work *dwork = to_delayed_work(work);
3041 struct pm8921_chg_chip *chip = container_of(dwork,
3042 struct pm8921_chg_chip, update_heartbeat_work);
3043
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003044 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003045 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003046 if (chip->recent_reported_soc <= 20)
3047 schedule_delayed_work(&chip->update_heartbeat_work,
3048 round_jiffies_relative(msecs_to_jiffies
3049 (LOW_SOC_HEARTBEAT_MS)));
3050 else
3051 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003052 round_jiffies_relative(msecs_to_jiffies
3053 (chip->update_time)));
3054}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003055#define VDD_LOOP_ACTIVE_BIT BIT(3)
3056#define VDD_MAX_INCREASE_MV 400
3057static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3058module_param(vdd_max_increase_mv, int, 0644);
3059
3060static int ichg_threshold_ua = -400000;
3061module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003062
3063#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003064static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
3065{
3066 int ichg_meas_ua, vbat_uv;
3067 int ichg_meas_ma;
3068 int adj_vdd_max_mv, programmed_vdd_max;
3069 int vbat_batt_terminal_uv;
3070 int vbat_batt_terminal_mv;
3071 int reg_loop;
3072 int delta_mv = 0;
3073
3074 if (chip->rconn_mohm == 0) {
3075 pr_debug("Exiting as rconn_mohm is 0\n");
3076 return;
3077 }
3078 /* adjust vdd_max only in normal temperature zone */
3079 if (chip->is_bat_cool || chip->is_bat_warm) {
3080 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3081 chip->is_bat_cool, chip->is_bat_warm);
3082 return;
3083 }
3084
3085 reg_loop = pm_chg_get_regulation_loop(chip);
3086 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3087 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3088 reg_loop);
3089 return;
3090 }
3091
3092 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
3093 &vbat_uv);
3094 if (ichg_meas_ua >= 0) {
3095 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
3096 return;
3097 }
3098 if (ichg_meas_ua <= ichg_threshold_ua) {
3099 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
3100 ichg_meas_ua, ichg_threshold_ua);
3101 return;
3102 }
3103 ichg_meas_ma = ichg_meas_ua / 1000;
3104
3105 /* rconn_mohm is in milliOhms */
3106 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
3107 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3108 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3109
3110 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3111
3112 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3113 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3114 delta_mv,
3115 programmed_vdd_max,
3116 adj_vdd_max_mv);
3117
3118 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3119 pr_debug("adj vdd_max lower than default max voltage\n");
3120 return;
3121 }
3122
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003123 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3124 * PM8921_CHG_VDDMAX_RES_MV;
3125
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003126 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3127 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003128 pr_debug("adjusting vdd_max_mv to %d to make "
3129 "vbat_batt_termial_uv = %d to %d\n",
3130 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3131 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3132}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003133
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003134enum {
3135 CHG_IN_PROGRESS,
3136 CHG_NOT_IN_PROGRESS,
3137 CHG_FINISHED,
3138};
3139
3140#define VBAT_TOLERANCE_MV 70
3141#define CHG_DISABLE_MSLEEP 100
3142static int is_charging_finished(struct pm8921_chg_chip *chip)
3143{
3144 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
3145 int ichg_meas_ma, iterm_programmed;
3146 int regulation_loop, fast_chg, vcp;
3147 int rc;
3148 static int last_vbat_programmed = -EINVAL;
3149
3150 if (!is_ext_charging(chip)) {
3151 /* return if the battery is not being fastcharged */
3152 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3153 pr_debug("fast_chg = %d\n", fast_chg);
3154 if (fast_chg == 0)
3155 return CHG_NOT_IN_PROGRESS;
3156
3157 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3158 pr_debug("vcp = %d\n", vcp);
3159 if (vcp == 1)
3160 return CHG_IN_PROGRESS;
3161
3162 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
3163 pr_debug("vbatdet_low = %d\n", vbatdet_low);
3164 if (vbatdet_low == 1)
3165 return CHG_IN_PROGRESS;
3166
3167 /* reset count if battery is hot/cold */
3168 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3169 pr_debug("batt_temp_ok = %d\n", rc);
3170 if (rc == 0)
3171 return CHG_IN_PROGRESS;
3172
3173 /* reset count if battery voltage is less than vddmax */
3174 vbat_meas_uv = get_prop_battery_uvolts(chip);
3175 if (vbat_meas_uv < 0)
3176 return CHG_IN_PROGRESS;
3177 vbat_meas_mv = vbat_meas_uv / 1000;
3178
3179 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3180 if (rc) {
3181 pr_err("couldnt read vddmax rc = %d\n", rc);
3182 return CHG_IN_PROGRESS;
3183 }
3184 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
3185 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003186
3187 if (last_vbat_programmed == -EINVAL)
3188 last_vbat_programmed = vbat_programmed;
3189 if (last_vbat_programmed != vbat_programmed) {
3190 /* vddmax changed, reset and check again */
3191 pr_debug("vddmax = %d last_vdd_max=%d\n",
3192 vbat_programmed, last_vbat_programmed);
3193 last_vbat_programmed = vbat_programmed;
3194 return CHG_IN_PROGRESS;
3195 }
3196
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003197 regulation_loop = pm_chg_get_regulation_loop(chip);
3198 if (regulation_loop < 0) {
3199 pr_err("couldnt read the regulation loop err=%d\n",
3200 regulation_loop);
3201 return CHG_IN_PROGRESS;
3202 }
3203 pr_debug("regulation_loop=%d\n", regulation_loop);
3204
3205 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3206 return CHG_IN_PROGRESS;
3207 } /* !is_ext_charging */
3208
3209 /* reset count if battery chg current is more than iterm */
3210 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3211 if (rc) {
3212 pr_err("couldnt read iterm rc = %d\n", rc);
3213 return CHG_IN_PROGRESS;
3214 }
3215
3216 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
3217 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3218 iterm_programmed, ichg_meas_ma);
3219 /*
3220 * ichg_meas_ma < 0 means battery is drawing current
3221 * ichg_meas_ma > 0 means battery is providing current
3222 */
3223 if (ichg_meas_ma > 0)
3224 return CHG_IN_PROGRESS;
3225
3226 if (ichg_meas_ma * -1 > iterm_programmed)
3227 return CHG_IN_PROGRESS;
3228
3229 return CHG_FINISHED;
3230}
3231
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003232/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003233 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003234 * has happened
3235 *
3236 * If all conditions favouring, if the charge current is
3237 * less than the term current for three consecutive times
3238 * an EOC has happened.
3239 * The wakelock is released if there is no need to reshedule
3240 * - this happens when the battery is removed or EOC has
3241 * happened
3242 */
3243#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003244static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003245{
3246 struct delayed_work *dwork = to_delayed_work(work);
3247 struct pm8921_chg_chip *chip = container_of(dwork,
3248 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003249 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003250 int end;
3251
3252 pm_chg_failed_clear(chip, 1);
3253 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003254
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003255 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003256 count = 0;
3257 wake_unlock(&chip->eoc_wake_lock);
3258 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003259 }
3260
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003261 /* If the disable hw clock switching
3262 * flag was set it can now be unset. Also, re-enable
3263 * the battery alarm to set the flag again when needed
3264 */
3265 if (chip->disable_hw_clock_switching) {
3266 /* Unset the hw clock switching flag */
3267 chip->disable_hw_clock_switching = 0;
3268
3269 if (pm8921_charger_enable_batt_alarm(chip))
3270 pr_err("couldn't set up batt alarm!\n");
3271 }
3272
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003273 if (end == CHG_FINISHED) {
3274 count++;
3275 } else {
3276 count = 0;
3277 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003278
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003279 if (count == CONSECUTIVE_COUNT) {
3280 count = 0;
3281 pr_info("End of Charging\n");
3282
3283 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003284
Amir Samuelovd31ef502011-10-26 14:41:36 +02003285 if (is_ext_charging(chip))
3286 chip->ext_charge_done = true;
3287
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003288 if (chip->is_bat_warm || chip->is_bat_cool)
3289 chip->bms_notify.is_battery_full = 0;
3290 else
3291 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003292 /* declare end of charging by invoking chgdone interrupt */
3293 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
3294 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003295 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003296 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003297 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003298 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003299 round_jiffies_relative(msecs_to_jiffies
3300 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003301 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003302}
3303
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003304static void btm_configure_work(struct work_struct *work)
3305{
3306 int rc;
3307
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003308 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003309 if (rc)
3310 pr_err("failed to configure btm rc=%d", rc);
3311}
3312
3313DECLARE_WORK(btm_config_work, btm_configure_work);
3314
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003315static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3316{
3317 unsigned int chg_current = chip->max_bat_chg_current;
3318
3319 if (chip->is_bat_cool)
3320 chg_current = min(chg_current, chip->cool_bat_chg_current);
3321
3322 if (chip->is_bat_warm)
3323 chg_current = min(chg_current, chip->warm_bat_chg_current);
3324
choongryeol.lee45ccbb52012-08-25 00:15:42 -07003325 if (chip->ext_warm_i_limit && chip->ext_batt_temp_monitor)
3326 chg_current = min(chg_current, chip->ext_warm_i_limit);
3327
David Keitelfdef3a42011-12-14 19:02:54 -08003328 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003329 chg_current = min(chg_current,
3330 chip->thermal_mitigation[thermal_mitigation]);
3331
3332 pm_chg_ibatmax_set(the_chip, chg_current);
3333}
3334
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003335#define TEMP_HYSTERISIS_DEGC 2
3336static void battery_cool(bool enter)
3337{
3338 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003339 if (enter == the_chip->is_bat_cool)
3340 return;
3341 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003342 if (enter) {
3343 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003344 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003345 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003346 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003347 pm_chg_vbatdet_set(the_chip,
3348 the_chip->cool_bat_voltage
3349 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003350 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003351 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003352 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003353 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003354 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003355 the_chip->max_voltage_mv
3356 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003357 }
3358 schedule_work(&btm_config_work);
3359}
3360
3361static void battery_warm(bool enter)
3362{
3363 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003364 if (enter == the_chip->is_bat_warm)
3365 return;
3366 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003367 if (enter) {
3368 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003369 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003370 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003371 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003372 pm_chg_vbatdet_set(the_chip,
3373 the_chip->warm_bat_voltage
3374 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003375 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003376 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003377 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003378 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003379 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003380 the_chip->max_voltage_mv
3381 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003382 }
3383 schedule_work(&btm_config_work);
3384}
3385
3386static int configure_btm(struct pm8921_chg_chip *chip)
3387{
3388 int rc;
3389
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003390 if (chip->warm_temp_dc != INT_MIN)
3391 btm_config.btm_warm_fn = battery_warm;
3392 else
3393 btm_config.btm_warm_fn = NULL;
3394
3395 if (chip->cool_temp_dc != INT_MIN)
3396 btm_config.btm_cool_fn = battery_cool;
3397 else
3398 btm_config.btm_cool_fn = NULL;
3399
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003400 btm_config.low_thr_temp = chip->cool_temp_dc;
3401 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003402 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003403 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003404 if (rc)
3405 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07003406 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003407 if (rc)
3408 pr_err("failed to start btm rc = %d\n", rc);
3409
3410 return rc;
3411}
3412
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003413/**
3414 * set_disable_status_param -
3415 *
3416 * Internal function to disable battery charging and also disable drawing
3417 * any current from the source. The device is forced to run on a battery
3418 * after this.
3419 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003420static int set_disable_status_param(const char *val, struct kernel_param *kp)
3421{
3422 int ret;
3423 struct pm8921_chg_chip *chip = the_chip;
3424
3425 ret = param_set_int(val, kp);
3426 if (ret) {
3427 pr_err("error setting value %d\n", ret);
3428 return ret;
3429 }
3430 pr_info("factory set disable param to %d\n", charging_disabled);
3431 if (chip) {
3432 pm_chg_auto_enable(chip, !charging_disabled);
3433 pm_chg_charge_dis(chip, charging_disabled);
3434 }
3435 return 0;
3436}
3437module_param_call(disabled, set_disable_status_param, param_get_uint,
3438 &charging_disabled, 0644);
3439
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003440static int rconn_mohm;
3441static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3442{
3443 int ret;
3444 struct pm8921_chg_chip *chip = the_chip;
3445
3446 ret = param_set_int(val, kp);
3447 if (ret) {
3448 pr_err("error setting value %d\n", ret);
3449 return ret;
3450 }
3451 if (chip)
3452 chip->rconn_mohm = rconn_mohm;
3453 return 0;
3454}
3455module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3456 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003457/**
3458 * set_thermal_mitigation_level -
3459 *
3460 * Internal function to control battery charging current to reduce
3461 * temperature
3462 */
3463static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3464{
3465 int ret;
3466 struct pm8921_chg_chip *chip = the_chip;
3467
3468 ret = param_set_int(val, kp);
3469 if (ret) {
3470 pr_err("error setting value %d\n", ret);
3471 return ret;
3472 }
3473
3474 if (!chip) {
3475 pr_err("called before init\n");
3476 return -EINVAL;
3477 }
3478
3479 if (!chip->thermal_mitigation) {
3480 pr_err("no thermal mitigation\n");
3481 return -EINVAL;
3482 }
3483
3484 if (thermal_mitigation < 0
3485 || thermal_mitigation >= chip->thermal_levels) {
3486 pr_err("out of bound level selected\n");
3487 return -EINVAL;
3488 }
3489
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003490 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003491 return ret;
3492}
3493module_param_call(thermal_mitigation, set_therm_mitigation_level,
3494 param_get_uint,
3495 &thermal_mitigation, 0644);
3496
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003497static int set_usb_max_current(const char *val, struct kernel_param *kp)
3498{
3499 int ret, mA;
3500 struct pm8921_chg_chip *chip = the_chip;
3501
3502 ret = param_set_int(val, kp);
3503 if (ret) {
3504 pr_err("error setting value %d\n", ret);
3505 return ret;
3506 }
3507 if (chip) {
3508 pr_warn("setting current max to %d\n", usb_max_current);
3509 pm_chg_iusbmax_get(chip, &mA);
3510 if (mA > usb_max_current)
3511 pm8921_charger_vbus_draw(usb_max_current);
3512 return 0;
3513 }
3514 return -EINVAL;
3515}
David Keitelacf57c82012-03-07 18:48:50 -08003516module_param_call(usb_max_current, set_usb_max_current,
3517 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519static void free_irqs(struct pm8921_chg_chip *chip)
3520{
3521 int i;
3522
3523 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3524 if (chip->pmic_chg_irq[i]) {
3525 free_irq(chip->pmic_chg_irq[i], chip);
3526 chip->pmic_chg_irq[i] = 0;
3527 }
3528}
3529
David Keitel88e1b572012-01-11 11:57:14 -08003530/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3532{
3533 unsigned long flags;
3534 int fsm_state;
3535
3536 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3537 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3538
3539 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003540 if (chip->usb_present) {
3541 schedule_delayed_work(&chip->unplug_check_work,
3542 round_jiffies_relative(msecs_to_jiffies
3543 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08003544 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003545 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003546
3547 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3548 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3549 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003550 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
3551 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
3552 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
3553 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3554 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003555 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003556 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3557 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Devin Kim32599592012-08-22 11:40:44 -07003558
3559 if (!chip->ext_batt_temp_monitor)
3560 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003561
3562 spin_lock_irqsave(&vbus_lock, flags);
3563 if (usb_chg_current) {
3564 /* reissue a vbus draw call */
3565 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003566 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567 }
3568 spin_unlock_irqrestore(&vbus_lock, flags);
3569
3570 fsm_state = pm_chg_get_fsm_state(chip);
3571 if (is_battery_charging(fsm_state)) {
3572 chip->bms_notify.is_charging = 1;
3573 pm8921_bms_charging_began();
3574 }
3575
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003576 check_battery_valid(chip);
3577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003578 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3579 chip->usb_present,
3580 chip->dc_present,
3581 get_prop_batt_present(chip),
3582 fsm_state);
3583}
3584
3585struct pm_chg_irq_init_data {
3586 unsigned int irq_id;
3587 char *name;
3588 unsigned long flags;
3589 irqreturn_t (*handler)(int, void *);
3590};
3591
3592#define CHG_IRQ(_id, _flags, _handler) \
3593{ \
3594 .irq_id = _id, \
3595 .name = #_id, \
3596 .flags = _flags, \
3597 .handler = _handler, \
3598}
3599struct pm_chg_irq_init_data chg_irq_data[] = {
3600 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3601 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003602 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3604 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003605 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3606 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3608 usbin_uv_irq_handler),
3609 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3610 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3611 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3612 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3613 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3614 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3615 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3616 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3617 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003618 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3619 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3621 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3622 batt_removed_irq_handler),
3623 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3624 batttemp_hot_irq_handler),
3625 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3626 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3627 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003628 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3629 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003630 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3631 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3633 coarse_det_low_irq_handler),
3634 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3635 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3636 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3637 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3638 batfet_irq_handler),
3639 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3640 dcin_valid_irq_handler),
3641 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3642 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003643 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644};
3645
3646static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3647 struct platform_device *pdev)
3648{
3649 struct resource *res;
3650 int ret, i;
3651
3652 ret = 0;
3653 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3654
3655 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3656 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3657 chg_irq_data[i].name);
3658 if (res == NULL) {
3659 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3660 goto err_out;
3661 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003662 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 ret = request_irq(res->start, chg_irq_data[i].handler,
3664 chg_irq_data[i].flags,
3665 chg_irq_data[i].name, chip);
3666 if (ret < 0) {
3667 pr_err("couldn't request %d (%s) %d\n", res->start,
3668 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003669 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003670 goto err_out;
3671 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003672 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3673 }
3674 return 0;
3675
3676err_out:
3677 free_irqs(chip);
3678 return -EINVAL;
3679}
3680
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003681static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3682{
3683 int err;
3684 u8 temp;
3685
3686 temp = 0xD1;
3687 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3688 if (err) {
3689 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3690 return;
3691 }
3692
3693 temp = 0xD3;
3694 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3695 if (err) {
3696 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3697 return;
3698 }
3699
3700 temp = 0xD1;
3701 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3702 if (err) {
3703 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3704 return;
3705 }
3706
3707 temp = 0xD5;
3708 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3709 if (err) {
3710 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3711 return;
3712 }
3713
3714 udelay(183);
3715
3716 temp = 0xD1;
3717 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3718 if (err) {
3719 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3720 return;
3721 }
3722
3723 temp = 0xD0;
3724 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3725 if (err) {
3726 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3727 return;
3728 }
3729 udelay(32);
3730
3731 temp = 0xD1;
3732 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3733 if (err) {
3734 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3735 return;
3736 }
3737
3738 temp = 0xD3;
3739 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3740 if (err) {
3741 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3742 return;
3743 }
3744}
3745
3746static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3747{
3748 int err;
3749 u8 temp;
3750
3751 temp = 0xD1;
3752 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3753 if (err) {
3754 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3755 return;
3756 }
3757
3758 temp = 0xD0;
3759 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3760 if (err) {
3761 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3762 return;
3763 }
3764}
3765
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003766#define VREF_BATT_THERM_FORCE_ON BIT(7)
3767static void detect_battery_removal(struct pm8921_chg_chip *chip)
3768{
3769 u8 temp;
3770
3771 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3772 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3773
3774 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3775 /*
3776 * batt therm force on bit is battery backed and is default 0
3777 * The charger sets this bit at init time. If this bit is found
3778 * 0 that means the battery was removed. Tell the bms about it
3779 */
3780 pm8921_bms_invalidate_shutdown_soc();
3781}
3782
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003783#define ENUM_TIMER_STOP_BIT BIT(1)
3784#define BOOT_DONE_BIT BIT(6)
David Keitelb157ff72012-06-14 11:22:30 -07003785#define BOOT_TIMER_EN_BIT BIT(1)
3786#define BOOT_DONE_MASK (BOOT_DONE_BIT | BOOT_TIMER_EN_BIT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787#define CHG_BATFET_ON_BIT BIT(3)
3788#define CHG_VCP_EN BIT(0)
3789#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3790#define SAFE_CURRENT_MA 1500
3791static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3792{
3793 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003794 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07003796 /* forcing 19p2mhz before accessing any charger registers */
3797 pm8921_chg_force_19p2mhz_clk(chip);
3798
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003799 detect_battery_removal(chip);
3800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
David Keitelb157ff72012-06-14 11:22:30 -07003802 BOOT_DONE_MASK, BOOT_DONE_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003803 if (rc) {
3804 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3805 return rc;
3806 }
3807
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003808 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3809
3810 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3811 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3812
3813 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003815 if (rc) {
3816 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003817 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818 return rc;
3819 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003820 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003821 chip->max_voltage_mv
3822 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003823 if (rc) {
3824 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003825 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003826 return rc;
3827 }
3828
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003829 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830 if (rc) {
3831 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003832 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833 return rc;
3834 }
3835 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3836 if (rc) {
3837 pr_err("Failed to set max voltage to %d rc=%d\n",
3838 SAFE_CURRENT_MA, rc);
3839 return rc;
3840 }
3841
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003842 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003843 if (rc) {
3844 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3845 return rc;
3846 }
3847
3848 rc = pm_chg_iterm_set(chip, chip->term_current);
3849 if (rc) {
3850 pr_err("Failed to set term current to %d rc=%d\n",
3851 chip->term_current, rc);
3852 return rc;
3853 }
3854
3855 /* Disable the ENUM TIMER */
3856 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3857 ENUM_TIMER_STOP_BIT);
3858 if (rc) {
3859 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3860 return rc;
3861 }
3862
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003863 if (chip->safety_time != 0) {
3864 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3865 if (rc) {
3866 pr_err("Failed to set max time to %d minutes rc=%d\n",
3867 chip->safety_time, rc);
3868 return rc;
3869 }
3870 }
3871
3872 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003873 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003874 if (rc) {
3875 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3876 chip->safety_time, rc);
3877 return rc;
3878 }
3879 }
3880
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003881 if (chip->vin_min != 0) {
3882 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3883 if (rc) {
3884 pr_err("Failed to set vin min to %d mV rc=%d\n",
3885 chip->vin_min, rc);
3886 return rc;
3887 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003888 } else {
3889 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003890 }
3891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003892 rc = pm_chg_disable_wd(chip);
3893 if (rc) {
3894 pr_err("Failed to disable wd rc=%d\n", rc);
3895 return rc;
3896 }
3897
3898 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3899 CHG_BAT_TEMP_DIS_BIT, 0);
3900 if (rc) {
3901 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3902 return rc;
3903 }
3904 /* switch to a 3.2Mhz for the buck */
3905 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3906 if (rc) {
3907 pr_err("Failed to switch buck clk rc=%d\n", rc);
3908 return rc;
3909 }
3910
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003911 if (chip->trkl_voltage != 0) {
3912 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3913 if (rc) {
3914 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3915 chip->trkl_voltage, rc);
3916 return rc;
3917 }
3918 }
3919
3920 if (chip->weak_voltage != 0) {
3921 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3922 if (rc) {
3923 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3924 chip->weak_voltage, rc);
3925 return rc;
3926 }
3927 }
3928
3929 if (chip->trkl_current != 0) {
3930 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3931 if (rc) {
3932 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3933 chip->trkl_voltage, rc);
3934 return rc;
3935 }
3936 }
3937
3938 if (chip->weak_current != 0) {
3939 rc = pm_chg_iweak_set(chip, chip->weak_current);
3940 if (rc) {
3941 pr_err("Failed to set weak current to %dmA rc=%d\n",
3942 chip->weak_current, rc);
3943 return rc;
3944 }
3945 }
3946
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003947 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3948 if (rc) {
3949 pr_err("Failed to set cold config %d rc=%d\n",
3950 chip->cold_thr, rc);
3951 }
3952
3953 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3954 if (rc) {
3955 pr_err("Failed to set hot config %d rc=%d\n",
3956 chip->hot_thr, rc);
3957 }
3958
Jay Chokshid674a512012-03-15 14:06:04 -07003959 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3960 if (rc) {
3961 pr_err("Failed to set charger LED src config %d rc=%d\n",
3962 chip->led_src_config, rc);
3963 }
3964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003965 /* Workarounds for die 1.1 and 1.0 */
3966 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3967 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3969 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003970
3971 /* software workaround for correct battery_id detection */
3972 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3973 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3974 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3975 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3976 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3977 udelay(100);
3978 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 }
3980
David Keitelb51995e2011-11-18 17:03:31 -08003981 /* Workarounds for die 3.0 */
3982 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3983 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3984
David Keitel38bdd4f2012-04-19 15:39:13 -07003985 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel0789fc62012-06-07 17:43:27 -07003986 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
David Keitel38bdd4f2012-04-19 15:39:13 -07003987 chip->iusb_fine_res = true;
David Keitel0789fc62012-06-07 17:43:27 -07003988 if (chip->uvd_voltage_mv)
3989 rc = pm_chg_uvd_threshold_set(chip,
3990 chip->uvd_voltage_mv);
3991 if (rc) {
3992 pr_err("Failed to set UVD threshold %drc=%d\n",
3993 chip->uvd_voltage_mv, rc);
3994 return rc;
3995 }
3996 }
David Keitel38bdd4f2012-04-19 15:39:13 -07003997
David Keitelb51995e2011-11-18 17:03:31 -08003998 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3999
David Keitela3c0d822011-11-03 14:18:52 -07004000 /* Disable EOC FSM processing */
4001 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
4002
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004003 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4004 VREF_BATT_THERM_FORCE_ON);
4005 if (rc)
4006 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 rc = pm_chg_charge_dis(chip, charging_disabled);
4009 if (rc) {
4010 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4011 return rc;
4012 }
4013
4014 rc = pm_chg_auto_enable(chip, !charging_disabled);
4015 if (rc) {
4016 pr_err("Failed to enable charging rc=%d\n", rc);
4017 return rc;
4018 }
4019
4020 return 0;
4021}
4022
4023static int get_rt_status(void *data, u64 * val)
4024{
4025 int i = (int)data;
4026 int ret;
4027
4028 /* global irq number is passed in via data */
4029 ret = pm_chg_get_rt_status(the_chip, i);
4030 *val = ret;
4031 return 0;
4032}
4033DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4034
4035static int get_fsm_status(void *data, u64 * val)
4036{
4037 u8 temp;
4038
4039 temp = pm_chg_get_fsm_state(the_chip);
4040 *val = temp;
4041 return 0;
4042}
4043DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4044
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004045static int get_reg_loop(void *data, u64 * val)
4046{
4047 u8 temp;
4048
4049 if (!the_chip) {
4050 pr_err("%s called before init\n", __func__);
4051 return -EINVAL;
4052 }
4053 temp = pm_chg_get_regulation_loop(the_chip);
4054 *val = temp;
4055 return 0;
4056}
4057DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059static int get_reg(void *data, u64 * val)
4060{
4061 int addr = (int)data;
4062 int ret;
4063 u8 temp;
4064
4065 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4066 if (ret) {
4067 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4068 addr, temp, ret);
4069 return -EAGAIN;
4070 }
4071 *val = temp;
4072 return 0;
4073}
4074
4075static int set_reg(void *data, u64 val)
4076{
4077 int addr = (int)data;
4078 int ret;
4079 u8 temp;
4080
4081 temp = (u8) val;
4082 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
4083 if (ret) {
4084 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
4085 addr, temp, ret);
4086 return -EAGAIN;
4087 }
4088 return 0;
4089}
4090DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4091
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004092enum {
4093 BAT_WARM_ZONE,
4094 BAT_COOL_ZONE,
4095};
4096static int get_warm_cool(void *data, u64 * val)
4097{
4098 if (!the_chip) {
4099 pr_err("%s called before init\n", __func__);
4100 return -EINVAL;
4101 }
4102 if ((int)data == BAT_WARM_ZONE)
4103 *val = the_chip->is_bat_warm;
4104 if ((int)data == BAT_COOL_ZONE)
4105 *val = the_chip->is_bat_cool;
4106 return 0;
4107}
4108DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004110static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4111{
4112 int i;
4113
4114 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4115
4116 if (IS_ERR(chip->dent)) {
4117 pr_err("pmic charger couldnt create debugfs dir\n");
4118 return;
4119 }
4120
4121 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4122 (void *)CHG_CNTRL, &reg_fops);
4123 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4124 (void *)CHG_CNTRL_2, &reg_fops);
4125 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4126 (void *)CHG_CNTRL_3, &reg_fops);
4127 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4128 (void *)PBL_ACCESS1, &reg_fops);
4129 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4130 (void *)PBL_ACCESS2, &reg_fops);
4131 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4132 (void *)SYS_CONFIG_1, &reg_fops);
4133 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4134 (void *)SYS_CONFIG_2, &reg_fops);
4135 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4136 (void *)CHG_VDD_MAX, &reg_fops);
4137 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4138 (void *)CHG_VDD_SAFE, &reg_fops);
4139 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4140 (void *)CHG_VBAT_DET, &reg_fops);
4141 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4142 (void *)CHG_IBAT_MAX, &reg_fops);
4143 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4144 (void *)CHG_IBAT_SAFE, &reg_fops);
4145 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4146 (void *)CHG_VIN_MIN, &reg_fops);
4147 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4148 (void *)CHG_VTRICKLE, &reg_fops);
4149 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4150 (void *)CHG_ITRICKLE, &reg_fops);
4151 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4152 (void *)CHG_ITERM, &reg_fops);
4153 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4154 (void *)CHG_TCHG_MAX, &reg_fops);
4155 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4156 (void *)CHG_TWDOG, &reg_fops);
4157 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4158 (void *)CHG_TEMP_THRESH, &reg_fops);
4159 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4160 (void *)CHG_COMP_OVR, &reg_fops);
4161 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4162 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4163 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4164 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4165 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4166 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4167 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4168 (void *)CHG_TEST, &reg_fops);
4169
4170 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4171 &fsm_fops);
4172
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004173 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4174 &reg_loop_fops);
4175
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004176 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4177 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4178 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4179 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004181 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4182 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4183 debugfs_create_file(chg_irq_data[i].name, 0444,
4184 chip->dent,
4185 (void *)chg_irq_data[i].irq_id,
4186 &rt_fops);
4187 }
4188}
4189
kyungtae.oh2ab04b02012-07-23 21:46:47 +09004190int pm8921_stop_chg_disable_irq(void)
4191{
4192
4193 struct pm8921_chg_chip *chip = the_chip;
4194
4195 pm8921_chg_disable_irq(chip, ATCFAIL_IRQ);
4196 pm8921_chg_disable_irq(chip, CHGHOT_IRQ);
4197 pm8921_chg_disable_irq(chip, ATCDONE_IRQ);
4198 pm8921_chg_disable_irq(chip, FASTCHG_IRQ);
4199 pm8921_chg_disable_irq(chip, CHGDONE_IRQ);
4200 pm8921_chg_disable_irq(chip, VBATDET_IRQ);
4201 pm8921_chg_disable_irq(chip, VBATDET_LOW_IRQ);
4202
4203 return 1;
4204}
4205int pm8921_start_chg_enable_irq(void)
4206{
4207
4208 struct pm8921_chg_chip *chip = the_chip;
4209
4210 pm8921_chg_enable_irq(chip, ATCFAIL_IRQ);
4211 pm8921_chg_enable_irq(chip, CHGHOT_IRQ);
4212 pm8921_chg_enable_irq(chip, ATCDONE_IRQ);
4213 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
4214 pm8921_chg_enable_irq(chip, CHGDONE_IRQ);
4215 pm8921_chg_enable_irq(chip, VBATDET_IRQ);
4216 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
4217
4218 return 1;
4219}
4220
4221static ssize_t pm8921_chg_status_show(struct device *dev,
4222 struct device_attribute *attr, char *buf)
4223{
4224 int fsm_state, is_charging, r;
4225 bool b_chg_ok = false;
4226
4227 if (!the_chip) {
4228 pr_err("called before init\n");
4229 return -EINVAL;
4230 }
4231
4232 fsm_state = pm_chg_get_fsm_state(the_chip);
4233 is_charging = is_battery_charging(fsm_state);
4234
4235 if (is_charging) {
4236 b_chg_ok = true;
4237 r = sprintf(buf, "%d\n", b_chg_ok);
4238 pr_info("pm8921_chg_status_show , true ! buf = %s, is_charging = %d\n",
4239 buf, is_charging);
4240 } else {
4241 b_chg_ok = false;
4242 r = sprintf(buf, "%d\n", b_chg_ok);
4243 pr_info("pm8921_chg_status_show , false ! buf = %s, is_charging = %d\n",
4244 buf, is_charging);
4245 }
4246
4247 return r;
4248}
4249
4250static ssize_t pm8921_chg_status_store(struct device *dev,
4251 struct device_attribute *attr,
4252 const char *buf, size_t count)
4253{
4254 int ret = 0, batt_status = 0;
4255 struct pm8921_chg_chip *chip = the_chip;
4256
4257 if (!count)
4258 return -EINVAL;
4259
4260 batt_status = get_prop_batt_status(chip);
4261
4262 if (strncmp(buf, "0", 1) == 0) {
4263 /* stop charging */
4264 pr_info("pm8921_chg_status_store : stop charging start\n");
4265 if (batt_status == POWER_SUPPLY_STATUS_CHARGING) {
4266 ret = pm8921_stop_chg_disable_irq();
4267 pm_chg_auto_enable(chip, 0);
4268 pm_chg_charge_dis(chip,1);
4269 pr_info("pm8921_chg_status_store : stop charging end\n");
4270 }
4271 } else if (strncmp(buf, "1", 1) == 0) {
4272 /* start charging */
4273 pr_info("pm8921_chg_status_store : start charging start\n");
4274 if (batt_status != POWER_SUPPLY_STATUS_CHARGING) {
4275 ret = pm8921_start_chg_enable_irq();
4276 pm_chg_auto_enable(chip, 1);
4277 pm_chg_charge_dis(chip,0);
4278 pr_info("pm8921_chg_status_store : start charging end\n");
4279 }
4280 }
4281
4282 if(ret == 0)
4283 return -EINVAL;
4284
4285 return ret;
4286}
4287DEVICE_ATTR(charge, 0664, pm8921_chg_status_show, pm8921_chg_status_store);
4288
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004289static int pm8921_charger_suspend_noirq(struct device *dev)
4290{
4291 int rc;
4292 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4293
4294 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4295 if (rc)
4296 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07004297 if (!(chip->disable_hw_clock_switching))
4298 pm8921_chg_set_hw_clk_switching(chip);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004299 return 0;
4300}
4301
4302static int pm8921_charger_resume_noirq(struct device *dev)
4303{
4304 int rc;
4305 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4306
4307 pm8921_chg_force_19p2mhz_clk(chip);
4308
4309 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4310 VREF_BATT_THERM_FORCE_ON);
4311 if (rc)
4312 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4313 return 0;
4314}
4315
David Keitelf2226022011-12-13 15:55:50 -08004316static int pm8921_charger_resume(struct device *dev)
4317{
4318 int rc;
4319 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4320
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004321 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08004322 && !(chip->keep_btm_on_suspend)) {
4323 rc = pm8xxx_adc_btm_configure(&btm_config);
4324 if (rc)
4325 pr_err("couldn't reconfigure btm rc=%d\n", rc);
4326
4327 rc = pm8xxx_adc_btm_start();
4328 if (rc)
4329 pr_err("couldn't restart btm rc=%d\n", rc);
4330 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004331 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4332 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4333 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4334 }
David Keitelf2226022011-12-13 15:55:50 -08004335 return 0;
4336}
4337
4338static int pm8921_charger_suspend(struct device *dev)
4339{
4340 int rc;
4341 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4342
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004343 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08004344 && !(chip->keep_btm_on_suspend)) {
4345 rc = pm8xxx_adc_btm_end();
4346 if (rc)
4347 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
4348 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004349
4350 if (is_usb_chg_plugged_in(chip)) {
4351 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4352 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4353 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004354
David Keitelf2226022011-12-13 15:55:50 -08004355 return 0;
4356}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4358{
4359 int rc = 0;
4360 struct pm8921_chg_chip *chip;
4361 const struct pm8921_charger_platform_data *pdata
4362 = pdev->dev.platform_data;
4363
4364 if (!pdata) {
4365 pr_err("missing platform data\n");
4366 return -EINVAL;
4367 }
4368
4369 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4370 GFP_KERNEL);
4371 if (!chip) {
4372 pr_err("Cannot allocate pm_chg_chip\n");
4373 return -ENOMEM;
4374 }
4375
4376 chip->dev = &pdev->dev;
4377 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004378 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004379 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004380 chip->max_voltage_mv = pdata->max_voltage;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07004381 chip->alarm_voltage_mv = pdata->alarm_voltage;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004382 chip->min_voltage_mv = pdata->min_voltage;
David Keitel0789fc62012-06-07 17:43:27 -07004383 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004384 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004385 chip->term_current = pdata->term_current;
4386 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004387 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004388 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4389 chip->batt_id_min = pdata->batt_id_min;
4390 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004391 if (pdata->cool_temp != INT_MIN)
4392 chip->cool_temp_dc = pdata->cool_temp * 10;
4393 else
4394 chip->cool_temp_dc = INT_MIN;
4395
4396 if (pdata->warm_temp != INT_MIN)
4397 chip->warm_temp_dc = pdata->warm_temp * 10;
4398 else
4399 chip->warm_temp_dc = INT_MIN;
4400
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004401 chip->temp_check_period = pdata->temp_check_period;
David Keitel5bed4f12012-05-25 18:04:14 -07004402 chip->dc_unplug_check = pdata->dc_unplug_check;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004403 chip->max_bat_chg_current = pdata->max_bat_chg_current;
4404 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4405 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4406 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4407 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08004408 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004409 chip->trkl_voltage = pdata->trkl_voltage;
4410 chip->weak_voltage = pdata->weak_voltage;
4411 chip->trkl_current = pdata->trkl_current;
4412 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004413 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004414 chip->thermal_mitigation = pdata->thermal_mitigation;
4415 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004416
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004417 chip->cold_thr = pdata->cold_thr;
4418 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004419 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004420 chip->led_src_config = pdata->led_src_config;
Devin Kim32599592012-08-22 11:40:44 -07004421 chip->ext_batt_temp_monitor = pdata->ext_batt_temp_monitor;
4422
4423 if (chip->ext_batt_temp_monitor)
4424 chip->ext_batt_health = POWER_SUPPLY_HEALTH_GOOD;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004426 rc = pm8921_chg_hw_init(chip);
4427 if (rc) {
4428 pr_err("couldn't init hardware rc=%d\n", rc);
4429 goto free_chip;
4430 }
4431
4432 chip->usb_psy.name = "usb",
4433 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4434 chip->usb_psy.supplied_to = pm_power_supplied_to,
4435 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004436 chip->usb_psy.properties = pm_power_props_usb,
4437 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4438 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004439 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004440
David Keitel6ed71a52012-01-30 12:42:18 -08004441 chip->dc_psy.name = "pm8921-dc",
4442 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4443 chip->dc_psy.supplied_to = pm_power_supplied_to,
4444 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004445 chip->dc_psy.properties = pm_power_props_mains,
4446 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4447 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004449 chip->batt_psy.name = "battery",
4450 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4451 chip->batt_psy.properties = msm_batt_power_props,
4452 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4453 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004454 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004455 rc = power_supply_register(chip->dev, &chip->usb_psy);
4456 if (rc < 0) {
4457 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004458 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004459 }
4460
David Keitel6ed71a52012-01-30 12:42:18 -08004461 rc = power_supply_register(chip->dev, &chip->dc_psy);
4462 if (rc < 0) {
4463 pr_err("power_supply_register usb failed rc = %d\n", rc);
4464 goto unregister_usb;
4465 }
4466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004467 rc = power_supply_register(chip->dev, &chip->batt_psy);
4468 if (rc < 0) {
4469 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004470 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004471 }
4472
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004473 platform_set_drvdata(pdev, chip);
4474 the_chip = chip;
4475
4476 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004477 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004478 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4479 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004480 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Devin Kim69f17302012-09-12 20:30:28 -07004481 INIT_DELAYED_WORK(&chip->unplug_usbcheck_work, unplug_usbcheck_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483 rc = request_irqs(chip, pdev);
4484 if (rc) {
4485 pr_err("couldn't register interrupts rc=%d\n", rc);
4486 goto unregister_batt;
4487 }
4488
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004489 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
4490 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
4491 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
Devin Kim32599592012-08-22 11:40:44 -07004492 if (!chip->ext_batt_temp_monitor)
4493 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004494 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004495 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004496 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004497 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004498 * care for jeita compliance
4499 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004500 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004501 rc = configure_btm(chip);
4502 if (rc) {
4503 pr_err("couldn't register with btm rc=%d\n", rc);
4504 goto free_irq;
4505 }
4506 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004507
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07004508 rc = pm8921_charger_configure_batt_alarm(chip);
4509 if (rc) {
4510 pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
4511 goto free_irq;
4512 }
4513
4514 rc = pm8921_charger_enable_batt_alarm(chip);
4515 if (rc) {
4516 pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
4517 goto free_irq;
4518 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004519 create_debugfs_entries(chip);
4520
4521 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004522 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004524 /* determine what state the charger is in */
4525 determine_initial_state(chip);
4526
kyungtae.oh839d5a52012-08-13 18:45:49 +09004527 rc = device_create_file(&pdev->dev, &dev_attr_charge);
4528 if (rc) {
4529 pr_err("Couldn't device_create_file charge! rc=%d\n",rc);
4530 goto free_irq;
4531 }
4532
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004533 if (chip->update_time) {
4534 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
4535 update_heartbeat);
4536 schedule_delayed_work(&chip->update_heartbeat_work,
4537 round_jiffies_relative(msecs_to_jiffies
4538 (chip->update_time)));
4539 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 return 0;
4541
4542free_irq:
4543 free_irqs(chip);
4544unregister_batt:
4545 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004546unregister_dc:
4547 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548unregister_usb:
4549 power_supply_unregister(&chip->usb_psy);
4550free_chip:
4551 kfree(chip);
4552 return rc;
4553}
4554
4555static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4556{
4557 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4558
kyungtae.oh839d5a52012-08-13 18:45:49 +09004559 device_remove_file(&pdev->dev, &dev_attr_charge);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560 free_irqs(chip);
4561 platform_set_drvdata(pdev, NULL);
4562 the_chip = NULL;
4563 kfree(chip);
4564 return 0;
4565}
David Keitelf2226022011-12-13 15:55:50 -08004566static const struct dev_pm_ops pm8921_pm_ops = {
4567 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004568 .suspend_noirq = pm8921_charger_suspend_noirq,
4569 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004570 .resume = pm8921_charger_resume,
4571};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004572static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004573 .probe = pm8921_charger_probe,
4574 .remove = __devexit_p(pm8921_charger_remove),
4575 .driver = {
4576 .name = PM8921_CHARGER_DEV_NAME,
4577 .owner = THIS_MODULE,
4578 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004579 },
4580};
4581
4582static int __init pm8921_charger_init(void)
4583{
4584 return platform_driver_register(&pm8921_charger_driver);
4585}
4586
4587static void __exit pm8921_charger_exit(void)
4588{
4589 platform_driver_unregister(&pm8921_charger_driver);
4590}
4591
4592late_initcall(pm8921_charger_init);
4593module_exit(pm8921_charger_exit);
4594
4595MODULE_LICENSE("GPL v2");
4596MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4597MODULE_VERSION("1.0");
4598MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);