blob: a2eb39ed2b9cef7ce54ba46ab27a8b778ef447cd [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070080#define IUSB_FINE_RES 0x2B6
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070082/* check EOC every 10 seconds */
83#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080084/* check for USB unplug every 200 msecs */
85#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087enum chg_fsm_state {
88 FSM_STATE_OFF_0 = 0,
89 FSM_STATE_BATFETDET_START_12 = 12,
90 FSM_STATE_BATFETDET_END_16 = 16,
91 FSM_STATE_ON_CHG_HIGHI_1 = 1,
92 FSM_STATE_ATC_2A = 2,
93 FSM_STATE_ATC_2B = 18,
94 FSM_STATE_ON_BAT_3 = 3,
95 FSM_STATE_ATC_FAIL_4 = 4 ,
96 FSM_STATE_DELAY_5 = 5,
97 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
98 FSM_STATE_FAST_CHG_7 = 7,
99 FSM_STATE_TRKL_CHG_8 = 8,
100 FSM_STATE_CHG_FAIL_9 = 9,
101 FSM_STATE_EOC_10 = 10,
102 FSM_STATE_ON_CHG_VREGOK_11 = 11,
103 FSM_STATE_ATC_PAUSE_13 = 13,
104 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
105 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
106 FSM_STATE_START_BOOT = 20,
107 FSM_STATE_FLCB_VREGOK = 21,
108 FSM_STATE_FLCB = 22,
109};
110
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700111struct fsm_state_to_batt_status {
112 enum chg_fsm_state fsm_state;
113 int batt_state;
114};
115
116static struct fsm_state_to_batt_status map[] = {
117 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
118 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
119 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
120 /*
121 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
122 * too hot/cold, charger too hot
123 */
124 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
125 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
126 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
127 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
128 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
129 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
130 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
134 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
135 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
136 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
141 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
142};
143
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700144enum chg_regulation_loop {
145 VDD_LOOP = BIT(3),
146 BAT_CURRENT_LOOP = BIT(2),
147 INPUT_CURRENT_LOOP = BIT(1),
148 INPUT_VOLTAGE_LOOP = BIT(0),
149 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
150 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
151};
152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153enum pmic_chg_interrupts {
154 USBIN_VALID_IRQ = 0,
155 USBIN_OV_IRQ,
156 BATT_INSERTED_IRQ,
157 VBATDET_LOW_IRQ,
158 USBIN_UV_IRQ,
159 VBAT_OV_IRQ,
160 CHGWDOG_IRQ,
161 VCP_IRQ,
162 ATCDONE_IRQ,
163 ATCFAIL_IRQ,
164 CHGDONE_IRQ,
165 CHGFAIL_IRQ,
166 CHGSTATE_IRQ,
167 LOOP_CHANGE_IRQ,
168 FASTCHG_IRQ,
169 TRKLCHG_IRQ,
170 BATT_REMOVED_IRQ,
171 BATTTEMP_HOT_IRQ,
172 CHGHOT_IRQ,
173 BATTTEMP_COLD_IRQ,
174 CHG_GONE_IRQ,
175 BAT_TEMP_OK_IRQ,
176 COARSE_DET_LOW_IRQ,
177 VDD_LOOP_IRQ,
178 VREG_OV_IRQ,
179 VBATDET_IRQ,
180 BATFET_IRQ,
181 PSI_IRQ,
182 DCIN_VALID_IRQ,
183 DCIN_OV_IRQ,
184 DCIN_UV_IRQ,
185 PM_CHG_MAX_INTS,
186};
187
188struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700189 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 int is_charging;
191 struct work_struct work;
192};
193
194/**
195 * struct pm8921_chg_chip -device information
196 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 * @usb_present: present status of usb
198 * @dc_present: present status of dc
199 * @usb_charger_current: usb current to charge the battery with used when
200 * the usb path is enabled or charging is resumed
201 * @safety_time: max time for which charging will happen
202 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800203 * @max_voltage_mv: the max volts the batt should be charged up to
204 * @min_voltage_mv: the min battery voltage before turning the FETon
205 * @cool_temp_dc: the cool temp threshold in deciCelcius
206 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700207 * @resume_voltage_delta: the voltage delta from vdd max at which the
208 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 * @term_current: The charging based term current
210 *
211 */
212struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700213 struct device *dev;
214 unsigned int usb_present;
215 unsigned int dc_present;
216 unsigned int usb_charger_current;
217 unsigned int max_bat_chg_current;
218 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
219 unsigned int safety_time;
220 unsigned int ttrkl_time;
221 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800222 unsigned int max_voltage_mv;
223 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800224 int cool_temp_dc;
225 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700226 unsigned int temp_check_period;
227 unsigned int cool_bat_chg_current;
228 unsigned int warm_bat_chg_current;
229 unsigned int cool_bat_voltage;
230 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700231 unsigned int is_bat_cool;
232 unsigned int is_bat_warm;
233 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700234 unsigned int term_current;
235 unsigned int vbat_channel;
236 unsigned int batt_temp_channel;
237 unsigned int batt_id_channel;
238 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800239 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800240 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700241 struct power_supply batt_psy;
242 struct dentry *dent;
243 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800244 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200245 bool ext_charging;
246 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700247 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700249 struct work_struct battery_id_valid_work;
250 int64_t batt_id_min;
251 int64_t batt_id_max;
252 int trkl_voltage;
253 int weak_voltage;
254 int trkl_current;
255 int weak_current;
256 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800257 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700258 int thermal_levels;
259 struct delayed_work update_heartbeat_work;
260 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800261 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800262 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700263 struct wake_lock eoc_wake_lock;
264 enum pm8921_chg_cold_thr cold_thr;
265 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800266 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700267 enum pm8921_chg_led_src_config led_src_config;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268};
269
David Keitelacf57c82012-03-07 18:48:50 -0800270/* user space parameter to limit usb current */
271static unsigned int usb_max_current;
272/*
273 * usb_target_ma is used for wall charger
274 * adaptive input current limiting only. Use
275 * pm_iusbmax_get() to get current maximum usb current setting.
276 */
277static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700279static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280
281static struct pm8921_chg_chip *the_chip;
282
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700283static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
286 u8 mask, u8 val)
287{
288 int rc;
289 u8 reg;
290
291 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
292 if (rc) {
293 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
294 return rc;
295 }
296 reg &= ~mask;
297 reg |= val & mask;
298 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
299 if (rc) {
300 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
301 return rc;
302 }
303 return 0;
304}
305
David Keitelcf867232012-01-27 18:40:12 -0800306static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
307{
308 return pm8xxx_read_irq_stat(chip->dev->parent,
309 chip->pmic_chg_irq[irq_id]);
310}
311
312/* Treat OverVoltage/UnderVoltage as source missing */
313static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
314{
315 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
316}
317
318/* Treat OverVoltage/UnderVoltage as source missing */
319static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
320{
321 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
322}
323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324#define CAPTURE_FSM_STATE_CMD 0xC2
325#define READ_BANK_7 0x70
326#define READ_BANK_4 0x40
327static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
328{
329 u8 temp;
330 int err, ret = 0;
331
332 temp = CAPTURE_FSM_STATE_CMD;
333 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
334 if (err) {
335 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
336 return err;
337 }
338
339 temp = READ_BANK_7;
340 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
341 if (err) {
342 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
343 return err;
344 }
345
346 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
347 if (err) {
348 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
349 return err;
350 }
351 /* get the lower 4 bits */
352 ret = temp & 0xF;
353
354 temp = READ_BANK_4;
355 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
356 if (err) {
357 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
358 return err;
359 }
360
361 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
362 if (err) {
363 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
364 return err;
365 }
366 /* get the upper 1 bit */
367 ret |= (temp & 0x1) << 4;
368 return ret;
369}
370
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700371#define READ_BANK_6 0x60
372static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
373{
374 u8 temp;
375 int err;
376
377 temp = READ_BANK_6;
378 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
379 if (err) {
380 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
381 return err;
382 }
383
384 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
385 if (err) {
386 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
387 return err;
388 }
389
390 /* return the lower 4 bits */
391 return temp & CHG_ALL_LOOPS;
392}
393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394#define CHG_USB_SUSPEND_BIT BIT(2)
395static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
396{
397 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
398 enable ? CHG_USB_SUSPEND_BIT : 0);
399}
400
401#define CHG_EN_BIT BIT(7)
402static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
403{
404 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
405 enable ? CHG_EN_BIT : 0);
406}
407
David Keitel753ec8d2011-11-02 10:56:37 -0700408#define CHG_FAILED_CLEAR BIT(0)
409#define ATC_FAILED_CLEAR BIT(1)
410static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
411{
412 int rc;
413
414 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
415 clear ? ATC_FAILED_CLEAR : 0);
416 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
417 clear ? CHG_FAILED_CLEAR : 0);
418 return rc;
419}
420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421#define CHG_CHARGE_DIS_BIT BIT(1)
422static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
423{
424 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
425 disable ? CHG_CHARGE_DIS_BIT : 0);
426}
427
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800428static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
429{
430 u8 temp;
431
432 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
433 return temp & CHG_CHARGE_DIS_BIT;
434}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435#define PM8921_CHG_V_MIN_MV 3240
436#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800437#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438#define PM8921_CHG_VDDMAX_MAX 4500
439#define PM8921_CHG_VDDMAX_MIN 3400
440#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800441static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800443 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800444 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800446 if (voltage < PM8921_CHG_VDDMAX_MIN
447 || voltage > PM8921_CHG_VDDMAX_MAX) {
448 pr_err("bad mV=%d asked to set\n", voltage);
449 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450 }
David Keitelcf867232012-01-27 18:40:12 -0800451
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800452 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
453
454 remainder = voltage % 20;
455 if (remainder >= 10) {
456 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
457 }
458
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800460 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461}
462
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700463static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
464{
465 u8 temp;
466 int rc;
467
468 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
469 if (rc) {
470 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700471 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700472 return rc;
473 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800474 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
475 + PM8921_CHG_V_MIN_MV;
476 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
477 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700478 return 0;
479}
480
David Keitelcf867232012-01-27 18:40:12 -0800481static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
482{
483 int current_mv, ret, steps, i;
484 bool increase;
485
486 ret = 0;
487
488 if (voltage < PM8921_CHG_VDDMAX_MIN
489 || voltage > PM8921_CHG_VDDMAX_MAX) {
490 pr_err("bad mV=%d asked to set\n", voltage);
491 return -EINVAL;
492 }
493
494 ret = pm_chg_vddmax_get(chip, &current_mv);
495 if (ret) {
496 pr_err("Failed to read vddmax rc=%d\n", ret);
497 return -EINVAL;
498 }
499 if (current_mv == voltage)
500 return 0;
501
502 /* Only change in increments when USB is present */
503 if (is_usb_chg_plugged_in(chip)) {
504 if (current_mv < voltage) {
505 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
506 increase = true;
507 } else {
508 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
509 increase = false;
510 }
511 for (i = 0; i < steps; i++) {
512 if (increase)
513 current_mv += PM8921_CHG_V_STEP_MV;
514 else
515 current_mv -= PM8921_CHG_V_STEP_MV;
516 ret |= __pm_chg_vddmax_set(chip, current_mv);
517 }
518 }
519 ret |= __pm_chg_vddmax_set(chip, voltage);
520 return ret;
521}
522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523#define PM8921_CHG_VDDSAFE_MIN 3400
524#define PM8921_CHG_VDDSAFE_MAX 4500
525static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
526{
527 u8 temp;
528
529 if (voltage < PM8921_CHG_VDDSAFE_MIN
530 || voltage > PM8921_CHG_VDDSAFE_MAX) {
531 pr_err("bad mV=%d asked to set\n", voltage);
532 return -EINVAL;
533 }
534 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
535 pr_debug("voltage=%d setting %02x\n", voltage, temp);
536 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
537}
538
539#define PM8921_CHG_VBATDET_MIN 3240
540#define PM8921_CHG_VBATDET_MAX 5780
541static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
542{
543 u8 temp;
544
545 if (voltage < PM8921_CHG_VBATDET_MIN
546 || voltage > PM8921_CHG_VBATDET_MAX) {
547 pr_err("bad mV=%d asked to set\n", voltage);
548 return -EINVAL;
549 }
550 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
551 pr_debug("voltage=%d setting %02x\n", voltage, temp);
552 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
553}
554
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700555#define PM8921_CHG_VINMIN_MIN_MV 3800
556#define PM8921_CHG_VINMIN_STEP_MV 100
557#define PM8921_CHG_VINMIN_USABLE_MAX 6500
558#define PM8921_CHG_VINMIN_USABLE_MIN 4300
559#define PM8921_CHG_VINMIN_MASK 0x1F
560static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
561{
562 u8 temp;
563
564 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
565 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
566 pr_err("bad mV=%d asked to set\n", voltage);
567 return -EINVAL;
568 }
569 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
570 pr_debug("voltage=%d setting %02x\n", voltage, temp);
571 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
572 temp);
573}
574
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800575static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
576{
577 u8 temp;
578 int rc, voltage_mv;
579
580 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
581 temp &= PM8921_CHG_VINMIN_MASK;
582
583 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
584 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
585
586 return voltage_mv;
587}
588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589#define PM8921_CHG_IBATMAX_MIN 325
590#define PM8921_CHG_IBATMAX_MAX 2000
591#define PM8921_CHG_I_MIN_MA 225
592#define PM8921_CHG_I_STEP_MA 50
593#define PM8921_CHG_I_MASK 0x3F
594static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
595{
596 u8 temp;
597
598 if (chg_current < PM8921_CHG_IBATMAX_MIN
599 || chg_current > PM8921_CHG_IBATMAX_MAX) {
600 pr_err("bad mA=%d asked to set\n", chg_current);
601 return -EINVAL;
602 }
603 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
604 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
605}
606
607#define PM8921_CHG_IBATSAFE_MIN 225
608#define PM8921_CHG_IBATSAFE_MAX 3375
609static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
610{
611 u8 temp;
612
613 if (chg_current < PM8921_CHG_IBATSAFE_MIN
614 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
615 pr_err("bad mA=%d asked to set\n", chg_current);
616 return -EINVAL;
617 }
618 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
619 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
620 PM8921_CHG_I_MASK, temp);
621}
622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700624#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625#define PM8921_CHG_ITERM_STEP_MA 10
626#define PM8921_CHG_ITERM_MASK 0xF
627static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
628{
629 u8 temp;
630
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700631 if (chg_current < PM8921_CHG_ITERM_MIN_MA
632 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633 pr_err("bad mA=%d asked to set\n", chg_current);
634 return -EINVAL;
635 }
636
637 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
638 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700639 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 temp);
641}
642
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700643static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
644{
645 u8 temp;
646 int rc;
647
648 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
649 if (rc) {
650 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700651 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700652 return rc;
653 }
654 temp &= PM8921_CHG_ITERM_MASK;
655 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
656 + PM8921_CHG_ITERM_MIN_MA;
657 return 0;
658}
659
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800660struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700661 int usb_ma;
662 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800663};
664
665static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700666 {100, 0x0},
667 {200, 0x1},
668 {500, 0x2},
669 {600, 0x3},
670 {700, 0x4},
671 {800, 0x5},
672 {850, 0x6},
673 {900, 0x8},
674 {950, 0x7},
675 {1000, 0x9},
676 {1100, 0xA},
677 {1200, 0xB},
678 {1300, 0xC},
679 {1400, 0xD},
680 {1500, 0xE},
681 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800682};
683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700685#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686#define PM8921_CHG_IUSB_MAX 7
687#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700688#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700689static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690{
David Keitel38bdd4f2012-04-19 15:39:13 -0700691 u8 temp, fineres;
692 int rc;
693
694 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[reg_val].value;
695 reg_val = usb_ma_table[reg_val].value >> 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700697 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
698 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 return -EINVAL;
700 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700701 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
702
703 /* IUSB_FINE_RES */
704 if (chip->iusb_fine_res) {
705 /* Clear IUSB_FINE_RES bit to avoid overshoot */
706 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
707 PM8917_IUSB_FINE_RES, 0);
708
709 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
710 PM8921_CHG_IUSB_MASK, temp);
711
712 if (rc) {
713 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
714 return rc;
715 }
716
717 if (fineres) {
718 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
719 PM8917_IUSB_FINE_RES, fineres);
720 if (rc)
721 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
722 rc);
723 }
724 } else {
725 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
726 PM8921_CHG_IUSB_MASK, temp);
727 if (rc)
728 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
729 }
730
731 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732}
733
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800734static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
735{
David Keitel38bdd4f2012-04-19 15:39:13 -0700736 u8 temp, fineres;
737 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800738
David Keitel38bdd4f2012-04-19 15:39:13 -0700739 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800740 *mA = 0;
741 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
742 if (rc) {
743 pr_err("err=%d reading PBL_ACCESS2\n", rc);
744 return rc;
745 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700746
747 if (chip->iusb_fine_res) {
748 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
749 if (rc) {
750 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
751 return rc;
752 }
753 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800754 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -0700755 temp = temp >> PM8921_CHG_IUSB_SHIFT;
756
757 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
758 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
759 if (usb_ma_table[i].value == temp)
760 break;
761 }
762
763 *mA = usb_ma_table[i].usb_ma;
764
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800765 return rc;
766}
767
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768#define PM8921_CHG_WD_MASK 0x1F
769static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
770{
771 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700772 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
773}
774
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700775#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700776#define PM8921_CHG_TCHG_MIN 4
777#define PM8921_CHG_TCHG_MAX 512
778#define PM8921_CHG_TCHG_STEP 4
779static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
780{
781 u8 temp;
782
783 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
784 pr_err("bad max minutes =%d asked to set\n", minutes);
785 return -EINVAL;
786 }
787
788 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
789 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
790 temp);
791}
792
793#define PM8921_CHG_TTRKL_MASK 0x1F
794#define PM8921_CHG_TTRKL_MIN 1
795#define PM8921_CHG_TTRKL_MAX 64
796static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
797{
798 u8 temp;
799
800 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
801 pr_err("bad max minutes =%d asked to set\n", minutes);
802 return -EINVAL;
803 }
804
805 temp = minutes - 1;
806 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
807 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808}
809
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700810#define PM8921_CHG_VTRKL_MIN_MV 2050
811#define PM8921_CHG_VTRKL_MAX_MV 2800
812#define PM8921_CHG_VTRKL_STEP_MV 50
813#define PM8921_CHG_VTRKL_SHIFT 4
814#define PM8921_CHG_VTRKL_MASK 0xF0
815static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
816{
817 u8 temp;
818
819 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
820 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
821 pr_err("bad voltage = %dmV asked to set\n", millivolts);
822 return -EINVAL;
823 }
824
825 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
826 temp = temp << PM8921_CHG_VTRKL_SHIFT;
827 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
828 temp);
829}
830
831#define PM8921_CHG_VWEAK_MIN_MV 2100
832#define PM8921_CHG_VWEAK_MAX_MV 3600
833#define PM8921_CHG_VWEAK_STEP_MV 100
834#define PM8921_CHG_VWEAK_MASK 0x0F
835static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
836{
837 u8 temp;
838
839 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
840 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
841 pr_err("bad voltage = %dmV asked to set\n", millivolts);
842 return -EINVAL;
843 }
844
845 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
846 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
847 temp);
848}
849
850#define PM8921_CHG_ITRKL_MIN_MA 50
851#define PM8921_CHG_ITRKL_MAX_MA 200
852#define PM8921_CHG_ITRKL_MASK 0x0F
853#define PM8921_CHG_ITRKL_STEP_MA 10
854static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
855{
856 u8 temp;
857
858 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
859 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
860 pr_err("bad current = %dmA asked to set\n", milliamps);
861 return -EINVAL;
862 }
863
864 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
865
866 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
867 temp);
868}
869
870#define PM8921_CHG_IWEAK_MIN_MA 325
871#define PM8921_CHG_IWEAK_MAX_MA 525
872#define PM8921_CHG_IWEAK_SHIFT 7
873#define PM8921_CHG_IWEAK_MASK 0x80
874static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
875{
876 u8 temp;
877
878 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
879 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
880 pr_err("bad current = %dmA asked to set\n", milliamps);
881 return -EINVAL;
882 }
883
884 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
885 temp = 0;
886 else
887 temp = 1;
888
889 temp = temp << PM8921_CHG_IWEAK_SHIFT;
890 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
891 temp);
892}
893
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700894#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
895#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
896static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
897 enum pm8921_chg_cold_thr cold_thr)
898{
899 u8 temp;
900
901 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
902 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
903 return pm_chg_masked_write(chip, CHG_CNTRL_2,
904 PM8921_CHG_BATT_TEMP_THR_COLD,
905 temp);
906}
907
908#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
909#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
910static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
911 enum pm8921_chg_hot_thr hot_thr)
912{
913 u8 temp;
914
915 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
916 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
917 return pm_chg_masked_write(chip, CHG_CNTRL_2,
918 PM8921_CHG_BATT_TEMP_THR_HOT,
919 temp);
920}
921
Jay Chokshid674a512012-03-15 14:06:04 -0700922#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
923#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
924static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
925 enum pm8921_chg_led_src_config led_src_config)
926{
927 u8 temp;
928
929 if (led_src_config < LED_SRC_GND ||
930 led_src_config > LED_SRC_BYPASS)
931 return -EINVAL;
932
933 if (led_src_config == LED_SRC_BYPASS)
934 return 0;
935
936 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
937
938 return pm_chg_masked_write(chip, CHG_CNTRL_3,
939 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
940}
941
David Keitel8c5201a2012-02-24 16:08:54 -0800942static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
943{
944 u8 temp;
945 int rc;
946
947 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
948 if (rc) {
949 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
950 return;
951 }
952 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
953 if (rc) {
954 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
955 return;
956 }
957 /* set the input voltage disable bit and the write bit */
958 temp |= 0x81;
959 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
960 if (rc) {
961 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
962 return;
963 }
964}
965
966static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
967{
968 u8 temp;
969 int rc;
970
971 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
972 if (rc) {
973 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
974 return;
975 }
976 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
977 if (rc) {
978 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
979 return;
980 }
981 /* unset the input voltage disable bit */
982 temp &= 0xFE;
983 /* set the write bit */
984 temp |= 0x80;
985 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
986 if (rc) {
987 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
988 return;
989 }
990}
991
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700992static int64_t read_battery_id(struct pm8921_chg_chip *chip)
993{
994 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700995 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700996
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700997 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700998 if (rc) {
999 pr_err("error reading batt id channel = %d, rc = %d\n",
1000 chip->vbat_channel, rc);
1001 return rc;
1002 }
1003 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1004 result.measurement);
1005 return result.physical;
1006}
1007
1008static int is_battery_valid(struct pm8921_chg_chip *chip)
1009{
1010 int64_t rc;
1011
1012 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1013 return 1;
1014
1015 rc = read_battery_id(chip);
1016 if (rc < 0) {
1017 pr_err("error reading batt id channel = %d, rc = %lld\n",
1018 chip->vbat_channel, rc);
1019 /* assume battery id is valid when adc error happens */
1020 return 1;
1021 }
1022
1023 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1024 pr_err("batt_id phy =%lld is not valid\n", rc);
1025 return 0;
1026 }
1027 return 1;
1028}
1029
1030static void check_battery_valid(struct pm8921_chg_chip *chip)
1031{
1032 if (is_battery_valid(chip) == 0) {
1033 pr_err("batt_id not valid, disbling charging\n");
1034 pm_chg_auto_enable(chip, 0);
1035 } else {
1036 pm_chg_auto_enable(chip, !charging_disabled);
1037 }
1038}
1039
1040static void battery_id_valid(struct work_struct *work)
1041{
1042 struct pm8921_chg_chip *chip = container_of(work,
1043 struct pm8921_chg_chip, battery_id_valid_work);
1044
1045 check_battery_valid(chip);
1046}
1047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1049{
1050 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1051 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1052 enable_irq(chip->pmic_chg_irq[interrupt]);
1053 }
1054}
1055
1056static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1057{
1058 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1059 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1060 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1061 }
1062}
1063
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001064static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1065{
1066 return test_bit(interrupt, chip->enabled_irqs);
1067}
1068
Amir Samuelovd31ef502011-10-26 14:41:36 +02001069static bool is_ext_charging(struct pm8921_chg_chip *chip)
1070{
David Keitel88e1b572012-01-11 11:57:14 -08001071 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001072
David Keitel88e1b572012-01-11 11:57:14 -08001073 if (!chip->ext_psy)
1074 return false;
1075 if (chip->ext_psy->get_property(chip->ext_psy,
1076 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1077 return false;
1078 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1079 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001080
1081 return false;
1082}
1083
1084static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1085{
David Keitel88e1b572012-01-11 11:57:14 -08001086 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001087
David Keitel88e1b572012-01-11 11:57:14 -08001088 if (!chip->ext_psy)
1089 return false;
1090 if (chip->ext_psy->get_property(chip->ext_psy,
1091 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1092 return false;
1093 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001094 return true;
1095
1096 return false;
1097}
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099static int is_battery_charging(int fsm_state)
1100{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001101 if (is_ext_charging(the_chip))
1102 return 1;
1103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104 switch (fsm_state) {
1105 case FSM_STATE_ATC_2A:
1106 case FSM_STATE_ATC_2B:
1107 case FSM_STATE_ON_CHG_AND_BAT_6:
1108 case FSM_STATE_FAST_CHG_7:
1109 case FSM_STATE_TRKL_CHG_8:
1110 return 1;
1111 }
1112 return 0;
1113}
1114
1115static void bms_notify(struct work_struct *work)
1116{
1117 struct bms_notify *n = container_of(work, struct bms_notify, work);
1118
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001119 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001121 } else {
1122 pm8921_bms_charging_end(n->is_battery_full);
1123 n->is_battery_full = 0;
1124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125}
1126
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001127static void bms_notify_check(struct pm8921_chg_chip *chip)
1128{
1129 int fsm_state, new_is_charging;
1130
1131 fsm_state = pm_chg_get_fsm_state(chip);
1132 new_is_charging = is_battery_charging(fsm_state);
1133
1134 if (chip->bms_notify.is_charging ^ new_is_charging) {
1135 chip->bms_notify.is_charging = new_is_charging;
1136 schedule_work(&(chip->bms_notify.work));
1137 }
1138}
1139
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001140static enum power_supply_property pm_power_props_usb[] = {
1141 POWER_SUPPLY_PROP_PRESENT,
1142 POWER_SUPPLY_PROP_ONLINE,
1143 POWER_SUPPLY_PROP_CURRENT_MAX,
1144};
1145
1146static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001148 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149};
1150
1151static char *pm_power_supplied_to[] = {
1152 "battery",
1153};
1154
David Keitel6ed71a52012-01-30 12:42:18 -08001155#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001156static int pm_power_get_property_mains(struct power_supply *psy,
1157 enum power_supply_property psp,
1158 union power_supply_propval *val)
1159{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001160 /* Check if called before init */
1161 if (!the_chip)
1162 return -EINVAL;
1163
1164 switch (psp) {
1165 case POWER_SUPPLY_PROP_PRESENT:
1166 case POWER_SUPPLY_PROP_ONLINE:
1167 val->intval = 0;
1168 if (charging_disabled)
1169 return 0;
1170
1171 /* check external charger first before the dc path */
1172 if (is_ext_charging(the_chip)) {
1173 val->intval = 1;
1174 return 0;
1175 }
1176
1177 if (pm_is_chg_charge_dis(the_chip)) {
1178 val->intval = 0;
1179 return 0;
1180 }
1181
1182 if (the_chip->dc_present) {
1183 val->intval = 1;
1184 return 0;
1185 }
1186
1187 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001188 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001189 val->intval = is_usb_chg_plugged_in(the_chip);
1190 return 0;
1191
1192 break;
1193 default:
1194 return -EINVAL;
1195 }
1196 return 0;
1197}
1198
1199static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 enum power_supply_property psp,
1201 union power_supply_propval *val)
1202{
David Keitel6ed71a52012-01-30 12:42:18 -08001203 int current_max;
1204
1205 /* Check if called before init */
1206 if (!the_chip)
1207 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208
1209 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001210 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001211 if (pm_is_chg_charge_dis(the_chip)) {
1212 val->intval = 0;
1213 } else {
1214 pm_chg_iusbmax_get(the_chip, &current_max);
1215 val->intval = current_max;
1216 }
David Keitel6ed71a52012-01-30 12:42:18 -08001217 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001219 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001220 val->intval = 0;
1221 if (charging_disabled)
1222 return 0;
1223
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001224 /*
1225 * if drawing any current from usb is disabled behave
1226 * as if no usb cable is connected
1227 */
1228 if (pm_is_chg_charge_dis(the_chip))
1229 return 0;
1230
David Keitel63f71662012-02-08 20:30:00 -08001231 /* USB charging */
David Keitelaf515712012-04-13 17:25:31 -07001232 if (usb_target_ma < USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001233 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001234 else
1235 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236 break;
1237 default:
1238 return -EINVAL;
1239 }
1240 return 0;
1241}
1242
1243static enum power_supply_property msm_batt_power_props[] = {
1244 POWER_SUPPLY_PROP_STATUS,
1245 POWER_SUPPLY_PROP_CHARGE_TYPE,
1246 POWER_SUPPLY_PROP_HEALTH,
1247 POWER_SUPPLY_PROP_PRESENT,
1248 POWER_SUPPLY_PROP_TECHNOLOGY,
1249 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1250 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1251 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1252 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001253 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001254 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001255 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256};
1257
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001258static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259{
1260 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001261 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001263 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 if (rc) {
1265 pr_err("error reading adc channel = %d, rc = %d\n",
1266 chip->vbat_channel, rc);
1267 return rc;
1268 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001269 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 result.measurement);
1271 return (int)result.physical;
1272}
1273
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001274static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1275{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001276 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1277 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1278 unsigned int low_voltage = chip->min_voltage_mv;
1279 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001280
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001281 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001282 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001283 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001284 return 100;
1285 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001286 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001287 / (high_voltage - low_voltage);
1288}
1289
David Keitel4f9397b2012-04-16 11:46:16 -07001290static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1291{
1292 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1293}
1294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1296{
David Keitel4f9397b2012-04-16 11:46:16 -07001297 int percent_soc;
1298
1299 if (!get_prop_batt_present(chip))
1300 percent_soc = voltage_based_capacity(chip);
1301 else
1302 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001303
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001304 if (percent_soc == -ENXIO)
1305 percent_soc = voltage_based_capacity(chip);
1306
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001307 if (percent_soc <= 10)
1308 pr_warn("low battery charge = %d%%\n", percent_soc);
1309
1310 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311}
1312
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001313static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1314{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001315 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001316
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001317 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001318 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001319 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001320 }
1321
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001322 if (rc) {
1323 pr_err("unable to get batt current rc = %d\n", rc);
1324 return rc;
1325 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001326 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001327 }
1328}
1329
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001330static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1331{
1332 int rc;
1333
1334 rc = pm8921_bms_get_fcc();
1335 if (rc < 0)
1336 pr_err("unable to get batt fcc rc = %d\n", rc);
1337 return rc;
1338}
1339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1341{
1342 int temp;
1343
1344 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1345 if (temp)
1346 return POWER_SUPPLY_HEALTH_OVERHEAT;
1347
1348 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1349 if (temp)
1350 return POWER_SUPPLY_HEALTH_COLD;
1351
1352 return POWER_SUPPLY_HEALTH_GOOD;
1353}
1354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1356{
1357 int temp;
1358
Amir Samuelovd31ef502011-10-26 14:41:36 +02001359 if (!get_prop_batt_present(chip))
1360 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1361
1362 if (is_ext_trickle_charging(chip))
1363 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1364
1365 if (is_ext_charging(chip))
1366 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1369 if (temp)
1370 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1371
1372 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1373 if (temp)
1374 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1375
1376 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1377}
1378
1379static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1380{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001381 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1382 int fsm_state = pm_chg_get_fsm_state(chip);
1383 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384
David Keitel88e1b572012-01-11 11:57:14 -08001385 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001386 if (chip->ext_charge_done)
1387 return POWER_SUPPLY_STATUS_FULL;
1388 if (chip->ext_charging)
1389 return POWER_SUPPLY_STATUS_CHARGING;
1390 }
1391
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001392 for (i = 0; i < ARRAY_SIZE(map); i++)
1393 if (map[i].fsm_state == fsm_state)
1394 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001395
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001396 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1397 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1398 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001399 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1400 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001401
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001402 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001403 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001404 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405}
1406
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001407#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001408static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1409{
1410 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001411 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001412
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001413 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001414 if (rc) {
1415 pr_err("error reading adc channel = %d, rc = %d\n",
1416 chip->vbat_channel, rc);
1417 return rc;
1418 }
1419 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1420 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001421 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1422 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1423 (int) result.physical);
1424
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001425 return (int)result.physical;
1426}
1427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428static int pm_batt_power_get_property(struct power_supply *psy,
1429 enum power_supply_property psp,
1430 union power_supply_propval *val)
1431{
1432 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1433 batt_psy);
1434
1435 switch (psp) {
1436 case POWER_SUPPLY_PROP_STATUS:
1437 val->intval = get_prop_batt_status(chip);
1438 break;
1439 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1440 val->intval = get_prop_charge_type(chip);
1441 break;
1442 case POWER_SUPPLY_PROP_HEALTH:
1443 val->intval = get_prop_batt_health(chip);
1444 break;
1445 case POWER_SUPPLY_PROP_PRESENT:
1446 val->intval = get_prop_batt_present(chip);
1447 break;
1448 case POWER_SUPPLY_PROP_TECHNOLOGY:
1449 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1450 break;
1451 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001452 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 break;
1454 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001455 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 break;
1457 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001458 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459 break;
1460 case POWER_SUPPLY_PROP_CAPACITY:
1461 val->intval = get_prop_batt_capacity(chip);
1462 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001463 case POWER_SUPPLY_PROP_CURRENT_NOW:
1464 val->intval = get_prop_batt_current(chip);
1465 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001466 case POWER_SUPPLY_PROP_TEMP:
1467 val->intval = get_prop_batt_temp(chip);
1468 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001469 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001470 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001471 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 default:
1473 return -EINVAL;
1474 }
1475
1476 return 0;
1477}
1478
1479static void (*notify_vbus_state_func_ptr)(int);
1480static int usb_chg_current;
1481static DEFINE_SPINLOCK(vbus_lock);
1482
1483int pm8921_charger_register_vbus_sn(void (*callback)(int))
1484{
1485 pr_debug("%p\n", callback);
1486 notify_vbus_state_func_ptr = callback;
1487 return 0;
1488}
1489EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1490
1491/* this is passed to the hsusb via platform_data msm_otg_pdata */
1492void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1493{
1494 pr_debug("%p\n", callback);
1495 notify_vbus_state_func_ptr = NULL;
1496}
1497EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1498
1499static void notify_usb_of_the_plugin_event(int plugin)
1500{
1501 plugin = !!plugin;
1502 if (notify_vbus_state_func_ptr) {
1503 pr_debug("notifying plugin\n");
1504 (*notify_vbus_state_func_ptr) (plugin);
1505 } else {
1506 pr_debug("unable to notify plugin\n");
1507 }
1508}
1509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510/* assumes vbus_lock is held */
1511static void __pm8921_charger_vbus_draw(unsigned int mA)
1512{
1513 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001514 if (!the_chip) {
1515 pr_err("called before init\n");
1516 return;
1517 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518
David Keitel38bdd4f2012-04-19 15:39:13 -07001519 if (mA >= 0 && mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001521 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001523 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 }
1525 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1526 if (rc)
1527 pr_err("fail to set suspend bit rc=%d\n", rc);
1528 } else {
1529 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1530 if (rc)
1531 pr_err("fail to reset suspend bit rc=%d\n", rc);
1532 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1533 if (usb_ma_table[i].usb_ma <= mA)
1534 break;
1535 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001536
1537 /* Check if IUSB_FINE_RES is available */
1538 if ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
1539 && !the_chip->iusb_fine_res)
1540 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 if (i < 0)
1542 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001543 rc = pm_chg_iusbmax_set(the_chip, i);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001545 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 }
1547 }
1548}
1549
1550/* USB calls these to tell us how much max usb current the system can draw */
1551void pm8921_charger_vbus_draw(unsigned int mA)
1552{
1553 unsigned long flags;
1554
1555 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001556
David Keitel62c6a4b2012-05-17 12:54:59 -07001557 if (!the_chip) {
1558 pr_err("chip not yet initalized\n");
1559 return;
1560 }
1561
1562 /*
1563 * Reject VBUS requests if USB connection is the only available
1564 * power source. This makes sure that if booting without
1565 * battery the iusb_max value is not decreased avoiding potential
1566 * brown_outs.
1567 *
1568 * This would also apply when the battery has been
1569 * removed from the running system.
1570 */
1571 if (!get_prop_batt_present(the_chip)
1572 && !is_dc_chg_plugged_in(the_chip)) {
1573 pr_err("rejected: no other power source connected\n");
1574 return;
1575 }
1576
David Keitelacf57c82012-03-07 18:48:50 -08001577 if (usb_max_current && mA > usb_max_current) {
1578 pr_warn("restricting usb current to %d instead of %d\n",
1579 usb_max_current, mA);
1580 mA = usb_max_current;
1581 }
1582 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1583 usb_target_ma = mA;
1584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 spin_lock_irqsave(&vbus_lock, flags);
1586 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001587 if (mA > USB_WALL_THRESHOLD_MA)
1588 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1589 else
1590 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 } else {
1592 /*
1593 * called before pmic initialized,
1594 * save this value and use it at probe
1595 */
David Keitelacf57c82012-03-07 18:48:50 -08001596 if (mA > USB_WALL_THRESHOLD_MA)
1597 usb_chg_current = USB_WALL_THRESHOLD_MA;
1598 else
1599 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 }
1601 spin_unlock_irqrestore(&vbus_lock, flags);
1602}
1603EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1604
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001605int pm8921_charger_enable(bool enable)
1606{
1607 int rc;
1608
1609 if (!the_chip) {
1610 pr_err("called before init\n");
1611 return -EINVAL;
1612 }
1613 enable = !!enable;
1614 rc = pm_chg_auto_enable(the_chip, enable);
1615 if (rc)
1616 pr_err("Failed rc=%d\n", rc);
1617 return rc;
1618}
1619EXPORT_SYMBOL(pm8921_charger_enable);
1620
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001621int pm8921_is_usb_chg_plugged_in(void)
1622{
1623 if (!the_chip) {
1624 pr_err("called before init\n");
1625 return -EINVAL;
1626 }
1627 return is_usb_chg_plugged_in(the_chip);
1628}
1629EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1630
1631int pm8921_is_dc_chg_plugged_in(void)
1632{
1633 if (!the_chip) {
1634 pr_err("called before init\n");
1635 return -EINVAL;
1636 }
1637 return is_dc_chg_plugged_in(the_chip);
1638}
1639EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1640
1641int pm8921_is_battery_present(void)
1642{
1643 if (!the_chip) {
1644 pr_err("called before init\n");
1645 return -EINVAL;
1646 }
1647 return get_prop_batt_present(the_chip);
1648}
1649EXPORT_SYMBOL(pm8921_is_battery_present);
1650
David Keitel012deef2011-12-02 11:49:33 -08001651/*
1652 * Disabling the charge current limit causes current
1653 * current limits to have no monitoring. An adequate charger
1654 * capable of supplying high current while sustaining VIN_MIN
1655 * is required if the limiting is disabled.
1656 */
1657int pm8921_disable_input_current_limit(bool disable)
1658{
1659 if (!the_chip) {
1660 pr_err("called before init\n");
1661 return -EINVAL;
1662 }
1663 if (disable) {
1664 pr_warn("Disabling input current limit!\n");
1665
1666 return pm8xxx_writeb(the_chip->dev->parent,
1667 CHG_BUCK_CTRL_TEST3, 0xF2);
1668 }
1669 return 0;
1670}
1671EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1672
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001673int pm8921_set_max_battery_charge_current(int ma)
1674{
1675 if (!the_chip) {
1676 pr_err("called before init\n");
1677 return -EINVAL;
1678 }
1679 return pm_chg_ibatmax_set(the_chip, ma);
1680}
1681EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1682
1683int pm8921_disable_source_current(bool disable)
1684{
1685 if (!the_chip) {
1686 pr_err("called before init\n");
1687 return -EINVAL;
1688 }
1689 if (disable)
1690 pr_warn("current drawn from chg=0, battery provides current\n");
1691 return pm_chg_charge_dis(the_chip, disable);
1692}
1693EXPORT_SYMBOL(pm8921_disable_source_current);
1694
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001695int pm8921_regulate_input_voltage(int voltage)
1696{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001697 int rc;
1698
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001699 if (!the_chip) {
1700 pr_err("called before init\n");
1701 return -EINVAL;
1702 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001703 rc = pm_chg_vinmin_set(the_chip, voltage);
1704
1705 if (rc == 0)
1706 the_chip->vin_min = voltage;
1707
1708 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001709}
1710
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001711#define USB_OV_THRESHOLD_MASK 0x60
1712#define USB_OV_THRESHOLD_SHIFT 5
1713int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1714{
1715 u8 temp;
1716
1717 if (!the_chip) {
1718 pr_err("called before init\n");
1719 return -EINVAL;
1720 }
1721
1722 if (ov > PM_USB_OV_7V) {
1723 pr_err("limiting to over voltage threshold to 7volts\n");
1724 ov = PM_USB_OV_7V;
1725 }
1726
1727 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1728
1729 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1730 USB_OV_THRESHOLD_MASK, temp);
1731}
1732EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1733
1734#define USB_DEBOUNCE_TIME_MASK 0x06
1735#define USB_DEBOUNCE_TIME_SHIFT 1
1736int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1737{
1738 u8 temp;
1739
1740 if (!the_chip) {
1741 pr_err("called before init\n");
1742 return -EINVAL;
1743 }
1744
1745 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1746 pr_err("limiting debounce to 80.5ms\n");
1747 ms = PM_USB_DEBOUNCE_80P5MS;
1748 }
1749
1750 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1751
1752 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1753 USB_DEBOUNCE_TIME_MASK, temp);
1754}
1755EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1756
1757#define USB_OVP_DISABLE_MASK 0x80
1758int pm8921_usb_ovp_disable(int disable)
1759{
1760 u8 temp = 0;
1761
1762 if (!the_chip) {
1763 pr_err("called before init\n");
1764 return -EINVAL;
1765 }
1766
1767 if (disable)
1768 temp = USB_OVP_DISABLE_MASK;
1769
1770 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1771 USB_OVP_DISABLE_MASK, temp);
1772}
1773
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001774bool pm8921_is_battery_charging(int *source)
1775{
1776 int fsm_state, is_charging, dc_present, usb_present;
1777
1778 if (!the_chip) {
1779 pr_err("called before init\n");
1780 return -EINVAL;
1781 }
1782 fsm_state = pm_chg_get_fsm_state(the_chip);
1783 is_charging = is_battery_charging(fsm_state);
1784 if (is_charging == 0) {
1785 *source = PM8921_CHG_SRC_NONE;
1786 return is_charging;
1787 }
1788
1789 if (source == NULL)
1790 return is_charging;
1791
1792 /* the battery is charging, the source is requested, find it */
1793 dc_present = is_dc_chg_plugged_in(the_chip);
1794 usb_present = is_usb_chg_plugged_in(the_chip);
1795
1796 if (dc_present && !usb_present)
1797 *source = PM8921_CHG_SRC_DC;
1798
1799 if (usb_present && !dc_present)
1800 *source = PM8921_CHG_SRC_USB;
1801
1802 if (usb_present && dc_present)
1803 /*
1804 * The system always chooses dc for charging since it has
1805 * higher priority.
1806 */
1807 *source = PM8921_CHG_SRC_DC;
1808
1809 return is_charging;
1810}
1811EXPORT_SYMBOL(pm8921_is_battery_charging);
1812
David Keitel86034022012-04-18 12:33:58 -07001813int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1814{
1815 if (!the_chip) {
1816 pr_err("called before init\n");
1817 return -EINVAL;
1818 }
1819
1820 if (type < POWER_SUPPLY_TYPE_USB)
1821 return -EINVAL;
1822
1823 the_chip->usb_psy.type = type;
1824 power_supply_changed(&the_chip->usb_psy);
1825 power_supply_changed(&the_chip->dc_psy);
1826 return 0;
1827}
1828EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1829
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001830int pm8921_batt_temperature(void)
1831{
1832 if (!the_chip) {
1833 pr_err("called before init\n");
1834 return -EINVAL;
1835 }
1836 return get_prop_batt_temp(the_chip);
1837}
1838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1840{
1841 int usb_present;
1842
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08001843 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 usb_present = is_usb_chg_plugged_in(chip);
1845 if (chip->usb_present ^ usb_present) {
1846 notify_usb_of_the_plugin_event(usb_present);
1847 chip->usb_present = usb_present;
1848 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001849 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08001850 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001852 if (usb_present) {
1853 schedule_delayed_work(&chip->unplug_check_work,
1854 round_jiffies_relative(msecs_to_jiffies
1855 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001856 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1857 } else {
David Keitelacf57c82012-03-07 18:48:50 -08001858 /* USB unplugged reset target current */
1859 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08001860 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001861 }
David Keitel8c5201a2012-02-24 16:08:54 -08001862 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001863 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864}
1865
Amir Samuelovd31ef502011-10-26 14:41:36 +02001866static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1867{
David Keitel88e1b572012-01-11 11:57:14 -08001868 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001869 pr_debug("external charger not registered.\n");
1870 return;
1871 }
1872
1873 if (!chip->ext_charging) {
1874 pr_debug("already not charging.\n");
1875 return;
1876 }
1877
David Keitel88e1b572012-01-11 11:57:14 -08001878 power_supply_set_charge_type(chip->ext_psy,
1879 POWER_SUPPLY_CHARGE_TYPE_NONE);
1880 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001881 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001882 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001883 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001884 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03001885 /* Update battery charging LEDs and user space battery info */
1886 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001887}
1888
1889static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1890{
1891 int dc_present;
1892 int batt_present;
1893 int batt_temp_ok;
1894 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001895 unsigned long delay =
1896 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1897
David Keitel88e1b572012-01-11 11:57:14 -08001898 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001899 pr_debug("external charger not registered.\n");
1900 return;
1901 }
1902
1903 if (chip->ext_charging) {
1904 pr_debug("already charging.\n");
1905 return;
1906 }
1907
David Keitel88e1b572012-01-11 11:57:14 -08001908 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001909 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1910 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001911
1912 if (!dc_present) {
1913 pr_warn("%s. dc not present.\n", __func__);
1914 return;
1915 }
1916 if (!batt_present) {
1917 pr_warn("%s. battery not present.\n", __func__);
1918 return;
1919 }
1920 if (!batt_temp_ok) {
1921 pr_warn("%s. battery temperature not ok.\n", __func__);
1922 return;
1923 }
David Keitel88e1b572012-01-11 11:57:14 -08001924 pm8921_disable_source_current(true); /* Force BATFET=ON */
1925 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001926 if (vbat_ov) {
1927 pr_warn("%s. battery over voltage.\n", __func__);
1928 return;
1929 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001930
David Keitel63f71662012-02-08 20:30:00 -08001931 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001932 power_supply_set_charge_type(chip->ext_psy,
1933 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001934 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001935 chip->ext_charging = true;
1936 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001937 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001938 /* Start BMS */
1939 schedule_delayed_work(&chip->eoc_work, delay);
1940 wake_lock(&chip->eoc_wake_lock);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03001941 /* Update battery charging LEDs and user space battery info */
1942 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001943}
1944
David Keitel8c5201a2012-02-24 16:08:54 -08001945static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001946{
1947 u8 temp;
1948 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001949
David Keitel8c5201a2012-02-24 16:08:54 -08001950 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001951 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001952 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1953 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001954 }
David Keitel8c5201a2012-02-24 16:08:54 -08001955 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1956 if (rc) {
1957 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1958 return;
1959 }
1960 /* set ovp fet disable bit and the write bit */
1961 temp |= 0x81;
1962 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1963 if (rc) {
1964 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1965 return;
1966 }
1967}
1968
1969static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1970{
1971 u8 temp;
1972 int rc;
1973
1974 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1975 if (rc) {
1976 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1977 return;
1978 }
1979 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1980 if (rc) {
1981 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1982 return;
1983 }
1984 /* unset ovp fet disable bit and set the write bit */
1985 temp &= 0xFE;
1986 temp |= 0x80;
1987 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1988 if (rc) {
1989 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1990 temp, rc);
1991 return;
1992 }
1993}
1994
1995static int param_open_ovp_counter = 10;
1996module_param(param_open_ovp_counter, int, 0644);
1997
1998#define WRITE_BANK_4 0xC0
1999#define USB_OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002000static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002001{
Steve Mucklef132c6c2012-06-06 18:30:57 -07002002 int chg_gone = 0, usb_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002003 int count = 0;
2004
2005 while (count++ < param_open_ovp_counter) {
2006 pm_chg_masked_write(chip, USB_OVP_CONTROL,
2007 USB_OVP_DEBOUNCE_TIME, 0x0);
2008 usleep(10);
2009 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2010 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2011 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
2012 count, chg_gone, usb_chg_plugged_in);
2013
2014 /* note usb_chg_plugged_in=0 => chg_gone=1 */
2015 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2016 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
2017 turn_off_usb_ovp_fet(chip);
2018
2019 msleep(20);
2020
2021 turn_on_usb_ovp_fet(chip);
2022 } else {
David Keitel712782e2012-03-29 14:11:47 -07002023 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002024 }
2025 }
David Keitel712782e2012-03-29 14:11:47 -07002026 pm_chg_masked_write(chip, USB_OVP_CONTROL,
2027 USB_OVP_DEBOUNCE_TIME, 0x2);
2028 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
2029 count, chg_gone, usb_chg_plugged_in);
2030 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002031}
David Keitelacf57c82012-03-07 18:48:50 -08002032
2033static int find_usb_ma_value(int value)
2034{
2035 int i;
2036
2037 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2038 if (value >= usb_ma_table[i].usb_ma)
2039 break;
2040 }
2041
2042 return i;
2043}
2044
2045static void decrease_usb_ma_value(int *value)
2046{
2047 int i;
2048
2049 if (value) {
2050 i = find_usb_ma_value(*value);
2051 if (i > 0)
2052 i--;
2053 *value = usb_ma_table[i].usb_ma;
2054 }
2055}
2056
2057static void increase_usb_ma_value(int *value)
2058{
2059 int i;
2060
2061 if (value) {
2062 i = find_usb_ma_value(*value);
2063
2064 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2065 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002066 /* Get next correct entry if IUSB_FINE_RES is not available */
2067 while (!the_chip->iusb_fine_res
2068 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2069 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2070 i++;
2071
David Keitelacf57c82012-03-07 18:48:50 -08002072 *value = usb_ma_table[i].usb_ma;
2073 }
2074}
2075
2076static void vin_collapse_check_worker(struct work_struct *work)
2077{
2078 struct delayed_work *dwork = to_delayed_work(work);
2079 struct pm8921_chg_chip *chip = container_of(dwork,
2080 struct pm8921_chg_chip, vin_collapse_check_work);
2081
2082 /* AICL only for wall-chargers */
2083 if (is_usb_chg_plugged_in(chip) &&
2084 usb_target_ma > USB_WALL_THRESHOLD_MA) {
2085 /* decrease usb_target_ma */
2086 decrease_usb_ma_value(&usb_target_ma);
2087 /* reset here, increase in unplug_check_worker */
2088 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2089 pr_debug("usb_now=%d, usb_target = %d\n",
2090 USB_WALL_THRESHOLD_MA, usb_target_ma);
2091 } else {
2092 handle_usb_insertion_removal(chip);
2093 }
2094}
2095
2096#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002097static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2098{
David Keitelacf57c82012-03-07 18:48:50 -08002099 if (usb_target_ma)
2100 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2101 round_jiffies_relative(msecs_to_jiffies
2102 (VIN_MIN_COLLAPSE_CHECK_MS)));
2103 else
2104 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105 return IRQ_HANDLED;
2106}
2107
2108static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
2109{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002110 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 return IRQ_HANDLED;
2112}
2113
2114static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2115{
2116 struct pm8921_chg_chip *chip = data;
2117 int status;
2118
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002119 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2120 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002121 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002122 pr_debug("battery present=%d", status);
2123 power_supply_changed(&chip->batt_psy);
2124 return IRQ_HANDLED;
2125}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002126
2127/*
2128 * this interrupt used to restart charging a battery.
2129 *
2130 * Note: When DC-inserted the VBAT can't go low.
2131 * VPH_PWR is provided by the ext-charger.
2132 * After End-Of-Charging from DC, charging can be resumed only
2133 * if DC is removed and then inserted after the battery was in use.
2134 * Therefore the handle_start_ext_chg() is not called.
2135 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2137{
2138 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002139 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002141 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002142
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002143 if (high_transition) {
2144 /* enable auto charging */
2145 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002146 pr_info("batt fell below resume voltage %s\n",
2147 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002148 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 power_supply_changed(&chip->batt_psy);
2152 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002153 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002154
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 return IRQ_HANDLED;
2156}
2157
2158static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
2159{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07002160 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 return IRQ_HANDLED;
2162}
2163
2164static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2165{
2166 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2167 return IRQ_HANDLED;
2168}
2169
2170static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2171{
2172 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2173 return IRQ_HANDLED;
2174}
2175
2176static irqreturn_t vcp_irq_handler(int irq, void *data)
2177{
David Keitel8c5201a2012-02-24 16:08:54 -08002178 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002179 return IRQ_HANDLED;
2180}
2181
2182static irqreturn_t atcdone_irq_handler(int irq, void *data)
2183{
2184 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2185 return IRQ_HANDLED;
2186}
2187
2188static irqreturn_t atcfail_irq_handler(int irq, void *data)
2189{
2190 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2191 return IRQ_HANDLED;
2192}
2193
2194static irqreturn_t chgdone_irq_handler(int irq, void *data)
2195{
2196 struct pm8921_chg_chip *chip = data;
2197
2198 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002199
2200 handle_stop_ext_chg(chip);
2201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 power_supply_changed(&chip->batt_psy);
2203 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002204 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002205
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002206 bms_notify_check(chip);
2207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 return IRQ_HANDLED;
2209}
2210
2211static irqreturn_t chgfail_irq_handler(int irq, void *data)
2212{
2213 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002214 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002215
David Keitel753ec8d2011-11-02 10:56:37 -07002216 ret = pm_chg_failed_clear(chip, 1);
2217 if (ret)
2218 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2219
2220 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2221 get_prop_batt_present(chip),
2222 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2223 pm_chg_get_fsm_state(data));
2224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002225 power_supply_changed(&chip->batt_psy);
2226 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002227 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002228 return IRQ_HANDLED;
2229}
2230
2231static irqreturn_t chgstate_irq_handler(int irq, void *data)
2232{
2233 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234
2235 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2236 power_supply_changed(&chip->batt_psy);
2237 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002238 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002240 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 return IRQ_HANDLED;
2243}
2244
David Keitel8c5201a2012-02-24 16:08:54 -08002245static int param_vin_disable_counter = 5;
2246module_param(param_vin_disable_counter, int, 0644);
2247
2248static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
2249 int count, int usb_ma)
2250{
David Keitelacf57c82012-03-07 18:48:50 -08002251 __pm8921_charger_vbus_draw(500);
David Keitel8c5201a2012-02-24 16:08:54 -08002252 pr_debug("count = %d iusb=500mA\n", count);
2253 disable_input_voltage_regulation(chip);
2254 pr_debug("count = %d disable_input_regulation\n", count);
2255
2256 msleep(20);
2257
2258 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2259 count,
2260 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2261 is_usb_chg_plugged_in(chip));
2262 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2263 count, usb_ma);
2264 enable_input_voltage_regulation(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002265 __pm8921_charger_vbus_draw(usb_ma);
David Keitel8c5201a2012-02-24 16:08:54 -08002266}
2267
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002268#define VIN_ACTIVE_BIT BIT(0)
2269#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2270#define VIN_MIN_INCREASE_MV 100
2271static void unplug_check_worker(struct work_struct *work)
2272{
2273 struct delayed_work *dwork = to_delayed_work(work);
2274 struct pm8921_chg_chip *chip = container_of(dwork,
2275 struct pm8921_chg_chip, unplug_check_work);
2276 u8 reg_loop;
David Keitelacf57c82012-03-07 18:48:50 -08002277 int ibat, usb_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002278 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002279
David Keitelacf57c82012-03-07 18:48:50 -08002280 reg_loop = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002281 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2282 if (!usb_chg_plugged_in) {
2283 pr_debug("Stopping Unplug Check Worker since USB is removed"
2284 "reg_loop = %d, fsm = %d ibat = %d\n",
2285 pm_chg_get_regulation_loop(chip),
2286 pm_chg_get_fsm_state(chip),
2287 get_prop_batt_current(chip)
2288 );
2289 return;
2290 }
David Keitel8c5201a2012-02-24 16:08:54 -08002291
2292 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitelacf57c82012-03-07 18:48:50 -08002293 if (usb_ma == 500 && !usb_target_ma) {
David Keitel8c5201a2012-02-24 16:08:54 -08002294 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2295 disable_input_voltage_regulation(chip);
2296 return;
2297 }
2298
2299 if (usb_ma <= 100) {
2300 pr_debug(
2301 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2302 usb_ma);
2303 goto check_again_later;
2304 }
2305 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2306 pr_debug("chg gone irq is enabled\n");
2307
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002308 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002309 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002310
David Keitel21b7dfb2012-03-31 13:57:14 -07002311 if ((reg_loop & VIN_ACTIVE_BIT) && (usb_ma > USB_WALL_THRESHOLD_MA)) {
David Keitelacf57c82012-03-07 18:48:50 -08002312 decrease_usb_ma_value(&usb_ma);
2313 usb_target_ma = usb_ma;
2314 /* end AICL here */
2315 __pm8921_charger_vbus_draw(usb_ma);
2316 pr_debug("usb_now=%d, usb_target = %d\n",
2317 usb_ma, usb_target_ma);
2318 }
2319
2320 reg_loop = pm_chg_get_regulation_loop(chip);
2321 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2322
2323 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002324 ibat = get_prop_batt_current(chip);
2325
2326 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2327 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2328 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002329 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002330
David Keitel8c5201a2012-02-24 16:08:54 -08002331 while (count++ < param_vin_disable_counter
2332 && usb_chg_plugged_in == 1) {
2333 attempt_reverse_boost_fix(chip, count, usb_ma);
2334 usb_chg_plugged_in
2335 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002336 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002337 }
2338 }
2339
David Keitel8c5201a2012-02-24 16:08:54 -08002340 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2341 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2342
2343 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2344 /* run the worker directly */
2345 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2346 chg_gone, usb_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002347 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002348 }
2349
David Keitelacf57c82012-03-07 18:48:50 -08002350 if (!(reg_loop & VIN_ACTIVE_BIT)) {
2351 /* only increase iusb_max if vin loop not active */
2352 if (usb_ma < usb_target_ma) {
2353 increase_usb_ma_value(&usb_ma);
2354 __pm8921_charger_vbus_draw(usb_ma);
2355 pr_debug("usb_now=%d, usb_target = %d\n",
2356 usb_ma, usb_target_ma);
2357 } else {
2358 usb_target_ma = usb_ma;
2359 }
2360 }
David Keitel8c5201a2012-02-24 16:08:54 -08002361check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002362 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002363 schedule_delayed_work(&chip->unplug_check_work,
2364 round_jiffies_relative(msecs_to_jiffies
2365 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2366}
2367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368static irqreturn_t loop_change_irq_handler(int irq, void *data)
2369{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002370 struct pm8921_chg_chip *chip = data;
2371
2372 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2373 pm_chg_get_fsm_state(data),
2374 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002375 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 return IRQ_HANDLED;
2377}
2378
2379static irqreturn_t fastchg_irq_handler(int irq, void *data)
2380{
2381 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002382 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002384 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2385 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2386 wake_lock(&chip->eoc_wake_lock);
2387 schedule_delayed_work(&chip->eoc_work,
2388 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002389 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002390 }
2391 power_supply_changed(&chip->batt_psy);
2392 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002393 return IRQ_HANDLED;
2394}
2395
2396static irqreturn_t trklchg_irq_handler(int irq, void *data)
2397{
2398 struct pm8921_chg_chip *chip = data;
2399
2400 power_supply_changed(&chip->batt_psy);
2401 return IRQ_HANDLED;
2402}
2403
2404static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2405{
2406 struct pm8921_chg_chip *chip = data;
2407 int status;
2408
2409 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2410 pr_debug("battery present=%d state=%d", !status,
2411 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002412 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413 power_supply_changed(&chip->batt_psy);
2414 return IRQ_HANDLED;
2415}
2416
2417static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2418{
2419 struct pm8921_chg_chip *chip = data;
2420
Amir Samuelovd31ef502011-10-26 14:41:36 +02002421 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 power_supply_changed(&chip->batt_psy);
2423 return IRQ_HANDLED;
2424}
2425
2426static irqreturn_t chghot_irq_handler(int irq, void *data)
2427{
2428 struct pm8921_chg_chip *chip = data;
2429
2430 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2431 power_supply_changed(&chip->batt_psy);
2432 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002433 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434 return IRQ_HANDLED;
2435}
2436
2437static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2438{
2439 struct pm8921_chg_chip *chip = data;
2440
2441 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002442 handle_stop_ext_chg(chip);
2443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 power_supply_changed(&chip->batt_psy);
2445 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446 return IRQ_HANDLED;
2447}
2448
2449static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2450{
2451 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002452 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002453
2454 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2455 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2456
2457 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002458 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 power_supply_changed(&chip->batt_psy);
2461 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 return IRQ_HANDLED;
2463}
David Keitel52fda532011-11-10 10:43:44 -08002464/*
2465 *
2466 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2467 * fire for two cases:
2468 *
2469 * If the interrupt line switches to high temperature is okay
2470 * and thus charging begins.
2471 * If bat_temp_ok is low this means the temperature is now
2472 * too hot or cold, so charging is stopped.
2473 *
2474 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2476{
David Keitel52fda532011-11-10 10:43:44 -08002477 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478 struct pm8921_chg_chip *chip = data;
2479
David Keitel52fda532011-11-10 10:43:44 -08002480 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2481
2482 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2483 bat_temp_ok, pm_chg_get_fsm_state(data));
2484
2485 if (bat_temp_ok)
2486 handle_start_ext_chg(chip);
2487 else
2488 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 power_supply_changed(&chip->batt_psy);
2491 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002492 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 return IRQ_HANDLED;
2494}
2495
2496static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2497{
2498 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2499 return IRQ_HANDLED;
2500}
2501
2502static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2503{
2504 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2505 return IRQ_HANDLED;
2506}
2507
2508static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2509{
2510 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2511 return IRQ_HANDLED;
2512}
2513
2514static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2515{
2516 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2517 return IRQ_HANDLED;
2518}
2519
2520static irqreturn_t batfet_irq_handler(int irq, void *data)
2521{
2522 struct pm8921_chg_chip *chip = data;
2523
2524 pr_debug("vreg ov\n");
2525 power_supply_changed(&chip->batt_psy);
2526 return IRQ_HANDLED;
2527}
2528
2529static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2530{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002531 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002532 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002533
David Keitel88e1b572012-01-11 11:57:14 -08002534 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2535 if (chip->ext_psy)
2536 power_supply_set_online(chip->ext_psy, dc_present);
2537 chip->dc_present = dc_present;
2538 if (dc_present)
2539 handle_start_ext_chg(chip);
2540 else
2541 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 return IRQ_HANDLED;
2543}
2544
2545static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2546{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002547 struct pm8921_chg_chip *chip = data;
2548
Amir Samuelovd31ef502011-10-26 14:41:36 +02002549 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 return IRQ_HANDLED;
2551}
2552
2553static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2554{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002555 struct pm8921_chg_chip *chip = data;
2556
Amir Samuelovd31ef502011-10-26 14:41:36 +02002557 handle_stop_ext_chg(chip);
2558
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002559 return IRQ_HANDLED;
2560}
2561
David Keitel88e1b572012-01-11 11:57:14 -08002562static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2563{
2564 struct power_supply *psy = &the_chip->batt_psy;
2565 struct power_supply *epsy = dev_get_drvdata(dev);
2566 int i, dcin_irq;
2567
2568 /* Only search for external supply if none is registered */
2569 if (!the_chip->ext_psy) {
2570 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2571 for (i = 0; i < epsy->num_supplicants; i++) {
2572 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2573 if (!strncmp(epsy->name, "dc", 2)) {
2574 the_chip->ext_psy = epsy;
2575 dcin_valid_irq_handler(dcin_irq,
2576 the_chip);
2577 }
2578 }
2579 }
2580 }
2581 return 0;
2582}
2583
2584static void pm_batt_external_power_changed(struct power_supply *psy)
2585{
2586 /* Only look for an external supply if it hasn't been registered */
2587 if (!the_chip->ext_psy)
2588 class_for_each_device(power_supply_class, NULL, psy,
2589 __pm_batt_external_power_changed_work);
2590}
2591
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002592/**
2593 * update_heartbeat - internal function to update userspace
2594 * per update_time minutes
2595 *
2596 */
2597static void update_heartbeat(struct work_struct *work)
2598{
2599 struct delayed_work *dwork = to_delayed_work(work);
2600 struct pm8921_chg_chip *chip = container_of(dwork,
2601 struct pm8921_chg_chip, update_heartbeat_work);
2602
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002603 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002604 power_supply_changed(&chip->batt_psy);
2605 schedule_delayed_work(&chip->update_heartbeat_work,
2606 round_jiffies_relative(msecs_to_jiffies
2607 (chip->update_time)));
2608}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002609#define VDD_LOOP_ACTIVE_BIT BIT(3)
2610#define VDD_MAX_INCREASE_MV 400
2611static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
2612module_param(vdd_max_increase_mv, int, 0644);
2613
2614static int ichg_threshold_ua = -400000;
2615module_param(ichg_threshold_ua, int, 0644);
2616static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
2617{
2618 int ichg_meas_ua, vbat_uv;
2619 int ichg_meas_ma;
2620 int adj_vdd_max_mv, programmed_vdd_max;
2621 int vbat_batt_terminal_uv;
2622 int vbat_batt_terminal_mv;
2623 int reg_loop;
2624 int delta_mv = 0;
2625
2626 if (chip->rconn_mohm == 0) {
2627 pr_debug("Exiting as rconn_mohm is 0\n");
2628 return;
2629 }
2630 /* adjust vdd_max only in normal temperature zone */
2631 if (chip->is_bat_cool || chip->is_bat_warm) {
2632 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
2633 chip->is_bat_cool, chip->is_bat_warm);
2634 return;
2635 }
2636
2637 reg_loop = pm_chg_get_regulation_loop(chip);
2638 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
2639 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
2640 reg_loop);
2641 return;
2642 }
2643
2644 pm8921_bms_get_simultaneous_battery_voltage_and_current(&ichg_meas_ua,
2645 &vbat_uv);
2646 if (ichg_meas_ua >= 0) {
2647 pr_debug("Exiting ichg_meas_ua = %d > 0\n", ichg_meas_ua);
2648 return;
2649 }
2650 if (ichg_meas_ua <= ichg_threshold_ua) {
2651 pr_debug("Exiting ichg_meas_ua = %d < ichg_threshold_ua = %d\n",
2652 ichg_meas_ua, ichg_threshold_ua);
2653 return;
2654 }
2655 ichg_meas_ma = ichg_meas_ua / 1000;
2656
2657 /* rconn_mohm is in milliOhms */
2658 vbat_batt_terminal_uv = vbat_uv + ichg_meas_ma * the_chip->rconn_mohm;
2659 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
2660 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
2661
2662 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
2663
2664 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
2665 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
2666 delta_mv,
2667 programmed_vdd_max,
2668 adj_vdd_max_mv);
2669
2670 if (adj_vdd_max_mv < chip->max_voltage_mv) {
2671 pr_debug("adj vdd_max lower than default max voltage\n");
2672 return;
2673 }
2674
2675 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
2676 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
2677
2678 pr_debug("adjusting vdd_max_mv to %d to make "
2679 "vbat_batt_termial_uv = %d to %d\n",
2680 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
2681 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
2682}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002683
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002684enum {
2685 CHG_IN_PROGRESS,
2686 CHG_NOT_IN_PROGRESS,
2687 CHG_FINISHED,
2688};
2689
2690#define VBAT_TOLERANCE_MV 70
2691#define CHG_DISABLE_MSLEEP 100
2692static int is_charging_finished(struct pm8921_chg_chip *chip)
2693{
2694 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2695 int ichg_meas_ma, iterm_programmed;
2696 int regulation_loop, fast_chg, vcp;
2697 int rc;
2698 static int last_vbat_programmed = -EINVAL;
2699
2700 if (!is_ext_charging(chip)) {
2701 /* return if the battery is not being fastcharged */
2702 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2703 pr_debug("fast_chg = %d\n", fast_chg);
2704 if (fast_chg == 0)
2705 return CHG_NOT_IN_PROGRESS;
2706
2707 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2708 pr_debug("vcp = %d\n", vcp);
2709 if (vcp == 1)
2710 return CHG_IN_PROGRESS;
2711
2712 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2713 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2714 if (vbatdet_low == 1)
2715 return CHG_IN_PROGRESS;
2716
2717 /* reset count if battery is hot/cold */
2718 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2719 pr_debug("batt_temp_ok = %d\n", rc);
2720 if (rc == 0)
2721 return CHG_IN_PROGRESS;
2722
2723 /* reset count if battery voltage is less than vddmax */
2724 vbat_meas_uv = get_prop_battery_uvolts(chip);
2725 if (vbat_meas_uv < 0)
2726 return CHG_IN_PROGRESS;
2727 vbat_meas_mv = vbat_meas_uv / 1000;
2728
2729 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2730 if (rc) {
2731 pr_err("couldnt read vddmax rc = %d\n", rc);
2732 return CHG_IN_PROGRESS;
2733 }
2734 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2735 vbat_programmed, vbat_meas_mv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002736
2737 if (last_vbat_programmed == -EINVAL)
2738 last_vbat_programmed = vbat_programmed;
2739 if (last_vbat_programmed != vbat_programmed) {
2740 /* vddmax changed, reset and check again */
2741 pr_debug("vddmax = %d last_vdd_max=%d\n",
2742 vbat_programmed, last_vbat_programmed);
2743 last_vbat_programmed = vbat_programmed;
2744 return CHG_IN_PROGRESS;
2745 }
2746
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002747 regulation_loop = pm_chg_get_regulation_loop(chip);
2748 if (regulation_loop < 0) {
2749 pr_err("couldnt read the regulation loop err=%d\n",
2750 regulation_loop);
2751 return CHG_IN_PROGRESS;
2752 }
2753 pr_debug("regulation_loop=%d\n", regulation_loop);
2754
2755 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2756 return CHG_IN_PROGRESS;
2757 } /* !is_ext_charging */
2758
2759 /* reset count if battery chg current is more than iterm */
2760 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2761 if (rc) {
2762 pr_err("couldnt read iterm rc = %d\n", rc);
2763 return CHG_IN_PROGRESS;
2764 }
2765
2766 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2767 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2768 iterm_programmed, ichg_meas_ma);
2769 /*
2770 * ichg_meas_ma < 0 means battery is drawing current
2771 * ichg_meas_ma > 0 means battery is providing current
2772 */
2773 if (ichg_meas_ma > 0)
2774 return CHG_IN_PROGRESS;
2775
2776 if (ichg_meas_ma * -1 > iterm_programmed)
2777 return CHG_IN_PROGRESS;
2778
2779 return CHG_FINISHED;
2780}
2781
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002782/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002783 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002784 * has happened
2785 *
2786 * If all conditions favouring, if the charge current is
2787 * less than the term current for three consecutive times
2788 * an EOC has happened.
2789 * The wakelock is released if there is no need to reshedule
2790 * - this happens when the battery is removed or EOC has
2791 * happened
2792 */
2793#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002794static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002795{
2796 struct delayed_work *dwork = to_delayed_work(work);
2797 struct pm8921_chg_chip *chip = container_of(dwork,
2798 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002799 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002800 int end;
2801
2802 pm_chg_failed_clear(chip, 1);
2803 end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002804
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002805 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002806 count = 0;
2807 wake_unlock(&chip->eoc_wake_lock);
2808 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002809 }
2810
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002811 if (end == CHG_FINISHED) {
2812 count++;
2813 } else {
2814 count = 0;
2815 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002816
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002817 if (count == CONSECUTIVE_COUNT) {
2818 count = 0;
2819 pr_info("End of Charging\n");
2820
2821 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002822
Amir Samuelovd31ef502011-10-26 14:41:36 +02002823 if (is_ext_charging(chip))
2824 chip->ext_charge_done = true;
2825
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002826 if (chip->is_bat_warm || chip->is_bat_cool)
2827 chip->bms_notify.is_battery_full = 0;
2828 else
2829 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002830 /* declare end of charging by invoking chgdone interrupt */
2831 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2832 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002833 } else {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002834 adjust_vdd_max_for_fastchg(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002835 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002836 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002837 round_jiffies_relative(msecs_to_jiffies
2838 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002839 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002840}
2841
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002842static void btm_configure_work(struct work_struct *work)
2843{
2844 int rc;
2845
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002846 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002847 if (rc)
2848 pr_err("failed to configure btm rc=%d", rc);
2849}
2850
2851DECLARE_WORK(btm_config_work, btm_configure_work);
2852
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002853static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2854{
2855 unsigned int chg_current = chip->max_bat_chg_current;
2856
2857 if (chip->is_bat_cool)
2858 chg_current = min(chg_current, chip->cool_bat_chg_current);
2859
2860 if (chip->is_bat_warm)
2861 chg_current = min(chg_current, chip->warm_bat_chg_current);
2862
David Keitelfdef3a42011-12-14 19:02:54 -08002863 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002864 chg_current = min(chg_current,
2865 chip->thermal_mitigation[thermal_mitigation]);
2866
2867 pm_chg_ibatmax_set(the_chip, chg_current);
2868}
2869
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002870#define TEMP_HYSTERISIS_DEGC 2
2871static void battery_cool(bool enter)
2872{
2873 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002874 if (enter == the_chip->is_bat_cool)
2875 return;
2876 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002877 if (enter) {
2878 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002879 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002880 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002881 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002882 pm_chg_vbatdet_set(the_chip,
2883 the_chip->cool_bat_voltage
2884 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002885 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002886 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002887 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002888 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002889 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002890 the_chip->max_voltage_mv
2891 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002892 }
2893 schedule_work(&btm_config_work);
2894}
2895
2896static void battery_warm(bool enter)
2897{
2898 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002899 if (enter == the_chip->is_bat_warm)
2900 return;
2901 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002902 if (enter) {
2903 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002904 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002905 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002906 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002907 pm_chg_vbatdet_set(the_chip,
2908 the_chip->warm_bat_voltage
2909 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002910 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002911 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002912 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002913 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002914 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002915 the_chip->max_voltage_mv
2916 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002917 }
2918 schedule_work(&btm_config_work);
2919}
2920
2921static int configure_btm(struct pm8921_chg_chip *chip)
2922{
2923 int rc;
2924
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002925 if (chip->warm_temp_dc != INT_MIN)
2926 btm_config.btm_warm_fn = battery_warm;
2927 else
2928 btm_config.btm_warm_fn = NULL;
2929
2930 if (chip->cool_temp_dc != INT_MIN)
2931 btm_config.btm_cool_fn = battery_cool;
2932 else
2933 btm_config.btm_cool_fn = NULL;
2934
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002935 btm_config.low_thr_temp = chip->cool_temp_dc;
2936 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002937 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002938 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002939 if (rc)
2940 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002941 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002942 if (rc)
2943 pr_err("failed to start btm rc = %d\n", rc);
2944
2945 return rc;
2946}
2947
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002948/**
2949 * set_disable_status_param -
2950 *
2951 * Internal function to disable battery charging and also disable drawing
2952 * any current from the source. The device is forced to run on a battery
2953 * after this.
2954 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002955static int set_disable_status_param(const char *val, struct kernel_param *kp)
2956{
2957 int ret;
2958 struct pm8921_chg_chip *chip = the_chip;
2959
2960 ret = param_set_int(val, kp);
2961 if (ret) {
2962 pr_err("error setting value %d\n", ret);
2963 return ret;
2964 }
2965 pr_info("factory set disable param to %d\n", charging_disabled);
2966 if (chip) {
2967 pm_chg_auto_enable(chip, !charging_disabled);
2968 pm_chg_charge_dis(chip, charging_disabled);
2969 }
2970 return 0;
2971}
2972module_param_call(disabled, set_disable_status_param, param_get_uint,
2973 &charging_disabled, 0644);
2974
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08002975static int rconn_mohm;
2976static int set_rconn_mohm(const char *val, struct kernel_param *kp)
2977{
2978 int ret;
2979 struct pm8921_chg_chip *chip = the_chip;
2980
2981 ret = param_set_int(val, kp);
2982 if (ret) {
2983 pr_err("error setting value %d\n", ret);
2984 return ret;
2985 }
2986 if (chip)
2987 chip->rconn_mohm = rconn_mohm;
2988 return 0;
2989}
2990module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
2991 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002992/**
2993 * set_thermal_mitigation_level -
2994 *
2995 * Internal function to control battery charging current to reduce
2996 * temperature
2997 */
2998static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2999{
3000 int ret;
3001 struct pm8921_chg_chip *chip = the_chip;
3002
3003 ret = param_set_int(val, kp);
3004 if (ret) {
3005 pr_err("error setting value %d\n", ret);
3006 return ret;
3007 }
3008
3009 if (!chip) {
3010 pr_err("called before init\n");
3011 return -EINVAL;
3012 }
3013
3014 if (!chip->thermal_mitigation) {
3015 pr_err("no thermal mitigation\n");
3016 return -EINVAL;
3017 }
3018
3019 if (thermal_mitigation < 0
3020 || thermal_mitigation >= chip->thermal_levels) {
3021 pr_err("out of bound level selected\n");
3022 return -EINVAL;
3023 }
3024
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003025 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003026 return ret;
3027}
3028module_param_call(thermal_mitigation, set_therm_mitigation_level,
3029 param_get_uint,
3030 &thermal_mitigation, 0644);
3031
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003032static int set_usb_max_current(const char *val, struct kernel_param *kp)
3033{
3034 int ret, mA;
3035 struct pm8921_chg_chip *chip = the_chip;
3036
3037 ret = param_set_int(val, kp);
3038 if (ret) {
3039 pr_err("error setting value %d\n", ret);
3040 return ret;
3041 }
3042 if (chip) {
3043 pr_warn("setting current max to %d\n", usb_max_current);
3044 pm_chg_iusbmax_get(chip, &mA);
3045 if (mA > usb_max_current)
3046 pm8921_charger_vbus_draw(usb_max_current);
3047 return 0;
3048 }
3049 return -EINVAL;
3050}
David Keitelacf57c82012-03-07 18:48:50 -08003051module_param_call(usb_max_current, set_usb_max_current,
3052 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054static void free_irqs(struct pm8921_chg_chip *chip)
3055{
3056 int i;
3057
3058 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3059 if (chip->pmic_chg_irq[i]) {
3060 free_irq(chip->pmic_chg_irq[i], chip);
3061 chip->pmic_chg_irq[i] = 0;
3062 }
3063}
3064
David Keitel88e1b572012-01-11 11:57:14 -08003065/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3067{
3068 unsigned long flags;
3069 int fsm_state;
3070
3071 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3072 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3073
3074 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003075 if (chip->usb_present) {
3076 schedule_delayed_work(&chip->unplug_check_work,
3077 round_jiffies_relative(msecs_to_jiffies
3078 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08003079 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081
3082 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3083 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3084 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003085 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
3086 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
3087 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
3088 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3089 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003090 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003091 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3092 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08003093 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094
3095 spin_lock_irqsave(&vbus_lock, flags);
3096 if (usb_chg_current) {
3097 /* reissue a vbus draw call */
3098 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003099 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100 }
3101 spin_unlock_irqrestore(&vbus_lock, flags);
3102
3103 fsm_state = pm_chg_get_fsm_state(chip);
3104 if (is_battery_charging(fsm_state)) {
3105 chip->bms_notify.is_charging = 1;
3106 pm8921_bms_charging_began();
3107 }
3108
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003109 check_battery_valid(chip);
3110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003111 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3112 chip->usb_present,
3113 chip->dc_present,
3114 get_prop_batt_present(chip),
3115 fsm_state);
3116}
3117
3118struct pm_chg_irq_init_data {
3119 unsigned int irq_id;
3120 char *name;
3121 unsigned long flags;
3122 irqreturn_t (*handler)(int, void *);
3123};
3124
3125#define CHG_IRQ(_id, _flags, _handler) \
3126{ \
3127 .irq_id = _id, \
3128 .name = #_id, \
3129 .flags = _flags, \
3130 .handler = _handler, \
3131}
3132struct pm_chg_irq_init_data chg_irq_data[] = {
3133 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3134 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003135 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3137 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003138 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3139 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3141 usbin_uv_irq_handler),
3142 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3143 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3144 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3145 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3146 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3147 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3148 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3149 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3150 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003151 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3152 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003153 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3154 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3155 batt_removed_irq_handler),
3156 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3157 batttemp_hot_irq_handler),
3158 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3159 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3160 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003161 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3162 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003163 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3164 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3166 coarse_det_low_irq_handler),
3167 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3168 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3169 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3170 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3171 batfet_irq_handler),
3172 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3173 dcin_valid_irq_handler),
3174 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3175 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003176 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177};
3178
3179static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3180 struct platform_device *pdev)
3181{
3182 struct resource *res;
3183 int ret, i;
3184
3185 ret = 0;
3186 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3187
3188 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3189 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3190 chg_irq_data[i].name);
3191 if (res == NULL) {
3192 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3193 goto err_out;
3194 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003195 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196 ret = request_irq(res->start, chg_irq_data[i].handler,
3197 chg_irq_data[i].flags,
3198 chg_irq_data[i].name, chip);
3199 if (ret < 0) {
3200 pr_err("couldn't request %d (%s) %d\n", res->start,
3201 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003202 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203 goto err_out;
3204 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3206 }
3207 return 0;
3208
3209err_out:
3210 free_irqs(chip);
3211 return -EINVAL;
3212}
3213
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003214static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3215{
3216 int err;
3217 u8 temp;
3218
3219 temp = 0xD1;
3220 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3221 if (err) {
3222 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3223 return;
3224 }
3225
3226 temp = 0xD3;
3227 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3228 if (err) {
3229 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3230 return;
3231 }
3232
3233 temp = 0xD1;
3234 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3235 if (err) {
3236 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3237 return;
3238 }
3239
3240 temp = 0xD5;
3241 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3242 if (err) {
3243 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3244 return;
3245 }
3246
3247 udelay(183);
3248
3249 temp = 0xD1;
3250 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3251 if (err) {
3252 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3253 return;
3254 }
3255
3256 temp = 0xD0;
3257 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3258 if (err) {
3259 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3260 return;
3261 }
3262 udelay(32);
3263
3264 temp = 0xD1;
3265 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3266 if (err) {
3267 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3268 return;
3269 }
3270
3271 temp = 0xD3;
3272 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3273 if (err) {
3274 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3275 return;
3276 }
3277}
3278
3279static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3280{
3281 int err;
3282 u8 temp;
3283
3284 temp = 0xD1;
3285 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3286 if (err) {
3287 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3288 return;
3289 }
3290
3291 temp = 0xD0;
3292 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3293 if (err) {
3294 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3295 return;
3296 }
3297}
3298
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003299#define VREF_BATT_THERM_FORCE_ON BIT(7)
3300static void detect_battery_removal(struct pm8921_chg_chip *chip)
3301{
3302 u8 temp;
3303
3304 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3305 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3306
3307 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3308 /*
3309 * batt therm force on bit is battery backed and is default 0
3310 * The charger sets this bit at init time. If this bit is found
3311 * 0 that means the battery was removed. Tell the bms about it
3312 */
3313 pm8921_bms_invalidate_shutdown_soc();
3314}
3315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003316#define ENUM_TIMER_STOP_BIT BIT(1)
3317#define BOOT_DONE_BIT BIT(6)
3318#define CHG_BATFET_ON_BIT BIT(3)
3319#define CHG_VCP_EN BIT(0)
3320#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3321#define SAFE_CURRENT_MA 1500
3322static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3323{
3324 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003325 int vdd_safe;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003326
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07003327 /* forcing 19p2mhz before accessing any charger registers */
3328 pm8921_chg_force_19p2mhz_clk(chip);
3329
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003330 detect_battery_removal(chip);
3331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003332 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
3333 BOOT_DONE_BIT, BOOT_DONE_BIT);
3334 if (rc) {
3335 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3336 return rc;
3337 }
3338
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003339 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3340
3341 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3342 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3343
3344 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003346 if (rc) {
3347 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003348 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 return rc;
3350 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003351 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003352 chip->max_voltage_mv
3353 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 if (rc) {
3355 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003356 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357 return rc;
3358 }
3359
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003360 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 if (rc) {
3362 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003363 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003364 return rc;
3365 }
3366 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
3367 if (rc) {
3368 pr_err("Failed to set max voltage to %d rc=%d\n",
3369 SAFE_CURRENT_MA, rc);
3370 return rc;
3371 }
3372
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003373 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003374 if (rc) {
3375 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3376 return rc;
3377 }
3378
3379 rc = pm_chg_iterm_set(chip, chip->term_current);
3380 if (rc) {
3381 pr_err("Failed to set term current to %d rc=%d\n",
3382 chip->term_current, rc);
3383 return rc;
3384 }
3385
3386 /* Disable the ENUM TIMER */
3387 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3388 ENUM_TIMER_STOP_BIT);
3389 if (rc) {
3390 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3391 return rc;
3392 }
3393
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003394 if (chip->safety_time != 0) {
3395 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3396 if (rc) {
3397 pr_err("Failed to set max time to %d minutes rc=%d\n",
3398 chip->safety_time, rc);
3399 return rc;
3400 }
3401 }
3402
3403 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003404 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003405 if (rc) {
3406 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3407 chip->safety_time, rc);
3408 return rc;
3409 }
3410 }
3411
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003412 if (chip->vin_min != 0) {
3413 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3414 if (rc) {
3415 pr_err("Failed to set vin min to %d mV rc=%d\n",
3416 chip->vin_min, rc);
3417 return rc;
3418 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003419 } else {
3420 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003421 }
3422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 rc = pm_chg_disable_wd(chip);
3424 if (rc) {
3425 pr_err("Failed to disable wd rc=%d\n", rc);
3426 return rc;
3427 }
3428
3429 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3430 CHG_BAT_TEMP_DIS_BIT, 0);
3431 if (rc) {
3432 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3433 return rc;
3434 }
3435 /* switch to a 3.2Mhz for the buck */
3436 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3437 if (rc) {
3438 pr_err("Failed to switch buck clk rc=%d\n", rc);
3439 return rc;
3440 }
3441
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003442 if (chip->trkl_voltage != 0) {
3443 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3444 if (rc) {
3445 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3446 chip->trkl_voltage, rc);
3447 return rc;
3448 }
3449 }
3450
3451 if (chip->weak_voltage != 0) {
3452 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3453 if (rc) {
3454 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3455 chip->weak_voltage, rc);
3456 return rc;
3457 }
3458 }
3459
3460 if (chip->trkl_current != 0) {
3461 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3462 if (rc) {
3463 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3464 chip->trkl_voltage, rc);
3465 return rc;
3466 }
3467 }
3468
3469 if (chip->weak_current != 0) {
3470 rc = pm_chg_iweak_set(chip, chip->weak_current);
3471 if (rc) {
3472 pr_err("Failed to set weak current to %dmA rc=%d\n",
3473 chip->weak_current, rc);
3474 return rc;
3475 }
3476 }
3477
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003478 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3479 if (rc) {
3480 pr_err("Failed to set cold config %d rc=%d\n",
3481 chip->cold_thr, rc);
3482 }
3483
3484 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3485 if (rc) {
3486 pr_err("Failed to set hot config %d rc=%d\n",
3487 chip->hot_thr, rc);
3488 }
3489
Jay Chokshid674a512012-03-15 14:06:04 -07003490 rc = pm_chg_led_src_config(chip, chip->led_src_config);
3491 if (rc) {
3492 pr_err("Failed to set charger LED src config %d rc=%d\n",
3493 chip->led_src_config, rc);
3494 }
3495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496 /* Workarounds for die 1.1 and 1.0 */
3497 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3498 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003499 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3500 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003501
3502 /* software workaround for correct battery_id detection */
3503 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3504 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3505 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3506 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3507 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3508 udelay(100);
3509 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 }
3511
David Keitelb51995e2011-11-18 17:03:31 -08003512 /* Workarounds for die 3.0 */
3513 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3514 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3515
David Keitel38bdd4f2012-04-19 15:39:13 -07003516 /* Enable isub_fine resolution AICL for PM8917 */
3517 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3518 chip->iusb_fine_res = true;
3519
David Keitelb51995e2011-11-18 17:03:31 -08003520 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3521
David Keitela3c0d822011-11-03 14:18:52 -07003522 /* Disable EOC FSM processing */
3523 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3524
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003525 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3526 VREF_BATT_THERM_FORCE_ON);
3527 if (rc)
3528 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003530 rc = pm_chg_charge_dis(chip, charging_disabled);
3531 if (rc) {
3532 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3533 return rc;
3534 }
3535
3536 rc = pm_chg_auto_enable(chip, !charging_disabled);
3537 if (rc) {
3538 pr_err("Failed to enable charging rc=%d\n", rc);
3539 return rc;
3540 }
3541
3542 return 0;
3543}
3544
3545static int get_rt_status(void *data, u64 * val)
3546{
3547 int i = (int)data;
3548 int ret;
3549
3550 /* global irq number is passed in via data */
3551 ret = pm_chg_get_rt_status(the_chip, i);
3552 *val = ret;
3553 return 0;
3554}
3555DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3556
3557static int get_fsm_status(void *data, u64 * val)
3558{
3559 u8 temp;
3560
3561 temp = pm_chg_get_fsm_state(the_chip);
3562 *val = temp;
3563 return 0;
3564}
3565DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3566
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003567static int get_reg_loop(void *data, u64 * val)
3568{
3569 u8 temp;
3570
3571 if (!the_chip) {
3572 pr_err("%s called before init\n", __func__);
3573 return -EINVAL;
3574 }
3575 temp = pm_chg_get_regulation_loop(the_chip);
3576 *val = temp;
3577 return 0;
3578}
3579DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003581static int get_reg(void *data, u64 * val)
3582{
3583 int addr = (int)data;
3584 int ret;
3585 u8 temp;
3586
3587 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3588 if (ret) {
3589 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3590 addr, temp, ret);
3591 return -EAGAIN;
3592 }
3593 *val = temp;
3594 return 0;
3595}
3596
3597static int set_reg(void *data, u64 val)
3598{
3599 int addr = (int)data;
3600 int ret;
3601 u8 temp;
3602
3603 temp = (u8) val;
3604 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3605 if (ret) {
3606 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3607 addr, temp, ret);
3608 return -EAGAIN;
3609 }
3610 return 0;
3611}
3612DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3613
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003614enum {
3615 BAT_WARM_ZONE,
3616 BAT_COOL_ZONE,
3617};
3618static int get_warm_cool(void *data, u64 * val)
3619{
3620 if (!the_chip) {
3621 pr_err("%s called before init\n", __func__);
3622 return -EINVAL;
3623 }
3624 if ((int)data == BAT_WARM_ZONE)
3625 *val = the_chip->is_bat_warm;
3626 if ((int)data == BAT_COOL_ZONE)
3627 *val = the_chip->is_bat_cool;
3628 return 0;
3629}
3630DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003632static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3633{
3634 int i;
3635
3636 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3637
3638 if (IS_ERR(chip->dent)) {
3639 pr_err("pmic charger couldnt create debugfs dir\n");
3640 return;
3641 }
3642
3643 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3644 (void *)CHG_CNTRL, &reg_fops);
3645 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3646 (void *)CHG_CNTRL_2, &reg_fops);
3647 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3648 (void *)CHG_CNTRL_3, &reg_fops);
3649 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3650 (void *)PBL_ACCESS1, &reg_fops);
3651 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3652 (void *)PBL_ACCESS2, &reg_fops);
3653 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3654 (void *)SYS_CONFIG_1, &reg_fops);
3655 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3656 (void *)SYS_CONFIG_2, &reg_fops);
3657 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3658 (void *)CHG_VDD_MAX, &reg_fops);
3659 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3660 (void *)CHG_VDD_SAFE, &reg_fops);
3661 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3662 (void *)CHG_VBAT_DET, &reg_fops);
3663 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3664 (void *)CHG_IBAT_MAX, &reg_fops);
3665 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3666 (void *)CHG_IBAT_SAFE, &reg_fops);
3667 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3668 (void *)CHG_VIN_MIN, &reg_fops);
3669 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3670 (void *)CHG_VTRICKLE, &reg_fops);
3671 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3672 (void *)CHG_ITRICKLE, &reg_fops);
3673 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3674 (void *)CHG_ITERM, &reg_fops);
3675 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3676 (void *)CHG_TCHG_MAX, &reg_fops);
3677 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3678 (void *)CHG_TWDOG, &reg_fops);
3679 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3680 (void *)CHG_TEMP_THRESH, &reg_fops);
3681 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3682 (void *)CHG_COMP_OVR, &reg_fops);
3683 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3684 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3685 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3686 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3687 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3688 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3689 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3690 (void *)CHG_TEST, &reg_fops);
3691
3692 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3693 &fsm_fops);
3694
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003695 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3696 &reg_loop_fops);
3697
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003698 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3699 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3700 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3701 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003703 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3704 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3705 debugfs_create_file(chg_irq_data[i].name, 0444,
3706 chip->dent,
3707 (void *)chg_irq_data[i].irq_id,
3708 &rt_fops);
3709 }
3710}
3711
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003712static int pm8921_charger_suspend_noirq(struct device *dev)
3713{
3714 int rc;
3715 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3716
3717 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3718 if (rc)
3719 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3720 pm8921_chg_set_hw_clk_switching(chip);
3721 return 0;
3722}
3723
3724static int pm8921_charger_resume_noirq(struct device *dev)
3725{
3726 int rc;
3727 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3728
3729 pm8921_chg_force_19p2mhz_clk(chip);
3730
3731 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3732 VREF_BATT_THERM_FORCE_ON);
3733 if (rc)
3734 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3735 return 0;
3736}
3737
David Keitelf2226022011-12-13 15:55:50 -08003738static int pm8921_charger_resume(struct device *dev)
3739{
3740 int rc;
3741 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3742
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003743 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003744 && !(chip->keep_btm_on_suspend)) {
3745 rc = pm8xxx_adc_btm_configure(&btm_config);
3746 if (rc)
3747 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3748
3749 rc = pm8xxx_adc_btm_start();
3750 if (rc)
3751 pr_err("couldn't restart btm rc=%d\n", rc);
3752 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003753 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3754 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3755 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3756 }
David Keitelf2226022011-12-13 15:55:50 -08003757 return 0;
3758}
3759
3760static int pm8921_charger_suspend(struct device *dev)
3761{
3762 int rc;
3763 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3764
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003765 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003766 && !(chip->keep_btm_on_suspend)) {
3767 rc = pm8xxx_adc_btm_end();
3768 if (rc)
3769 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3770 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003771
3772 if (is_usb_chg_plugged_in(chip)) {
3773 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3774 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3775 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003776
David Keitelf2226022011-12-13 15:55:50 -08003777 return 0;
3778}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3780{
3781 int rc = 0;
3782 struct pm8921_chg_chip *chip;
3783 const struct pm8921_charger_platform_data *pdata
3784 = pdev->dev.platform_data;
3785
3786 if (!pdata) {
3787 pr_err("missing platform data\n");
3788 return -EINVAL;
3789 }
3790
3791 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3792 GFP_KERNEL);
3793 if (!chip) {
3794 pr_err("Cannot allocate pm_chg_chip\n");
3795 return -ENOMEM;
3796 }
3797
3798 chip->dev = &pdev->dev;
3799 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003800 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003802 chip->max_voltage_mv = pdata->max_voltage;
3803 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003804 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003805 chip->term_current = pdata->term_current;
3806 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003807 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003808 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3809 chip->batt_id_min = pdata->batt_id_min;
3810 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003811 if (pdata->cool_temp != INT_MIN)
3812 chip->cool_temp_dc = pdata->cool_temp * 10;
3813 else
3814 chip->cool_temp_dc = INT_MIN;
3815
3816 if (pdata->warm_temp != INT_MIN)
3817 chip->warm_temp_dc = pdata->warm_temp * 10;
3818 else
3819 chip->warm_temp_dc = INT_MIN;
3820
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003821 chip->temp_check_period = pdata->temp_check_period;
3822 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3823 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3824 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3825 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3826 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003827 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003828 chip->trkl_voltage = pdata->trkl_voltage;
3829 chip->weak_voltage = pdata->weak_voltage;
3830 chip->trkl_current = pdata->trkl_current;
3831 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003832 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003833 chip->thermal_mitigation = pdata->thermal_mitigation;
3834 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003835
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003836 chip->cold_thr = pdata->cold_thr;
3837 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003838 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07003839 chip->led_src_config = pdata->led_src_config;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003841 rc = pm8921_chg_hw_init(chip);
3842 if (rc) {
3843 pr_err("couldn't init hardware rc=%d\n", rc);
3844 goto free_chip;
3845 }
3846
3847 chip->usb_psy.name = "usb",
3848 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3849 chip->usb_psy.supplied_to = pm_power_supplied_to,
3850 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003851 chip->usb_psy.properties = pm_power_props_usb,
3852 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
3853 chip->usb_psy.get_property = pm_power_get_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854
David Keitel6ed71a52012-01-30 12:42:18 -08003855 chip->dc_psy.name = "pm8921-dc",
3856 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3857 chip->dc_psy.supplied_to = pm_power_supplied_to,
3858 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08003859 chip->dc_psy.properties = pm_power_props_mains,
3860 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
3861 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08003862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863 chip->batt_psy.name = "battery",
3864 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3865 chip->batt_psy.properties = msm_batt_power_props,
3866 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3867 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003868 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 rc = power_supply_register(chip->dev, &chip->usb_psy);
3870 if (rc < 0) {
3871 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003872 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003873 }
3874
David Keitel6ed71a52012-01-30 12:42:18 -08003875 rc = power_supply_register(chip->dev, &chip->dc_psy);
3876 if (rc < 0) {
3877 pr_err("power_supply_register usb failed rc = %d\n", rc);
3878 goto unregister_usb;
3879 }
3880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 rc = power_supply_register(chip->dev, &chip->batt_psy);
3882 if (rc < 0) {
3883 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003884 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885 }
3886
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003887 platform_set_drvdata(pdev, chip);
3888 the_chip = chip;
3889
3890 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003891 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08003892 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
3893 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003894 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896 rc = request_irqs(chip, pdev);
3897 if (rc) {
3898 pr_err("couldn't register interrupts rc=%d\n", rc);
3899 goto unregister_batt;
3900 }
3901
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003902 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3903 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3904 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003905 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3906 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003907 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003908 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003909 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003910 * care for jeita compliance
3911 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003912 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003913 rc = configure_btm(chip);
3914 if (rc) {
3915 pr_err("couldn't register with btm rc=%d\n", rc);
3916 goto free_irq;
3917 }
3918 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003919
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 create_debugfs_entries(chip);
3921
3922 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003923 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003925 /* determine what state the charger is in */
3926 determine_initial_state(chip);
3927
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003928 if (chip->update_time) {
3929 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3930 update_heartbeat);
3931 schedule_delayed_work(&chip->update_heartbeat_work,
3932 round_jiffies_relative(msecs_to_jiffies
3933 (chip->update_time)));
3934 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 return 0;
3936
3937free_irq:
3938 free_irqs(chip);
3939unregister_batt:
3940 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003941unregister_dc:
3942 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003943unregister_usb:
3944 power_supply_unregister(&chip->usb_psy);
3945free_chip:
3946 kfree(chip);
3947 return rc;
3948}
3949
3950static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3951{
3952 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3953
3954 free_irqs(chip);
3955 platform_set_drvdata(pdev, NULL);
3956 the_chip = NULL;
3957 kfree(chip);
3958 return 0;
3959}
David Keitelf2226022011-12-13 15:55:50 -08003960static const struct dev_pm_ops pm8921_pm_ops = {
3961 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003962 .suspend_noirq = pm8921_charger_suspend_noirq,
3963 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003964 .resume = pm8921_charger_resume,
3965};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003967 .probe = pm8921_charger_probe,
3968 .remove = __devexit_p(pm8921_charger_remove),
3969 .driver = {
3970 .name = PM8921_CHARGER_DEV_NAME,
3971 .owner = THIS_MODULE,
3972 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003973 },
3974};
3975
3976static int __init pm8921_charger_init(void)
3977{
3978 return platform_driver_register(&pm8921_charger_driver);
3979}
3980
3981static void __exit pm8921_charger_exit(void)
3982{
3983 platform_driver_unregister(&pm8921_charger_driver);
3984}
3985
3986late_initcall(pm8921_charger_init);
3987module_exit(pm8921_charger_exit);
3988
3989MODULE_LICENSE("GPL v2");
3990MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3991MODULE_VERSION("1.0");
3992MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);