blob: 65e923e69e2d57c99fc28cff1f749f56e1fb3a66 [file] [log] [blame]
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
24#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/delay.h>
26#include <linux/bitops.h>
27#include <linux/workqueue.h>
28#include <linux/debugfs.h>
29#include <linux/slab.h>
30
31#include <mach/msm_xo.h>
32#include <mach/msm_hsusb.h>
33
34#define CHG_BUCK_CLOCK_CTRL 0x14
35
36#define PBL_ACCESS1 0x04
37#define PBL_ACCESS2 0x05
38#define SYS_CONFIG_1 0x06
39#define SYS_CONFIG_2 0x07
40#define CHG_CNTRL 0x204
41#define CHG_IBAT_MAX 0x205
42#define CHG_TEST 0x206
43#define CHG_BUCK_CTRL_TEST1 0x207
44#define CHG_BUCK_CTRL_TEST2 0x208
45#define CHG_BUCK_CTRL_TEST3 0x209
46#define COMPARATOR_OVERRIDE 0x20A
47#define PSI_TXRX_SAMPLE_DATA_0 0x20B
48#define PSI_TXRX_SAMPLE_DATA_1 0x20C
49#define PSI_TXRX_SAMPLE_DATA_2 0x20D
50#define PSI_TXRX_SAMPLE_DATA_3 0x20E
51#define PSI_CONFIG_STATUS 0x20F
52#define CHG_IBAT_SAFE 0x210
53#define CHG_ITRICKLE 0x211
54#define CHG_CNTRL_2 0x212
55#define CHG_VBAT_DET 0x213
56#define CHG_VTRICKLE 0x214
57#define CHG_ITERM 0x215
58#define CHG_CNTRL_3 0x216
59#define CHG_VIN_MIN 0x217
60#define CHG_TWDOG 0x218
61#define CHG_TTRKL_MAX 0x219
62#define CHG_TEMP_THRESH 0x21A
63#define CHG_TCHG_MAX 0x21B
64#define USB_OVP_CONTROL 0x21C
65#define DC_OVP_CONTROL 0x21D
66#define USB_OVP_TEST 0x21E
67#define DC_OVP_TEST 0x21F
68#define CHG_VDD_MAX 0x220
69#define CHG_VDD_SAFE 0x221
70#define CHG_VBAT_BOOT_THRESH 0x222
71#define USB_OVP_TRIM 0x355
72#define BUCK_CONTROL_TRIM1 0x356
73#define BUCK_CONTROL_TRIM2 0x357
74#define BUCK_CONTROL_TRIM3 0x358
75#define BUCK_CONTROL_TRIM4 0x359
76#define CHG_DEFAULTS_TRIM 0x35A
77#define CHG_ITRIM 0x35B
78#define CHG_TTRIM 0x35C
79#define CHG_COMP_OVR 0x20A
80
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070081/* check EOC every 10 seconds */
82#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080083/* check for USB unplug every 200 msecs */
84#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086enum chg_fsm_state {
87 FSM_STATE_OFF_0 = 0,
88 FSM_STATE_BATFETDET_START_12 = 12,
89 FSM_STATE_BATFETDET_END_16 = 16,
90 FSM_STATE_ON_CHG_HIGHI_1 = 1,
91 FSM_STATE_ATC_2A = 2,
92 FSM_STATE_ATC_2B = 18,
93 FSM_STATE_ON_BAT_3 = 3,
94 FSM_STATE_ATC_FAIL_4 = 4 ,
95 FSM_STATE_DELAY_5 = 5,
96 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
97 FSM_STATE_FAST_CHG_7 = 7,
98 FSM_STATE_TRKL_CHG_8 = 8,
99 FSM_STATE_CHG_FAIL_9 = 9,
100 FSM_STATE_EOC_10 = 10,
101 FSM_STATE_ON_CHG_VREGOK_11 = 11,
102 FSM_STATE_ATC_PAUSE_13 = 13,
103 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
104 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
105 FSM_STATE_START_BOOT = 20,
106 FSM_STATE_FLCB_VREGOK = 21,
107 FSM_STATE_FLCB = 22,
108};
109
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700110struct fsm_state_to_batt_status {
111 enum chg_fsm_state fsm_state;
112 int batt_state;
113};
114
115static struct fsm_state_to_batt_status map[] = {
116 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
117 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
118 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
119 /*
120 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
121 * too hot/cold, charger too hot
122 */
123 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
124 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
125 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
126 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
127 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
128 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
129 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
130 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
131 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
132 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
133 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
134 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
135 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
136 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
137 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
138 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
139 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
140 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
141};
142
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700143enum chg_regulation_loop {
144 VDD_LOOP = BIT(3),
145 BAT_CURRENT_LOOP = BIT(2),
146 INPUT_CURRENT_LOOP = BIT(1),
147 INPUT_VOLTAGE_LOOP = BIT(0),
148 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
149 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
150};
151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152enum pmic_chg_interrupts {
153 USBIN_VALID_IRQ = 0,
154 USBIN_OV_IRQ,
155 BATT_INSERTED_IRQ,
156 VBATDET_LOW_IRQ,
157 USBIN_UV_IRQ,
158 VBAT_OV_IRQ,
159 CHGWDOG_IRQ,
160 VCP_IRQ,
161 ATCDONE_IRQ,
162 ATCFAIL_IRQ,
163 CHGDONE_IRQ,
164 CHGFAIL_IRQ,
165 CHGSTATE_IRQ,
166 LOOP_CHANGE_IRQ,
167 FASTCHG_IRQ,
168 TRKLCHG_IRQ,
169 BATT_REMOVED_IRQ,
170 BATTTEMP_HOT_IRQ,
171 CHGHOT_IRQ,
172 BATTTEMP_COLD_IRQ,
173 CHG_GONE_IRQ,
174 BAT_TEMP_OK_IRQ,
175 COARSE_DET_LOW_IRQ,
176 VDD_LOOP_IRQ,
177 VREG_OV_IRQ,
178 VBATDET_IRQ,
179 BATFET_IRQ,
180 PSI_IRQ,
181 DCIN_VALID_IRQ,
182 DCIN_OV_IRQ,
183 DCIN_UV_IRQ,
184 PM_CHG_MAX_INTS,
185};
186
187struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700188 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189 int is_charging;
190 struct work_struct work;
191};
192
193/**
194 * struct pm8921_chg_chip -device information
195 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 * @usb_present: present status of usb
197 * @dc_present: present status of dc
198 * @usb_charger_current: usb current to charge the battery with used when
199 * the usb path is enabled or charging is resumed
200 * @safety_time: max time for which charging will happen
201 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800202 * @max_voltage_mv: the max volts the batt should be charged up to
203 * @min_voltage_mv: the min battery voltage before turning the FETon
204 * @cool_temp_dc: the cool temp threshold in deciCelcius
205 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700206 * @resume_voltage_delta: the voltage delta from vdd max at which the
207 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @term_current: The charging based term current
209 *
210 */
211struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700212 struct device *dev;
213 unsigned int usb_present;
214 unsigned int dc_present;
215 unsigned int usb_charger_current;
216 unsigned int max_bat_chg_current;
217 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
218 unsigned int safety_time;
219 unsigned int ttrkl_time;
220 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800221 unsigned int max_voltage_mv;
222 unsigned int min_voltage_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800223 int cool_temp_dc;
224 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700225 unsigned int temp_check_period;
226 unsigned int cool_bat_chg_current;
227 unsigned int warm_bat_chg_current;
228 unsigned int cool_bat_voltage;
229 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700230 unsigned int is_bat_cool;
231 unsigned int is_bat_warm;
232 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700233 unsigned int term_current;
234 unsigned int vbat_channel;
235 unsigned int batt_temp_channel;
236 unsigned int batt_id_channel;
237 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800238 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800239 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700240 struct power_supply batt_psy;
241 struct dentry *dent;
242 struct bms_notify bms_notify;
David Keitelf2226022011-12-13 15:55:50 -0800243 bool keep_btm_on_suspend;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200244 bool ext_charging;
245 bool ext_charge_done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 struct work_struct battery_id_valid_work;
248 int64_t batt_id_min;
249 int64_t batt_id_max;
250 int trkl_voltage;
251 int weak_voltage;
252 int trkl_current;
253 int weak_current;
254 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800255 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700256 int thermal_levels;
257 struct delayed_work update_heartbeat_work;
258 struct delayed_work eoc_work;
David Keitel8c5201a2012-02-24 16:08:54 -0800259 struct work_struct unplug_ovp_fet_open_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800260 struct delayed_work unplug_check_work;
David Keitel8c5201a2012-02-24 16:08:54 -0800261 struct wake_lock unplug_ovp_fet_open_wake_lock;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct wake_lock eoc_wake_lock;
263 enum pm8921_chg_cold_thr cold_thr;
264 enum pm8921_chg_hot_thr hot_thr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265};
266
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800267static int usb_max_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700269static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271static struct pm8921_chg_chip *the_chip;
272
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700273static struct pm8xxx_adc_arb_btm_param btm_config;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
276 u8 mask, u8 val)
277{
278 int rc;
279 u8 reg;
280
281 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
282 if (rc) {
283 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
284 return rc;
285 }
286 reg &= ~mask;
287 reg |= val & mask;
288 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
289 if (rc) {
290 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
291 return rc;
292 }
293 return 0;
294}
295
David Keitelcf867232012-01-27 18:40:12 -0800296static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
297{
298 return pm8xxx_read_irq_stat(chip->dev->parent,
299 chip->pmic_chg_irq[irq_id]);
300}
301
302/* Treat OverVoltage/UnderVoltage as source missing */
303static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
304{
305 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
306}
307
308/* Treat OverVoltage/UnderVoltage as source missing */
309static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
310{
311 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
312}
313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314#define CAPTURE_FSM_STATE_CMD 0xC2
315#define READ_BANK_7 0x70
316#define READ_BANK_4 0x40
317static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
318{
319 u8 temp;
320 int err, ret = 0;
321
322 temp = CAPTURE_FSM_STATE_CMD;
323 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
324 if (err) {
325 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
326 return err;
327 }
328
329 temp = READ_BANK_7;
330 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
331 if (err) {
332 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
333 return err;
334 }
335
336 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
337 if (err) {
338 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
339 return err;
340 }
341 /* get the lower 4 bits */
342 ret = temp & 0xF;
343
344 temp = READ_BANK_4;
345 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
346 if (err) {
347 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
348 return err;
349 }
350
351 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
352 if (err) {
353 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
354 return err;
355 }
356 /* get the upper 1 bit */
357 ret |= (temp & 0x1) << 4;
358 return ret;
359}
360
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700361#define READ_BANK_6 0x60
362static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
363{
364 u8 temp;
365 int err;
366
367 temp = READ_BANK_6;
368 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
369 if (err) {
370 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
371 return err;
372 }
373
374 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
375 if (err) {
376 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
377 return err;
378 }
379
380 /* return the lower 4 bits */
381 return temp & CHG_ALL_LOOPS;
382}
383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384#define CHG_USB_SUSPEND_BIT BIT(2)
385static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
386{
387 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
388 enable ? CHG_USB_SUSPEND_BIT : 0);
389}
390
391#define CHG_EN_BIT BIT(7)
392static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
393{
394 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
395 enable ? CHG_EN_BIT : 0);
396}
397
David Keitel753ec8d2011-11-02 10:56:37 -0700398#define CHG_FAILED_CLEAR BIT(0)
399#define ATC_FAILED_CLEAR BIT(1)
400static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
401{
402 int rc;
403
404 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
405 clear ? ATC_FAILED_CLEAR : 0);
406 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
407 clear ? CHG_FAILED_CLEAR : 0);
408 return rc;
409}
410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411#define CHG_CHARGE_DIS_BIT BIT(1)
412static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
413{
414 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
415 disable ? CHG_CHARGE_DIS_BIT : 0);
416}
417
418#define PM8921_CHG_V_MIN_MV 3240
419#define PM8921_CHG_V_STEP_MV 20
David Keitelcf867232012-01-27 18:40:12 -0800420#define PM8921_CHG_V_STEP_10_MV_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421#define PM8921_CHG_VDDMAX_MAX 4500
422#define PM8921_CHG_VDDMAX_MIN 3400
423#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800424static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425{
David Keitelcf867232012-01-27 18:40:12 -0800426 int remainder, voltage_20_step;
427 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428
David Keitelcf867232012-01-27 18:40:12 -0800429 voltage_20_step = voltage;
430 remainder = voltage % 20;
431 if (remainder >= 10) {
432 voltage_20_step += 10;
433 temp = PM8921_CHG_V_STEP_10_MV_BIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 }
David Keitelcf867232012-01-27 18:40:12 -0800435
436 temp |= (voltage_20_step - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800438 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439}
440
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700441static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
442{
443 u8 temp;
444 int rc;
445
446 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
447 if (rc) {
448 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700449 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700450 return rc;
451 }
452 temp &= PM8921_CHG_V_MASK;
453 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
David Keitelcf867232012-01-27 18:40:12 -0800454 if (temp & PM8921_CHG_V_STEP_10_MV_BIT)
455 *voltage = *voltage - 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700456 return 0;
457}
458
David Keitelcf867232012-01-27 18:40:12 -0800459static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
460{
461 int current_mv, ret, steps, i;
462 bool increase;
463
464 ret = 0;
465
466 if (voltage < PM8921_CHG_VDDMAX_MIN
467 || voltage > PM8921_CHG_VDDMAX_MAX) {
468 pr_err("bad mV=%d asked to set\n", voltage);
469 return -EINVAL;
470 }
471
472 ret = pm_chg_vddmax_get(chip, &current_mv);
473 if (ret) {
474 pr_err("Failed to read vddmax rc=%d\n", ret);
475 return -EINVAL;
476 }
477 if (current_mv == voltage)
478 return 0;
479
480 /* Only change in increments when USB is present */
481 if (is_usb_chg_plugged_in(chip)) {
482 if (current_mv < voltage) {
483 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
484 increase = true;
485 } else {
486 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
487 increase = false;
488 }
489 for (i = 0; i < steps; i++) {
490 if (increase)
491 current_mv += PM8921_CHG_V_STEP_MV;
492 else
493 current_mv -= PM8921_CHG_V_STEP_MV;
494 ret |= __pm_chg_vddmax_set(chip, current_mv);
495 }
496 }
497 ret |= __pm_chg_vddmax_set(chip, voltage);
498 return ret;
499}
500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501#define PM8921_CHG_VDDSAFE_MIN 3400
502#define PM8921_CHG_VDDSAFE_MAX 4500
503static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
504{
505 u8 temp;
506
507 if (voltage < PM8921_CHG_VDDSAFE_MIN
508 || voltage > PM8921_CHG_VDDSAFE_MAX) {
509 pr_err("bad mV=%d asked to set\n", voltage);
510 return -EINVAL;
511 }
512 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
513 pr_debug("voltage=%d setting %02x\n", voltage, temp);
514 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
515}
516
517#define PM8921_CHG_VBATDET_MIN 3240
518#define PM8921_CHG_VBATDET_MAX 5780
519static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
520{
521 u8 temp;
522
523 if (voltage < PM8921_CHG_VBATDET_MIN
524 || voltage > PM8921_CHG_VBATDET_MAX) {
525 pr_err("bad mV=%d asked to set\n", voltage);
526 return -EINVAL;
527 }
528 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
529 pr_debug("voltage=%d setting %02x\n", voltage, temp);
530 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
531}
532
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700533#define PM8921_CHG_VINMIN_MIN_MV 3800
534#define PM8921_CHG_VINMIN_STEP_MV 100
535#define PM8921_CHG_VINMIN_USABLE_MAX 6500
536#define PM8921_CHG_VINMIN_USABLE_MIN 4300
537#define PM8921_CHG_VINMIN_MASK 0x1F
538static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
539{
540 u8 temp;
541
542 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
543 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
544 pr_err("bad mV=%d asked to set\n", voltage);
545 return -EINVAL;
546 }
547 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
548 pr_debug("voltage=%d setting %02x\n", voltage, temp);
549 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
550 temp);
551}
552
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800553static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
554{
555 u8 temp;
556 int rc, voltage_mv;
557
558 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
559 temp &= PM8921_CHG_VINMIN_MASK;
560
561 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
562 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
563
564 return voltage_mv;
565}
566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567#define PM8921_CHG_IBATMAX_MIN 325
568#define PM8921_CHG_IBATMAX_MAX 2000
569#define PM8921_CHG_I_MIN_MA 225
570#define PM8921_CHG_I_STEP_MA 50
571#define PM8921_CHG_I_MASK 0x3F
572static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
573{
574 u8 temp;
575
576 if (chg_current < PM8921_CHG_IBATMAX_MIN
577 || chg_current > PM8921_CHG_IBATMAX_MAX) {
578 pr_err("bad mA=%d asked to set\n", chg_current);
579 return -EINVAL;
580 }
581 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
582 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
583}
584
585#define PM8921_CHG_IBATSAFE_MIN 225
586#define PM8921_CHG_IBATSAFE_MAX 3375
587static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
588{
589 u8 temp;
590
591 if (chg_current < PM8921_CHG_IBATSAFE_MIN
592 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
593 pr_err("bad mA=%d asked to set\n", chg_current);
594 return -EINVAL;
595 }
596 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
597 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
598 PM8921_CHG_I_MASK, temp);
599}
600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700602#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603#define PM8921_CHG_ITERM_STEP_MA 10
604#define PM8921_CHG_ITERM_MASK 0xF
605static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
606{
607 u8 temp;
608
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700609 if (chg_current < PM8921_CHG_ITERM_MIN_MA
610 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 pr_err("bad mA=%d asked to set\n", chg_current);
612 return -EINVAL;
613 }
614
615 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
616 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700617 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 temp);
619}
620
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700621static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
622{
623 u8 temp;
624 int rc;
625
626 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
627 if (rc) {
628 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700629 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700630 return rc;
631 }
632 temp &= PM8921_CHG_ITERM_MASK;
633 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
634 + PM8921_CHG_ITERM_MIN_MA;
635 return 0;
636}
637
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800638struct usb_ma_limit_entry {
639 int usb_ma;
640 u8 chg_iusb_value;
641};
642
643static struct usb_ma_limit_entry usb_ma_table[] = {
644 {100, 0},
645 {500, 1},
646 {700, 2},
647 {850, 3},
648 {900, 4},
649 {1100, 5},
650 {1300, 6},
651 {1500, 7},
652};
653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654#define PM8921_CHG_IUSB_MASK 0x1C
655#define PM8921_CHG_IUSB_MAX 7
656#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700657static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658{
659 u8 temp;
660
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700661 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
662 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 return -EINVAL;
664 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700665 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
667 temp);
668}
669
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800670static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
671{
672 u8 temp;
673 int i, rc;
674
675 *mA = 0;
676 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
677 if (rc) {
678 pr_err("err=%d reading PBL_ACCESS2\n", rc);
679 return rc;
680 }
681 temp &= PM8921_CHG_IUSB_MASK;
682 temp = temp >> 2;
683 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
684 if (usb_ma_table[i].chg_iusb_value == temp)
685 *mA = usb_ma_table[i].usb_ma;
686 }
687 return rc;
688}
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690#define PM8921_CHG_WD_MASK 0x1F
691static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
692{
693 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700694 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
695}
696
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700697#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700698#define PM8921_CHG_TCHG_MIN 4
699#define PM8921_CHG_TCHG_MAX 512
700#define PM8921_CHG_TCHG_STEP 4
701static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
702{
703 u8 temp;
704
705 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
706 pr_err("bad max minutes =%d asked to set\n", minutes);
707 return -EINVAL;
708 }
709
710 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
711 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
712 temp);
713}
714
715#define PM8921_CHG_TTRKL_MASK 0x1F
716#define PM8921_CHG_TTRKL_MIN 1
717#define PM8921_CHG_TTRKL_MAX 64
718static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
719{
720 u8 temp;
721
722 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
723 pr_err("bad max minutes =%d asked to set\n", minutes);
724 return -EINVAL;
725 }
726
727 temp = minutes - 1;
728 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
729 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730}
731
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700732#define PM8921_CHG_VTRKL_MIN_MV 2050
733#define PM8921_CHG_VTRKL_MAX_MV 2800
734#define PM8921_CHG_VTRKL_STEP_MV 50
735#define PM8921_CHG_VTRKL_SHIFT 4
736#define PM8921_CHG_VTRKL_MASK 0xF0
737static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
738{
739 u8 temp;
740
741 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
742 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
743 pr_err("bad voltage = %dmV asked to set\n", millivolts);
744 return -EINVAL;
745 }
746
747 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
748 temp = temp << PM8921_CHG_VTRKL_SHIFT;
749 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
750 temp);
751}
752
753#define PM8921_CHG_VWEAK_MIN_MV 2100
754#define PM8921_CHG_VWEAK_MAX_MV 3600
755#define PM8921_CHG_VWEAK_STEP_MV 100
756#define PM8921_CHG_VWEAK_MASK 0x0F
757static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
758{
759 u8 temp;
760
761 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
762 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
763 pr_err("bad voltage = %dmV asked to set\n", millivolts);
764 return -EINVAL;
765 }
766
767 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
768 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
769 temp);
770}
771
772#define PM8921_CHG_ITRKL_MIN_MA 50
773#define PM8921_CHG_ITRKL_MAX_MA 200
774#define PM8921_CHG_ITRKL_MASK 0x0F
775#define PM8921_CHG_ITRKL_STEP_MA 10
776static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
777{
778 u8 temp;
779
780 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
781 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
782 pr_err("bad current = %dmA asked to set\n", milliamps);
783 return -EINVAL;
784 }
785
786 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
787
788 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
789 temp);
790}
791
792#define PM8921_CHG_IWEAK_MIN_MA 325
793#define PM8921_CHG_IWEAK_MAX_MA 525
794#define PM8921_CHG_IWEAK_SHIFT 7
795#define PM8921_CHG_IWEAK_MASK 0x80
796static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
797{
798 u8 temp;
799
800 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
801 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
802 pr_err("bad current = %dmA asked to set\n", milliamps);
803 return -EINVAL;
804 }
805
806 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
807 temp = 0;
808 else
809 temp = 1;
810
811 temp = temp << PM8921_CHG_IWEAK_SHIFT;
812 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
813 temp);
814}
815
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700816#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
817#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
818static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
819 enum pm8921_chg_cold_thr cold_thr)
820{
821 u8 temp;
822
823 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
824 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
825 return pm_chg_masked_write(chip, CHG_CNTRL_2,
826 PM8921_CHG_BATT_TEMP_THR_COLD,
827 temp);
828}
829
830#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
831#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
832static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
833 enum pm8921_chg_hot_thr hot_thr)
834{
835 u8 temp;
836
837 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
838 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
839 return pm_chg_masked_write(chip, CHG_CNTRL_2,
840 PM8921_CHG_BATT_TEMP_THR_HOT,
841 temp);
842}
843
David Keitel8c5201a2012-02-24 16:08:54 -0800844static void disable_input_voltage_regulation(struct pm8921_chg_chip *chip)
845{
846 u8 temp;
847 int rc;
848
849 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
850 if (rc) {
851 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
852 return;
853 }
854 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
855 if (rc) {
856 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
857 return;
858 }
859 /* set the input voltage disable bit and the write bit */
860 temp |= 0x81;
861 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
862 if (rc) {
863 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
864 return;
865 }
866}
867
868static void enable_input_voltage_regulation(struct pm8921_chg_chip *chip)
869{
870 u8 temp;
871 int rc;
872
873 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x70);
874 if (rc) {
875 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
876 return;
877 }
878 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
879 if (rc) {
880 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
881 return;
882 }
883 /* unset the input voltage disable bit */
884 temp &= 0xFE;
885 /* set the write bit */
886 temp |= 0x80;
887 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
888 if (rc) {
889 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
890 return;
891 }
892}
893
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700894static int64_t read_battery_id(struct pm8921_chg_chip *chip)
895{
896 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700897 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700898
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700899 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700900 if (rc) {
901 pr_err("error reading batt id channel = %d, rc = %d\n",
902 chip->vbat_channel, rc);
903 return rc;
904 }
905 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
906 result.measurement);
907 return result.physical;
908}
909
910static int is_battery_valid(struct pm8921_chg_chip *chip)
911{
912 int64_t rc;
913
914 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
915 return 1;
916
917 rc = read_battery_id(chip);
918 if (rc < 0) {
919 pr_err("error reading batt id channel = %d, rc = %lld\n",
920 chip->vbat_channel, rc);
921 /* assume battery id is valid when adc error happens */
922 return 1;
923 }
924
925 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
926 pr_err("batt_id phy =%lld is not valid\n", rc);
927 return 0;
928 }
929 return 1;
930}
931
932static void check_battery_valid(struct pm8921_chg_chip *chip)
933{
934 if (is_battery_valid(chip) == 0) {
935 pr_err("batt_id not valid, disbling charging\n");
936 pm_chg_auto_enable(chip, 0);
937 } else {
938 pm_chg_auto_enable(chip, !charging_disabled);
939 }
940}
941
942static void battery_id_valid(struct work_struct *work)
943{
944 struct pm8921_chg_chip *chip = container_of(work,
945 struct pm8921_chg_chip, battery_id_valid_work);
946
947 check_battery_valid(chip);
948}
949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
951{
952 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
953 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
954 enable_irq(chip->pmic_chg_irq[interrupt]);
955 }
956}
957
958static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
959{
960 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
961 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
962 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
963 }
964}
965
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800966static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
967{
968 return test_bit(interrupt, chip->enabled_irqs);
969}
970
Amir Samuelovd31ef502011-10-26 14:41:36 +0200971static bool is_ext_charging(struct pm8921_chg_chip *chip)
972{
David Keitel88e1b572012-01-11 11:57:14 -0800973 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200974
David Keitel88e1b572012-01-11 11:57:14 -0800975 if (!chip->ext_psy)
976 return false;
977 if (chip->ext_psy->get_property(chip->ext_psy,
978 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
979 return false;
980 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
981 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200982
983 return false;
984}
985
986static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
987{
David Keitel88e1b572012-01-11 11:57:14 -0800988 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200989
David Keitel88e1b572012-01-11 11:57:14 -0800990 if (!chip->ext_psy)
991 return false;
992 if (chip->ext_psy->get_property(chip->ext_psy,
993 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
994 return false;
995 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +0200996 return true;
997
998 return false;
999}
1000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001static int is_battery_charging(int fsm_state)
1002{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001003 if (is_ext_charging(the_chip))
1004 return 1;
1005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 switch (fsm_state) {
1007 case FSM_STATE_ATC_2A:
1008 case FSM_STATE_ATC_2B:
1009 case FSM_STATE_ON_CHG_AND_BAT_6:
1010 case FSM_STATE_FAST_CHG_7:
1011 case FSM_STATE_TRKL_CHG_8:
1012 return 1;
1013 }
1014 return 0;
1015}
1016
1017static void bms_notify(struct work_struct *work)
1018{
1019 struct bms_notify *n = container_of(work, struct bms_notify, work);
1020
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001021 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001023 } else {
1024 pm8921_bms_charging_end(n->is_battery_full);
1025 n->is_battery_full = 0;
1026 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027}
1028
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001029static void bms_notify_check(struct pm8921_chg_chip *chip)
1030{
1031 int fsm_state, new_is_charging;
1032
1033 fsm_state = pm_chg_get_fsm_state(chip);
1034 new_is_charging = is_battery_charging(fsm_state);
1035
1036 if (chip->bms_notify.is_charging ^ new_is_charging) {
1037 chip->bms_notify.is_charging = new_is_charging;
1038 schedule_work(&(chip->bms_notify.work));
1039 }
1040}
1041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042static enum power_supply_property pm_power_props[] = {
1043 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001044 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045};
1046
1047static char *pm_power_supplied_to[] = {
1048 "battery",
1049};
1050
David Keitel6ed71a52012-01-30 12:42:18 -08001051#define USB_WALL_THRESHOLD_MA 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052static int pm_power_get_property(struct power_supply *psy,
1053 enum power_supply_property psp,
1054 union power_supply_propval *val)
1055{
David Keitel6ed71a52012-01-30 12:42:18 -08001056 int current_max;
1057
1058 /* Check if called before init */
1059 if (!the_chip)
1060 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061
1062 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001063 case POWER_SUPPLY_PROP_CURRENT_MAX:
1064 pm_chg_iusbmax_get(the_chip, &current_max);
1065 val->intval = current_max;
1066 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001068 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001069 val->intval = 0;
1070 if (charging_disabled)
1071 return 0;
1072
1073 /* USB charging */
1074 if (psy->type == POWER_SUPPLY_TYPE_USB ||
David Keitel6ed71a52012-01-30 12:42:18 -08001075 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
1076 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
1077 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
David Keitel63f71662012-02-08 20:30:00 -08001078 val->intval = is_usb_chg_plugged_in(the_chip);
1079 return 0;
1080 }
1081
1082 /* DC charging */
1083 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
1084 /* external charger is connected */
1085 if (the_chip->dc_present || is_ext_charging(the_chip)) {
1086 val->intval = 1;
1087 return 0;
1088 }
1089 /* USB with max current greater than 500 mA connected */
David Keitel6ed71a52012-01-30 12:42:18 -08001090 pm_chg_iusbmax_get(the_chip, &current_max);
1091 if (current_max > USB_WALL_THRESHOLD_MA)
David Keitel63f71662012-02-08 20:30:00 -08001092 val->intval = is_usb_chg_plugged_in(the_chip);
1093 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 }
David Keitel63f71662012-02-08 20:30:00 -08001095
1096 pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 break;
1098 default:
1099 return -EINVAL;
1100 }
1101 return 0;
1102}
1103
1104static enum power_supply_property msm_batt_power_props[] = {
1105 POWER_SUPPLY_PROP_STATUS,
1106 POWER_SUPPLY_PROP_CHARGE_TYPE,
1107 POWER_SUPPLY_PROP_HEALTH,
1108 POWER_SUPPLY_PROP_PRESENT,
1109 POWER_SUPPLY_PROP_TECHNOLOGY,
1110 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1111 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1112 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1113 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001114 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001115 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001116 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117};
1118
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001119static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001120{
1121 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001122 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001123
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001124 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 if (rc) {
1126 pr_err("error reading adc channel = %d, rc = %d\n",
1127 chip->vbat_channel, rc);
1128 return rc;
1129 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001130 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131 result.measurement);
1132 return (int)result.physical;
1133}
1134
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001135static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1136{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001137 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1138 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1139 unsigned int low_voltage = chip->min_voltage_mv;
1140 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001141
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001142 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001143 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001144 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001145 return 100;
1146 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001147 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001148 / (high_voltage - low_voltage);
1149}
1150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1152{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001153 int percent_soc = pm8921_bms_get_percent_charge();
1154
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001155 if (percent_soc == -ENXIO)
1156 percent_soc = voltage_based_capacity(chip);
1157
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001158 if (percent_soc <= 10)
1159 pr_warn("low battery charge = %d%%\n", percent_soc);
1160
1161 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162}
1163
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001164static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1165{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001166 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001167
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001168 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001169 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001170 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001171 }
1172
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001173 if (rc) {
1174 pr_err("unable to get batt current rc = %d\n", rc);
1175 return rc;
1176 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001177 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001178 }
1179}
1180
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001181static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1182{
1183 int rc;
1184
1185 rc = pm8921_bms_get_fcc();
1186 if (rc < 0)
1187 pr_err("unable to get batt fcc rc = %d\n", rc);
1188 return rc;
1189}
1190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1192{
1193 int temp;
1194
1195 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1196 if (temp)
1197 return POWER_SUPPLY_HEALTH_OVERHEAT;
1198
1199 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1200 if (temp)
1201 return POWER_SUPPLY_HEALTH_COLD;
1202
1203 return POWER_SUPPLY_HEALTH_GOOD;
1204}
1205
1206static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1207{
1208 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1209}
1210
1211static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1212{
1213 int temp;
1214
Amir Samuelovd31ef502011-10-26 14:41:36 +02001215 if (!get_prop_batt_present(chip))
1216 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1217
1218 if (is_ext_trickle_charging(chip))
1219 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1220
1221 if (is_ext_charging(chip))
1222 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001224 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1225 if (temp)
1226 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1227
1228 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1229 if (temp)
1230 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1231
1232 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1233}
1234
1235static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1236{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001237 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1238 int fsm_state = pm_chg_get_fsm_state(chip);
1239 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240
David Keitel88e1b572012-01-11 11:57:14 -08001241 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001242 if (chip->ext_charge_done)
1243 return POWER_SUPPLY_STATUS_FULL;
1244 if (chip->ext_charging)
1245 return POWER_SUPPLY_STATUS_CHARGING;
1246 }
1247
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001248 for (i = 0; i < ARRAY_SIZE(map); i++)
1249 if (map[i].fsm_state == fsm_state)
1250 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001251
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001252 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1253 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1254 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001255 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1256 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001257
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001258 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001259 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001260 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261}
1262
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001263#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001264static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1265{
1266 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001267 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001268
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001269 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001270 if (rc) {
1271 pr_err("error reading adc channel = %d, rc = %d\n",
1272 chip->vbat_channel, rc);
1273 return rc;
1274 }
1275 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1276 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001277 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1278 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1279 (int) result.physical);
1280
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001281 return (int)result.physical;
1282}
1283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284static int pm_batt_power_get_property(struct power_supply *psy,
1285 enum power_supply_property psp,
1286 union power_supply_propval *val)
1287{
1288 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1289 batt_psy);
1290
1291 switch (psp) {
1292 case POWER_SUPPLY_PROP_STATUS:
1293 val->intval = get_prop_batt_status(chip);
1294 break;
1295 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1296 val->intval = get_prop_charge_type(chip);
1297 break;
1298 case POWER_SUPPLY_PROP_HEALTH:
1299 val->intval = get_prop_batt_health(chip);
1300 break;
1301 case POWER_SUPPLY_PROP_PRESENT:
1302 val->intval = get_prop_batt_present(chip);
1303 break;
1304 case POWER_SUPPLY_PROP_TECHNOLOGY:
1305 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1306 break;
1307 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001308 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001309 break;
1310 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001311 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 break;
1313 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001314 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 break;
1316 case POWER_SUPPLY_PROP_CAPACITY:
1317 val->intval = get_prop_batt_capacity(chip);
1318 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001319 case POWER_SUPPLY_PROP_CURRENT_NOW:
1320 val->intval = get_prop_batt_current(chip);
1321 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001322 case POWER_SUPPLY_PROP_TEMP:
1323 val->intval = get_prop_batt_temp(chip);
1324 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001325 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001326 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001327 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 default:
1329 return -EINVAL;
1330 }
1331
1332 return 0;
1333}
1334
1335static void (*notify_vbus_state_func_ptr)(int);
1336static int usb_chg_current;
1337static DEFINE_SPINLOCK(vbus_lock);
1338
1339int pm8921_charger_register_vbus_sn(void (*callback)(int))
1340{
1341 pr_debug("%p\n", callback);
1342 notify_vbus_state_func_ptr = callback;
1343 return 0;
1344}
1345EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1346
1347/* this is passed to the hsusb via platform_data msm_otg_pdata */
1348void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1349{
1350 pr_debug("%p\n", callback);
1351 notify_vbus_state_func_ptr = NULL;
1352}
1353EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1354
1355static void notify_usb_of_the_plugin_event(int plugin)
1356{
1357 plugin = !!plugin;
1358 if (notify_vbus_state_func_ptr) {
1359 pr_debug("notifying plugin\n");
1360 (*notify_vbus_state_func_ptr) (plugin);
1361 } else {
1362 pr_debug("unable to notify plugin\n");
1363 }
1364}
1365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366/* assumes vbus_lock is held */
1367static void __pm8921_charger_vbus_draw(unsigned int mA)
1368{
1369 int i, rc;
1370
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001371 if (usb_max_current && mA > usb_max_current) {
1372 pr_warn("restricting usb current to %d instead of %d\n",
1373 usb_max_current, mA);
1374 mA = usb_max_current;
1375 }
1376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 if (mA > 0 && mA <= 2) {
1378 usb_chg_current = 0;
1379 rc = pm_chg_iusbmax_set(the_chip,
1380 usb_ma_table[0].chg_iusb_value);
1381 if (rc) {
1382 pr_err("unable to set iusb to %d rc = %d\n",
1383 usb_ma_table[0].chg_iusb_value, rc);
1384 }
1385 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1386 if (rc)
1387 pr_err("fail to set suspend bit rc=%d\n", rc);
1388 } else {
1389 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1390 if (rc)
1391 pr_err("fail to reset suspend bit rc=%d\n", rc);
1392 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1393 if (usb_ma_table[i].usb_ma <= mA)
1394 break;
1395 }
1396 if (i < 0)
1397 i = 0;
1398 rc = pm_chg_iusbmax_set(the_chip,
1399 usb_ma_table[i].chg_iusb_value);
1400 if (rc) {
1401 pr_err("unable to set iusb to %d rc = %d\n",
1402 usb_ma_table[i].chg_iusb_value, rc);
1403 }
1404 }
1405}
1406
1407/* USB calls these to tell us how much max usb current the system can draw */
1408void pm8921_charger_vbus_draw(unsigned int mA)
1409{
1410 unsigned long flags;
1411
1412 pr_debug("Enter charge=%d\n", mA);
1413 spin_lock_irqsave(&vbus_lock, flags);
1414 if (the_chip) {
1415 __pm8921_charger_vbus_draw(mA);
1416 } else {
1417 /*
1418 * called before pmic initialized,
1419 * save this value and use it at probe
1420 */
1421 usb_chg_current = mA;
1422 }
1423 spin_unlock_irqrestore(&vbus_lock, flags);
1424}
1425EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1426
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001427int pm8921_charger_enable(bool enable)
1428{
1429 int rc;
1430
1431 if (!the_chip) {
1432 pr_err("called before init\n");
1433 return -EINVAL;
1434 }
1435 enable = !!enable;
1436 rc = pm_chg_auto_enable(the_chip, enable);
1437 if (rc)
1438 pr_err("Failed rc=%d\n", rc);
1439 return rc;
1440}
1441EXPORT_SYMBOL(pm8921_charger_enable);
1442
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001443int pm8921_is_usb_chg_plugged_in(void)
1444{
1445 if (!the_chip) {
1446 pr_err("called before init\n");
1447 return -EINVAL;
1448 }
1449 return is_usb_chg_plugged_in(the_chip);
1450}
1451EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1452
1453int pm8921_is_dc_chg_plugged_in(void)
1454{
1455 if (!the_chip) {
1456 pr_err("called before init\n");
1457 return -EINVAL;
1458 }
1459 return is_dc_chg_plugged_in(the_chip);
1460}
1461EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1462
1463int pm8921_is_battery_present(void)
1464{
1465 if (!the_chip) {
1466 pr_err("called before init\n");
1467 return -EINVAL;
1468 }
1469 return get_prop_batt_present(the_chip);
1470}
1471EXPORT_SYMBOL(pm8921_is_battery_present);
1472
David Keitel012deef2011-12-02 11:49:33 -08001473/*
1474 * Disabling the charge current limit causes current
1475 * current limits to have no monitoring. An adequate charger
1476 * capable of supplying high current while sustaining VIN_MIN
1477 * is required if the limiting is disabled.
1478 */
1479int pm8921_disable_input_current_limit(bool disable)
1480{
1481 if (!the_chip) {
1482 pr_err("called before init\n");
1483 return -EINVAL;
1484 }
1485 if (disable) {
1486 pr_warn("Disabling input current limit!\n");
1487
1488 return pm8xxx_writeb(the_chip->dev->parent,
1489 CHG_BUCK_CTRL_TEST3, 0xF2);
1490 }
1491 return 0;
1492}
1493EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1494
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001495int pm8921_set_max_battery_charge_current(int ma)
1496{
1497 if (!the_chip) {
1498 pr_err("called before init\n");
1499 return -EINVAL;
1500 }
1501 return pm_chg_ibatmax_set(the_chip, ma);
1502}
1503EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1504
1505int pm8921_disable_source_current(bool disable)
1506{
1507 if (!the_chip) {
1508 pr_err("called before init\n");
1509 return -EINVAL;
1510 }
1511 if (disable)
1512 pr_warn("current drawn from chg=0, battery provides current\n");
1513 return pm_chg_charge_dis(the_chip, disable);
1514}
1515EXPORT_SYMBOL(pm8921_disable_source_current);
1516
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001517int pm8921_regulate_input_voltage(int voltage)
1518{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001519 int rc;
1520
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001521 if (!the_chip) {
1522 pr_err("called before init\n");
1523 return -EINVAL;
1524 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001525 rc = pm_chg_vinmin_set(the_chip, voltage);
1526
1527 if (rc == 0)
1528 the_chip->vin_min = voltage;
1529
1530 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001531}
1532
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001533#define USB_OV_THRESHOLD_MASK 0x60
1534#define USB_OV_THRESHOLD_SHIFT 5
1535int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1536{
1537 u8 temp;
1538
1539 if (!the_chip) {
1540 pr_err("called before init\n");
1541 return -EINVAL;
1542 }
1543
1544 if (ov > PM_USB_OV_7V) {
1545 pr_err("limiting to over voltage threshold to 7volts\n");
1546 ov = PM_USB_OV_7V;
1547 }
1548
1549 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1550
1551 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1552 USB_OV_THRESHOLD_MASK, temp);
1553}
1554EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1555
1556#define USB_DEBOUNCE_TIME_MASK 0x06
1557#define USB_DEBOUNCE_TIME_SHIFT 1
1558int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1559{
1560 u8 temp;
1561
1562 if (!the_chip) {
1563 pr_err("called before init\n");
1564 return -EINVAL;
1565 }
1566
1567 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1568 pr_err("limiting debounce to 80.5ms\n");
1569 ms = PM_USB_DEBOUNCE_80P5MS;
1570 }
1571
1572 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1573
1574 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1575 USB_DEBOUNCE_TIME_MASK, temp);
1576}
1577EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1578
1579#define USB_OVP_DISABLE_MASK 0x80
1580int pm8921_usb_ovp_disable(int disable)
1581{
1582 u8 temp = 0;
1583
1584 if (!the_chip) {
1585 pr_err("called before init\n");
1586 return -EINVAL;
1587 }
1588
1589 if (disable)
1590 temp = USB_OVP_DISABLE_MASK;
1591
1592 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1593 USB_OVP_DISABLE_MASK, temp);
1594}
1595
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001596bool pm8921_is_battery_charging(int *source)
1597{
1598 int fsm_state, is_charging, dc_present, usb_present;
1599
1600 if (!the_chip) {
1601 pr_err("called before init\n");
1602 return -EINVAL;
1603 }
1604 fsm_state = pm_chg_get_fsm_state(the_chip);
1605 is_charging = is_battery_charging(fsm_state);
1606 if (is_charging == 0) {
1607 *source = PM8921_CHG_SRC_NONE;
1608 return is_charging;
1609 }
1610
1611 if (source == NULL)
1612 return is_charging;
1613
1614 /* the battery is charging, the source is requested, find it */
1615 dc_present = is_dc_chg_plugged_in(the_chip);
1616 usb_present = is_usb_chg_plugged_in(the_chip);
1617
1618 if (dc_present && !usb_present)
1619 *source = PM8921_CHG_SRC_DC;
1620
1621 if (usb_present && !dc_present)
1622 *source = PM8921_CHG_SRC_USB;
1623
1624 if (usb_present && dc_present)
1625 /*
1626 * The system always chooses dc for charging since it has
1627 * higher priority.
1628 */
1629 *source = PM8921_CHG_SRC_DC;
1630
1631 return is_charging;
1632}
1633EXPORT_SYMBOL(pm8921_is_battery_charging);
1634
David Keitel6df9cea2011-12-21 12:36:45 -08001635int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1636{
1637 if (!the_chip) {
1638 pr_err("called before init\n");
1639 return -EINVAL;
1640 }
1641
1642 if (type < POWER_SUPPLY_TYPE_USB)
1643 return -EINVAL;
1644
1645 the_chip->usb_psy.type = type;
1646 power_supply_changed(&the_chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001647 power_supply_changed(&the_chip->dc_psy);
David Keitel6df9cea2011-12-21 12:36:45 -08001648 return 0;
1649}
1650EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1651
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001652int pm8921_batt_temperature(void)
1653{
1654 if (!the_chip) {
1655 pr_err("called before init\n");
1656 return -EINVAL;
1657 }
1658 return get_prop_batt_temp(the_chip);
1659}
1660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1662{
1663 int usb_present;
1664
1665 usb_present = is_usb_chg_plugged_in(chip);
1666 if (chip->usb_present ^ usb_present) {
1667 notify_usb_of_the_plugin_event(usb_present);
1668 chip->usb_present = usb_present;
1669 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001670 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001671 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001672 if (usb_present) {
1673 schedule_delayed_work(&chip->unplug_check_work,
1674 round_jiffies_relative(msecs_to_jiffies
1675 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08001676 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
1677 } else {
1678 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001679 }
David Keitel8c5201a2012-02-24 16:08:54 -08001680 enable_input_voltage_regulation(chip);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001681 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682}
1683
Amir Samuelovd31ef502011-10-26 14:41:36 +02001684static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1685{
David Keitel88e1b572012-01-11 11:57:14 -08001686 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001687 pr_debug("external charger not registered.\n");
1688 return;
1689 }
1690
1691 if (!chip->ext_charging) {
1692 pr_debug("already not charging.\n");
1693 return;
1694 }
1695
David Keitel88e1b572012-01-11 11:57:14 -08001696 power_supply_set_charge_type(chip->ext_psy,
1697 POWER_SUPPLY_CHARGE_TYPE_NONE);
1698 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001699 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001700 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001701 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001702 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001703}
1704
1705static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1706{
1707 int dc_present;
1708 int batt_present;
1709 int batt_temp_ok;
1710 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001711 unsigned long delay =
1712 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1713
David Keitel88e1b572012-01-11 11:57:14 -08001714 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001715 pr_debug("external charger not registered.\n");
1716 return;
1717 }
1718
1719 if (chip->ext_charging) {
1720 pr_debug("already charging.\n");
1721 return;
1722 }
1723
David Keitel88e1b572012-01-11 11:57:14 -08001724 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001725 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1726 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001727
1728 if (!dc_present) {
1729 pr_warn("%s. dc not present.\n", __func__);
1730 return;
1731 }
1732 if (!batt_present) {
1733 pr_warn("%s. battery not present.\n", __func__);
1734 return;
1735 }
1736 if (!batt_temp_ok) {
1737 pr_warn("%s. battery temperature not ok.\n", __func__);
1738 return;
1739 }
David Keitel88e1b572012-01-11 11:57:14 -08001740 pm8921_disable_source_current(true); /* Force BATFET=ON */
1741 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001742 if (vbat_ov) {
1743 pr_warn("%s. battery over voltage.\n", __func__);
1744 return;
1745 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001746
David Keitel63f71662012-02-08 20:30:00 -08001747 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001748 power_supply_set_charge_type(chip->ext_psy,
1749 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001750 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001751 chip->ext_charging = true;
1752 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001753 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001754 /* Start BMS */
1755 schedule_delayed_work(&chip->eoc_work, delay);
1756 wake_lock(&chip->eoc_wake_lock);
1757}
1758
David Keitel8c5201a2012-02-24 16:08:54 -08001759static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001760{
1761 u8 temp;
1762 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001763
David Keitel8c5201a2012-02-24 16:08:54 -08001764 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001765 if (rc) {
David Keitel8c5201a2012-02-24 16:08:54 -08001766 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1767 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001768 }
David Keitel8c5201a2012-02-24 16:08:54 -08001769 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1770 if (rc) {
1771 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1772 return;
1773 }
1774 /* set ovp fet disable bit and the write bit */
1775 temp |= 0x81;
1776 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1777 if (rc) {
1778 pr_err("Failed to write 0x%x USB_OVP_TEST rc=%d\n", temp, rc);
1779 return;
1780 }
1781}
1782
1783static void turn_on_usb_ovp_fet(struct pm8921_chg_chip *chip)
1784{
1785 u8 temp;
1786 int rc;
1787
1788 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0x30);
1789 if (rc) {
1790 pr_err("Failed to write 0x30 to USB_OVP_TEST rc = %d\n", rc);
1791 return;
1792 }
1793 rc = pm8xxx_readb(chip->dev->parent, USB_OVP_TEST, &temp);
1794 if (rc) {
1795 pr_err("Failed to read from USB_OVP_TEST rc = %d\n", rc);
1796 return;
1797 }
1798 /* unset ovp fet disable bit and set the write bit */
1799 temp &= 0xFE;
1800 temp |= 0x80;
1801 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, temp);
1802 if (rc) {
1803 pr_err("Failed to write 0x%x to USB_OVP_TEST rc = %d\n",
1804 temp, rc);
1805 return;
1806 }
1807}
1808
1809static int param_open_ovp_counter = 10;
1810module_param(param_open_ovp_counter, int, 0644);
1811
1812#define WRITE_BANK_4 0xC0
1813#define USB_OVP_DEBOUNCE_TIME 0x06
1814static void unplug_ovp_fet_open_worker(struct work_struct *work)
1815{
1816 struct pm8921_chg_chip *chip = container_of(work,
1817 struct pm8921_chg_chip,
1818 unplug_ovp_fet_open_work);
1819 int chg_gone, usb_chg_plugged_in;
1820 int count = 0;
1821
1822 while (count++ < param_open_ovp_counter) {
1823 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1824 USB_OVP_DEBOUNCE_TIME, 0x0);
1825 usleep(10);
1826 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1827 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
1828 pr_debug("OVP FET count = %d chg_gone=%d, usb_valid = %d\n",
1829 count, chg_gone, usb_chg_plugged_in);
1830
1831 /* note usb_chg_plugged_in=0 => chg_gone=1 */
1832 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
1833 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
1834 turn_off_usb_ovp_fet(chip);
1835
1836 msleep(20);
1837
1838 turn_on_usb_ovp_fet(chip);
1839 } else {
1840 pm_chg_masked_write(chip, USB_OVP_CONTROL,
1841 USB_OVP_DEBOUNCE_TIME, 0x1);
1842 pr_debug("Exit count=%d chg_gone=%d, usb_valid=%d\n",
1843 count, chg_gone, usb_chg_plugged_in);
1844 return;
1845 }
1846 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001847}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1849{
1850 handle_usb_insertion_removal(data);
1851 return IRQ_HANDLED;
1852}
1853
1854static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1855{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001856 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 return IRQ_HANDLED;
1858}
1859
1860static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1861{
1862 struct pm8921_chg_chip *chip = data;
1863 int status;
1864
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001865 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1866 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001867 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 pr_debug("battery present=%d", status);
1869 power_supply_changed(&chip->batt_psy);
1870 return IRQ_HANDLED;
1871}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001872
1873/*
1874 * this interrupt used to restart charging a battery.
1875 *
1876 * Note: When DC-inserted the VBAT can't go low.
1877 * VPH_PWR is provided by the ext-charger.
1878 * After End-Of-Charging from DC, charging can be resumed only
1879 * if DC is removed and then inserted after the battery was in use.
1880 * Therefore the handle_start_ext_chg() is not called.
1881 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1883{
1884 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001885 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001887 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001888
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001889 if (high_transition) {
1890 /* enable auto charging */
1891 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001892 pr_info("batt fell below resume voltage %s\n",
1893 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001894 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001895 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897 power_supply_changed(&chip->batt_psy);
1898 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001899 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901 return IRQ_HANDLED;
1902}
1903
1904static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1905{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001906 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907 return IRQ_HANDLED;
1908}
1909
1910static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1911{
1912 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1913 return IRQ_HANDLED;
1914}
1915
1916static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1917{
1918 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1919 return IRQ_HANDLED;
1920}
1921
1922static irqreturn_t vcp_irq_handler(int irq, void *data)
1923{
David Keitel8c5201a2012-02-24 16:08:54 -08001924 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 return IRQ_HANDLED;
1926}
1927
1928static irqreturn_t atcdone_irq_handler(int irq, void *data)
1929{
1930 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1931 return IRQ_HANDLED;
1932}
1933
1934static irqreturn_t atcfail_irq_handler(int irq, void *data)
1935{
1936 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1937 return IRQ_HANDLED;
1938}
1939
1940static irqreturn_t chgdone_irq_handler(int irq, void *data)
1941{
1942 struct pm8921_chg_chip *chip = data;
1943
1944 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001945
1946 handle_stop_ext_chg(chip);
1947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 power_supply_changed(&chip->batt_psy);
1949 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001950 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001951
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001952 bms_notify_check(chip);
1953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 return IRQ_HANDLED;
1955}
1956
1957static irqreturn_t chgfail_irq_handler(int irq, void *data)
1958{
1959 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001960 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961
David Keitel753ec8d2011-11-02 10:56:37 -07001962 ret = pm_chg_failed_clear(chip, 1);
1963 if (ret)
1964 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1965
1966 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1967 get_prop_batt_present(chip),
1968 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1969 pm_chg_get_fsm_state(data));
1970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 power_supply_changed(&chip->batt_psy);
1972 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001973 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001974 return IRQ_HANDLED;
1975}
1976
1977static irqreturn_t chgstate_irq_handler(int irq, void *data)
1978{
1979 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980
1981 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1982 power_supply_changed(&chip->batt_psy);
1983 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001984 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001986 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 return IRQ_HANDLED;
1989}
1990
David Keitel8c5201a2012-02-24 16:08:54 -08001991static int param_vin_disable_counter = 5;
1992module_param(param_vin_disable_counter, int, 0644);
1993
1994static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip,
1995 int count, int usb_ma)
1996{
1997 pm8921_charger_vbus_draw(500);
1998 pr_debug("count = %d iusb=500mA\n", count);
1999 disable_input_voltage_regulation(chip);
2000 pr_debug("count = %d disable_input_regulation\n", count);
2001
2002 msleep(20);
2003
2004 pr_debug("count = %d end sleep 20ms chg_gone=%d, usb_valid = %d\n",
2005 count,
2006 pm_chg_get_rt_status(chip, CHG_GONE_IRQ),
2007 is_usb_chg_plugged_in(chip));
2008 pr_debug("count = %d restoring input regulation and usb_ma = %d\n",
2009 count, usb_ma);
2010 enable_input_voltage_regulation(chip);
2011 pm8921_charger_vbus_draw(usb_ma);
2012}
2013
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002014#define VIN_ACTIVE_BIT BIT(0)
2015#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2016#define VIN_MIN_INCREASE_MV 100
2017static void unplug_check_worker(struct work_struct *work)
2018{
2019 struct delayed_work *dwork = to_delayed_work(work);
2020 struct pm8921_chg_chip *chip = container_of(dwork,
2021 struct pm8921_chg_chip, unplug_check_work);
2022 u8 reg_loop;
2023 int ibat, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002024 int usb_ma;
2025 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002026
2027 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2028 if (!usb_chg_plugged_in) {
2029 pr_debug("Stopping Unplug Check Worker since USB is removed"
2030 "reg_loop = %d, fsm = %d ibat = %d\n",
2031 pm_chg_get_regulation_loop(chip),
2032 pm_chg_get_fsm_state(chip),
2033 get_prop_batt_current(chip)
2034 );
2035 return;
2036 }
David Keitel8c5201a2012-02-24 16:08:54 -08002037
2038 pm_chg_iusbmax_get(chip, &usb_ma);
2039 if (usb_ma == 500) {
2040 pr_debug("Stopping Unplug Check Worker since USB == 500mA\n");
2041 disable_input_voltage_regulation(chip);
2042 return;
2043 }
2044
2045 if (usb_ma <= 100) {
2046 pr_debug(
2047 "Unenumerated yet or suspended usb_ma = %d skipping\n",
2048 usb_ma);
2049 goto check_again_later;
2050 }
2051 if (pm8921_chg_is_enabled(chip, CHG_GONE_IRQ))
2052 pr_debug("chg gone irq is enabled\n");
2053
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002054 reg_loop = pm_chg_get_regulation_loop(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002055 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002056
2057 if (reg_loop & VIN_ACTIVE_BIT) {
2058 ibat = get_prop_batt_current(chip);
2059
2060 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
2061 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2062 if (ibat > 0) {
David Keitel8c5201a2012-02-24 16:08:54 -08002063 int count = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002064
David Keitel8c5201a2012-02-24 16:08:54 -08002065 while (count++ < param_vin_disable_counter
2066 && usb_chg_plugged_in == 1) {
2067 attempt_reverse_boost_fix(chip, count, usb_ma);
2068 usb_chg_plugged_in
2069 = is_usb_chg_plugged_in(chip);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002070 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002071 }
2072 }
2073
David Keitel8c5201a2012-02-24 16:08:54 -08002074 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2075 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2076
2077 if (chg_gone == 1 && usb_chg_plugged_in == 1) {
2078 /* run the worker directly */
2079 pr_debug(" ver5 step: chg_gone=%d, usb_valid = %d\n",
2080 chg_gone, usb_chg_plugged_in);
2081 schedule_work(&chip->unplug_ovp_fet_open_work);
2082 }
2083
2084check_again_later:
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002085 schedule_delayed_work(&chip->unplug_check_work,
2086 round_jiffies_relative(msecs_to_jiffies
2087 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2088}
2089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090static irqreturn_t loop_change_irq_handler(int irq, void *data)
2091{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002092 struct pm8921_chg_chip *chip = data;
2093
2094 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2095 pm_chg_get_fsm_state(data),
2096 pm_chg_get_regulation_loop(data));
2097 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 return IRQ_HANDLED;
2099}
2100
2101static irqreturn_t fastchg_irq_handler(int irq, void *data)
2102{
2103 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002104 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002106 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2107 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2108 wake_lock(&chip->eoc_wake_lock);
2109 schedule_delayed_work(&chip->eoc_work,
2110 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002111 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002112 }
2113 power_supply_changed(&chip->batt_psy);
2114 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 return IRQ_HANDLED;
2116}
2117
2118static irqreturn_t trklchg_irq_handler(int irq, void *data)
2119{
2120 struct pm8921_chg_chip *chip = data;
2121
2122 power_supply_changed(&chip->batt_psy);
2123 return IRQ_HANDLED;
2124}
2125
2126static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2127{
2128 struct pm8921_chg_chip *chip = data;
2129 int status;
2130
2131 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2132 pr_debug("battery present=%d state=%d", !status,
2133 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002134 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 power_supply_changed(&chip->batt_psy);
2136 return IRQ_HANDLED;
2137}
2138
2139static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2140{
2141 struct pm8921_chg_chip *chip = data;
2142
Amir Samuelovd31ef502011-10-26 14:41:36 +02002143 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 power_supply_changed(&chip->batt_psy);
2145 return IRQ_HANDLED;
2146}
2147
2148static irqreturn_t chghot_irq_handler(int irq, void *data)
2149{
2150 struct pm8921_chg_chip *chip = data;
2151
2152 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2153 power_supply_changed(&chip->batt_psy);
2154 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002155 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 return IRQ_HANDLED;
2157}
2158
2159static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2160{
2161 struct pm8921_chg_chip *chip = data;
2162
2163 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002164 handle_stop_ext_chg(chip);
2165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 power_supply_changed(&chip->batt_psy);
2167 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168 return IRQ_HANDLED;
2169}
2170
2171static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2172{
2173 struct pm8921_chg_chip *chip = data;
David Keitel8c5201a2012-02-24 16:08:54 -08002174 int chg_gone, usb_chg_plugged_in;
2175
2176 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2177 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2178
2179 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2180 schedule_work(&chip->unplug_ovp_fet_open_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181
2182 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2183 power_supply_changed(&chip->batt_psy);
2184 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 return IRQ_HANDLED;
2186}
David Keitel52fda532011-11-10 10:43:44 -08002187/*
2188 *
2189 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2190 * fire for two cases:
2191 *
2192 * If the interrupt line switches to high temperature is okay
2193 * and thus charging begins.
2194 * If bat_temp_ok is low this means the temperature is now
2195 * too hot or cold, so charging is stopped.
2196 *
2197 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2199{
David Keitel52fda532011-11-10 10:43:44 -08002200 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 struct pm8921_chg_chip *chip = data;
2202
David Keitel52fda532011-11-10 10:43:44 -08002203 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2204
2205 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2206 bat_temp_ok, pm_chg_get_fsm_state(data));
2207
2208 if (bat_temp_ok)
2209 handle_start_ext_chg(chip);
2210 else
2211 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 power_supply_changed(&chip->batt_psy);
2214 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002215 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 return IRQ_HANDLED;
2217}
2218
2219static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2220{
2221 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2222 return IRQ_HANDLED;
2223}
2224
2225static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2226{
2227 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2228 return IRQ_HANDLED;
2229}
2230
2231static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2232{
2233 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2234 return IRQ_HANDLED;
2235}
2236
2237static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2238{
2239 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2240 return IRQ_HANDLED;
2241}
2242
2243static irqreturn_t batfet_irq_handler(int irq, void *data)
2244{
2245 struct pm8921_chg_chip *chip = data;
2246
2247 pr_debug("vreg ov\n");
2248 power_supply_changed(&chip->batt_psy);
2249 return IRQ_HANDLED;
2250}
2251
2252static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2253{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002254 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002255 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002256
David Keitel88e1b572012-01-11 11:57:14 -08002257 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2258 if (chip->ext_psy)
2259 power_supply_set_online(chip->ext_psy, dc_present);
2260 chip->dc_present = dc_present;
2261 if (dc_present)
2262 handle_start_ext_chg(chip);
2263 else
2264 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 return IRQ_HANDLED;
2266}
2267
2268static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2269{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002270 struct pm8921_chg_chip *chip = data;
2271
Amir Samuelovd31ef502011-10-26 14:41:36 +02002272 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 return IRQ_HANDLED;
2274}
2275
2276static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2277{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002278 struct pm8921_chg_chip *chip = data;
2279
Amir Samuelovd31ef502011-10-26 14:41:36 +02002280 handle_stop_ext_chg(chip);
2281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 return IRQ_HANDLED;
2283}
2284
David Keitel88e1b572012-01-11 11:57:14 -08002285static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2286{
2287 struct power_supply *psy = &the_chip->batt_psy;
2288 struct power_supply *epsy = dev_get_drvdata(dev);
2289 int i, dcin_irq;
2290
2291 /* Only search for external supply if none is registered */
2292 if (!the_chip->ext_psy) {
2293 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2294 for (i = 0; i < epsy->num_supplicants; i++) {
2295 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2296 if (!strncmp(epsy->name, "dc", 2)) {
2297 the_chip->ext_psy = epsy;
2298 dcin_valid_irq_handler(dcin_irq,
2299 the_chip);
2300 }
2301 }
2302 }
2303 }
2304 return 0;
2305}
2306
2307static void pm_batt_external_power_changed(struct power_supply *psy)
2308{
2309 /* Only look for an external supply if it hasn't been registered */
2310 if (!the_chip->ext_psy)
2311 class_for_each_device(power_supply_class, NULL, psy,
2312 __pm_batt_external_power_changed_work);
2313}
2314
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002315/**
2316 * update_heartbeat - internal function to update userspace
2317 * per update_time minutes
2318 *
2319 */
2320static void update_heartbeat(struct work_struct *work)
2321{
2322 struct delayed_work *dwork = to_delayed_work(work);
2323 struct pm8921_chg_chip *chip = container_of(dwork,
2324 struct pm8921_chg_chip, update_heartbeat_work);
2325
2326 power_supply_changed(&chip->batt_psy);
2327 schedule_delayed_work(&chip->update_heartbeat_work,
2328 round_jiffies_relative(msecs_to_jiffies
2329 (chip->update_time)));
2330}
2331
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002332enum {
2333 CHG_IN_PROGRESS,
2334 CHG_NOT_IN_PROGRESS,
2335 CHG_FINISHED,
2336};
2337
2338#define VBAT_TOLERANCE_MV 70
2339#define CHG_DISABLE_MSLEEP 100
2340static int is_charging_finished(struct pm8921_chg_chip *chip)
2341{
2342 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2343 int ichg_meas_ma, iterm_programmed;
2344 int regulation_loop, fast_chg, vcp;
2345 int rc;
2346 static int last_vbat_programmed = -EINVAL;
2347
2348 if (!is_ext_charging(chip)) {
2349 /* return if the battery is not being fastcharged */
2350 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2351 pr_debug("fast_chg = %d\n", fast_chg);
2352 if (fast_chg == 0)
2353 return CHG_NOT_IN_PROGRESS;
2354
2355 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2356 pr_debug("vcp = %d\n", vcp);
2357 if (vcp == 1)
2358 return CHG_IN_PROGRESS;
2359
2360 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2361 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2362 if (vbatdet_low == 1)
2363 return CHG_IN_PROGRESS;
2364
2365 /* reset count if battery is hot/cold */
2366 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2367 pr_debug("batt_temp_ok = %d\n", rc);
2368 if (rc == 0)
2369 return CHG_IN_PROGRESS;
2370
2371 /* reset count if battery voltage is less than vddmax */
2372 vbat_meas_uv = get_prop_battery_uvolts(chip);
2373 if (vbat_meas_uv < 0)
2374 return CHG_IN_PROGRESS;
2375 vbat_meas_mv = vbat_meas_uv / 1000;
2376
2377 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2378 if (rc) {
2379 pr_err("couldnt read vddmax rc = %d\n", rc);
2380 return CHG_IN_PROGRESS;
2381 }
2382 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2383 vbat_programmed, vbat_meas_mv);
2384 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2385 return CHG_IN_PROGRESS;
2386
2387 if (last_vbat_programmed == -EINVAL)
2388 last_vbat_programmed = vbat_programmed;
2389 if (last_vbat_programmed != vbat_programmed) {
2390 /* vddmax changed, reset and check again */
2391 pr_debug("vddmax = %d last_vdd_max=%d\n",
2392 vbat_programmed, last_vbat_programmed);
2393 last_vbat_programmed = vbat_programmed;
2394 return CHG_IN_PROGRESS;
2395 }
2396
2397 /*
2398 * TODO if charging from an external charger
2399 * check SOC instead of regulation loop
2400 */
2401 regulation_loop = pm_chg_get_regulation_loop(chip);
2402 if (regulation_loop < 0) {
2403 pr_err("couldnt read the regulation loop err=%d\n",
2404 regulation_loop);
2405 return CHG_IN_PROGRESS;
2406 }
2407 pr_debug("regulation_loop=%d\n", regulation_loop);
2408
2409 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2410 return CHG_IN_PROGRESS;
2411 } /* !is_ext_charging */
2412
2413 /* reset count if battery chg current is more than iterm */
2414 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2415 if (rc) {
2416 pr_err("couldnt read iterm rc = %d\n", rc);
2417 return CHG_IN_PROGRESS;
2418 }
2419
2420 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2421 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2422 iterm_programmed, ichg_meas_ma);
2423 /*
2424 * ichg_meas_ma < 0 means battery is drawing current
2425 * ichg_meas_ma > 0 means battery is providing current
2426 */
2427 if (ichg_meas_ma > 0)
2428 return CHG_IN_PROGRESS;
2429
2430 if (ichg_meas_ma * -1 > iterm_programmed)
2431 return CHG_IN_PROGRESS;
2432
2433 return CHG_FINISHED;
2434}
2435
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002436/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002437 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002438 * has happened
2439 *
2440 * If all conditions favouring, if the charge current is
2441 * less than the term current for three consecutive times
2442 * an EOC has happened.
2443 * The wakelock is released if there is no need to reshedule
2444 * - this happens when the battery is removed or EOC has
2445 * happened
2446 */
2447#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002448static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002449{
2450 struct delayed_work *dwork = to_delayed_work(work);
2451 struct pm8921_chg_chip *chip = container_of(dwork,
2452 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002453 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002454 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002455
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002456 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002457 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002458 count = 0;
2459 wake_unlock(&chip->eoc_wake_lock);
2460 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002461 }
2462
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002463 if (end == CHG_FINISHED) {
2464 count++;
2465 } else {
2466 count = 0;
2467 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002468
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002469 if (count == CONSECUTIVE_COUNT) {
2470 count = 0;
2471 pr_info("End of Charging\n");
2472
2473 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002474
Amir Samuelovd31ef502011-10-26 14:41:36 +02002475 if (is_ext_charging(chip))
2476 chip->ext_charge_done = true;
2477
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002478 if (chip->is_bat_warm || chip->is_bat_cool)
2479 chip->bms_notify.is_battery_full = 0;
2480 else
2481 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002482 /* declare end of charging by invoking chgdone interrupt */
2483 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2484 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002485 } else {
2486 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002487 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002488 round_jiffies_relative(msecs_to_jiffies
2489 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002490 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002491}
2492
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002493static void btm_configure_work(struct work_struct *work)
2494{
2495 int rc;
2496
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002497 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002498 if (rc)
2499 pr_err("failed to configure btm rc=%d", rc);
2500}
2501
2502DECLARE_WORK(btm_config_work, btm_configure_work);
2503
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002504static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2505{
2506 unsigned int chg_current = chip->max_bat_chg_current;
2507
2508 if (chip->is_bat_cool)
2509 chg_current = min(chg_current, chip->cool_bat_chg_current);
2510
2511 if (chip->is_bat_warm)
2512 chg_current = min(chg_current, chip->warm_bat_chg_current);
2513
David Keitelfdef3a42011-12-14 19:02:54 -08002514 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002515 chg_current = min(chg_current,
2516 chip->thermal_mitigation[thermal_mitigation]);
2517
2518 pm_chg_ibatmax_set(the_chip, chg_current);
2519}
2520
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002521#define TEMP_HYSTERISIS_DEGC 2
2522static void battery_cool(bool enter)
2523{
2524 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002525 if (enter == the_chip->is_bat_cool)
2526 return;
2527 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002528 if (enter) {
2529 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002530 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002531 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002532 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002533 pm_chg_vbatdet_set(the_chip,
2534 the_chip->cool_bat_voltage
2535 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002536 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002537 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002538 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002539 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002540 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002541 the_chip->max_voltage_mv
2542 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002543 }
2544 schedule_work(&btm_config_work);
2545}
2546
2547static void battery_warm(bool enter)
2548{
2549 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002550 if (enter == the_chip->is_bat_warm)
2551 return;
2552 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002553 if (enter) {
2554 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002555 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002556 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002557 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002558 pm_chg_vbatdet_set(the_chip,
2559 the_chip->warm_bat_voltage
2560 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002561 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002562 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002563 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002564 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002565 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002566 the_chip->max_voltage_mv
2567 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002568 }
2569 schedule_work(&btm_config_work);
2570}
2571
2572static int configure_btm(struct pm8921_chg_chip *chip)
2573{
2574 int rc;
2575
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002576 if (chip->warm_temp_dc != INT_MIN)
2577 btm_config.btm_warm_fn = battery_warm;
2578 else
2579 btm_config.btm_warm_fn = NULL;
2580
2581 if (chip->cool_temp_dc != INT_MIN)
2582 btm_config.btm_cool_fn = battery_cool;
2583 else
2584 btm_config.btm_cool_fn = NULL;
2585
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002586 btm_config.low_thr_temp = chip->cool_temp_dc;
2587 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002588 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002589 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002590 if (rc)
2591 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002592 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002593 if (rc)
2594 pr_err("failed to start btm rc = %d\n", rc);
2595
2596 return rc;
2597}
2598
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002599/**
2600 * set_disable_status_param -
2601 *
2602 * Internal function to disable battery charging and also disable drawing
2603 * any current from the source. The device is forced to run on a battery
2604 * after this.
2605 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606static int set_disable_status_param(const char *val, struct kernel_param *kp)
2607{
2608 int ret;
2609 struct pm8921_chg_chip *chip = the_chip;
2610
2611 ret = param_set_int(val, kp);
2612 if (ret) {
2613 pr_err("error setting value %d\n", ret);
2614 return ret;
2615 }
2616 pr_info("factory set disable param to %d\n", charging_disabled);
2617 if (chip) {
2618 pm_chg_auto_enable(chip, !charging_disabled);
2619 pm_chg_charge_dis(chip, charging_disabled);
2620 }
2621 return 0;
2622}
2623module_param_call(disabled, set_disable_status_param, param_get_uint,
2624 &charging_disabled, 0644);
2625
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002626/**
2627 * set_thermal_mitigation_level -
2628 *
2629 * Internal function to control battery charging current to reduce
2630 * temperature
2631 */
2632static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2633{
2634 int ret;
2635 struct pm8921_chg_chip *chip = the_chip;
2636
2637 ret = param_set_int(val, kp);
2638 if (ret) {
2639 pr_err("error setting value %d\n", ret);
2640 return ret;
2641 }
2642
2643 if (!chip) {
2644 pr_err("called before init\n");
2645 return -EINVAL;
2646 }
2647
2648 if (!chip->thermal_mitigation) {
2649 pr_err("no thermal mitigation\n");
2650 return -EINVAL;
2651 }
2652
2653 if (thermal_mitigation < 0
2654 || thermal_mitigation >= chip->thermal_levels) {
2655 pr_err("out of bound level selected\n");
2656 return -EINVAL;
2657 }
2658
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002659 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002660 return ret;
2661}
2662module_param_call(thermal_mitigation, set_therm_mitigation_level,
2663 param_get_uint,
2664 &thermal_mitigation, 0644);
2665
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002666static int set_usb_max_current(const char *val, struct kernel_param *kp)
2667{
2668 int ret, mA;
2669 struct pm8921_chg_chip *chip = the_chip;
2670
2671 ret = param_set_int(val, kp);
2672 if (ret) {
2673 pr_err("error setting value %d\n", ret);
2674 return ret;
2675 }
2676 if (chip) {
2677 pr_warn("setting current max to %d\n", usb_max_current);
2678 pm_chg_iusbmax_get(chip, &mA);
2679 if (mA > usb_max_current)
2680 pm8921_charger_vbus_draw(usb_max_current);
2681 return 0;
2682 }
2683 return -EINVAL;
2684}
2685module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2686 &usb_max_current, 0644);
2687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688static void free_irqs(struct pm8921_chg_chip *chip)
2689{
2690 int i;
2691
2692 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2693 if (chip->pmic_chg_irq[i]) {
2694 free_irq(chip->pmic_chg_irq[i], chip);
2695 chip->pmic_chg_irq[i] = 0;
2696 }
2697}
2698
David Keitel88e1b572012-01-11 11:57:14 -08002699/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2701{
2702 unsigned long flags;
2703 int fsm_state;
2704
2705 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2706 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2707
2708 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002709 if (chip->usb_present) {
2710 schedule_delayed_work(&chip->unplug_check_work,
2711 round_jiffies_relative(msecs_to_jiffies
2712 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002713 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002714 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715
2716 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2717 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2718 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002719 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2720 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2721 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2722 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2723 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002724 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002725 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2726 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002727 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002728
2729 spin_lock_irqsave(&vbus_lock, flags);
2730 if (usb_chg_current) {
2731 /* reissue a vbus draw call */
2732 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002733 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 }
2735 spin_unlock_irqrestore(&vbus_lock, flags);
2736
2737 fsm_state = pm_chg_get_fsm_state(chip);
2738 if (is_battery_charging(fsm_state)) {
2739 chip->bms_notify.is_charging = 1;
2740 pm8921_bms_charging_began();
2741 }
2742
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002743 check_battery_valid(chip);
2744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002745 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2746 chip->usb_present,
2747 chip->dc_present,
2748 get_prop_batt_present(chip),
2749 fsm_state);
2750}
2751
2752struct pm_chg_irq_init_data {
2753 unsigned int irq_id;
2754 char *name;
2755 unsigned long flags;
2756 irqreturn_t (*handler)(int, void *);
2757};
2758
2759#define CHG_IRQ(_id, _flags, _handler) \
2760{ \
2761 .irq_id = _id, \
2762 .name = #_id, \
2763 .flags = _flags, \
2764 .handler = _handler, \
2765}
2766struct pm_chg_irq_init_data chg_irq_data[] = {
2767 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2768 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002769 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2771 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002772 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2773 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2775 usbin_uv_irq_handler),
2776 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2777 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2778 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2779 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2780 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2781 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2782 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2783 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2784 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002785 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2786 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2788 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2789 batt_removed_irq_handler),
2790 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2791 batttemp_hot_irq_handler),
2792 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2793 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2794 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08002795 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2796 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002797 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2798 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002799 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2800 coarse_det_low_irq_handler),
2801 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2802 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2803 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2804 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2805 batfet_irq_handler),
2806 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2807 dcin_valid_irq_handler),
2808 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2809 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002810 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811};
2812
2813static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2814 struct platform_device *pdev)
2815{
2816 struct resource *res;
2817 int ret, i;
2818
2819 ret = 0;
2820 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2821
2822 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2823 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2824 chg_irq_data[i].name);
2825 if (res == NULL) {
2826 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2827 goto err_out;
2828 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002829 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830 ret = request_irq(res->start, chg_irq_data[i].handler,
2831 chg_irq_data[i].flags,
2832 chg_irq_data[i].name, chip);
2833 if (ret < 0) {
2834 pr_err("couldn't request %d (%s) %d\n", res->start,
2835 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002836 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837 goto err_out;
2838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2840 }
2841 return 0;
2842
2843err_out:
2844 free_irqs(chip);
2845 return -EINVAL;
2846}
2847
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002848static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2849{
2850 int err;
2851 u8 temp;
2852
2853 temp = 0xD1;
2854 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2855 if (err) {
2856 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2857 return;
2858 }
2859
2860 temp = 0xD3;
2861 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2862 if (err) {
2863 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2864 return;
2865 }
2866
2867 temp = 0xD1;
2868 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2869 if (err) {
2870 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2871 return;
2872 }
2873
2874 temp = 0xD5;
2875 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2876 if (err) {
2877 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2878 return;
2879 }
2880
2881 udelay(183);
2882
2883 temp = 0xD1;
2884 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2885 if (err) {
2886 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2887 return;
2888 }
2889
2890 temp = 0xD0;
2891 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2892 if (err) {
2893 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2894 return;
2895 }
2896 udelay(32);
2897
2898 temp = 0xD1;
2899 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2900 if (err) {
2901 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2902 return;
2903 }
2904
2905 temp = 0xD3;
2906 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2907 if (err) {
2908 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2909 return;
2910 }
2911}
2912
2913static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2914{
2915 int err;
2916 u8 temp;
2917
2918 temp = 0xD1;
2919 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2920 if (err) {
2921 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2922 return;
2923 }
2924
2925 temp = 0xD0;
2926 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2927 if (err) {
2928 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2929 return;
2930 }
2931}
2932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933#define ENUM_TIMER_STOP_BIT BIT(1)
2934#define BOOT_DONE_BIT BIT(6)
2935#define CHG_BATFET_ON_BIT BIT(3)
2936#define CHG_VCP_EN BIT(0)
2937#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2938#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002939#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2941{
2942 int rc;
2943
2944 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2945 BOOT_DONE_BIT, BOOT_DONE_BIT);
2946 if (rc) {
2947 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2948 return rc;
2949 }
2950
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002951 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 if (rc) {
2953 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002954 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002955 return rc;
2956 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002957 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002958 chip->max_voltage_mv
2959 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002960 if (rc) {
2961 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002962 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 return rc;
2964 }
2965
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002966 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 if (rc) {
2968 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002969 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 return rc;
2971 }
2972 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2973 if (rc) {
2974 pr_err("Failed to set max voltage to %d rc=%d\n",
2975 SAFE_CURRENT_MA, rc);
2976 return rc;
2977 }
2978
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002979 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 if (rc) {
2981 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2982 return rc;
2983 }
2984
2985 rc = pm_chg_iterm_set(chip, chip->term_current);
2986 if (rc) {
2987 pr_err("Failed to set term current to %d rc=%d\n",
2988 chip->term_current, rc);
2989 return rc;
2990 }
2991
2992 /* Disable the ENUM TIMER */
2993 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2994 ENUM_TIMER_STOP_BIT);
2995 if (rc) {
2996 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2997 return rc;
2998 }
2999
3000 /* init with the lowest USB current */
3001 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
3002 if (rc) {
3003 pr_err("Failed to set usb max to %d rc=%d\n",
3004 usb_ma_table[0].chg_iusb_value, rc);
3005 return rc;
3006 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003007
3008 if (chip->safety_time != 0) {
3009 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
3010 if (rc) {
3011 pr_err("Failed to set max time to %d minutes rc=%d\n",
3012 chip->safety_time, rc);
3013 return rc;
3014 }
3015 }
3016
3017 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003018 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003019 if (rc) {
3020 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
3021 chip->safety_time, rc);
3022 return rc;
3023 }
3024 }
3025
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003026 if (chip->vin_min != 0) {
3027 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3028 if (rc) {
3029 pr_err("Failed to set vin min to %d mV rc=%d\n",
3030 chip->vin_min, rc);
3031 return rc;
3032 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003033 } else {
3034 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003035 }
3036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 rc = pm_chg_disable_wd(chip);
3038 if (rc) {
3039 pr_err("Failed to disable wd rc=%d\n", rc);
3040 return rc;
3041 }
3042
3043 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
3044 CHG_BAT_TEMP_DIS_BIT, 0);
3045 if (rc) {
3046 pr_err("Failed to enable temp control chg rc=%d\n", rc);
3047 return rc;
3048 }
3049 /* switch to a 3.2Mhz for the buck */
3050 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
3051 if (rc) {
3052 pr_err("Failed to switch buck clk rc=%d\n", rc);
3053 return rc;
3054 }
3055
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003056 if (chip->trkl_voltage != 0) {
3057 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
3058 if (rc) {
3059 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
3060 chip->trkl_voltage, rc);
3061 return rc;
3062 }
3063 }
3064
3065 if (chip->weak_voltage != 0) {
3066 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
3067 if (rc) {
3068 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
3069 chip->weak_voltage, rc);
3070 return rc;
3071 }
3072 }
3073
3074 if (chip->trkl_current != 0) {
3075 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
3076 if (rc) {
3077 pr_err("Failed to set trkl current to %dmA rc=%d\n",
3078 chip->trkl_voltage, rc);
3079 return rc;
3080 }
3081 }
3082
3083 if (chip->weak_current != 0) {
3084 rc = pm_chg_iweak_set(chip, chip->weak_current);
3085 if (rc) {
3086 pr_err("Failed to set weak current to %dmA rc=%d\n",
3087 chip->weak_current, rc);
3088 return rc;
3089 }
3090 }
3091
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003092 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
3093 if (rc) {
3094 pr_err("Failed to set cold config %d rc=%d\n",
3095 chip->cold_thr, rc);
3096 }
3097
3098 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
3099 if (rc) {
3100 pr_err("Failed to set hot config %d rc=%d\n",
3101 chip->hot_thr, rc);
3102 }
3103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104 /* Workarounds for die 1.1 and 1.0 */
3105 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
3106 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
3108 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003109
3110 /* software workaround for correct battery_id detection */
3111 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
3112 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
3113 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
3114 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
3115 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
3116 udelay(100);
3117 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118 }
3119
David Keitelb51995e2011-11-18 17:03:31 -08003120 /* Workarounds for die 3.0 */
3121 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
3122 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
3123
3124 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
3125
David Keitela3c0d822011-11-03 14:18:52 -07003126 /* Disable EOC FSM processing */
3127 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
3128
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003129 pm8921_chg_force_19p2mhz_clk(chip);
3130
3131 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3132 VREF_BATT_THERM_FORCE_ON);
3133 if (rc)
3134 pr_err("Failed to Force Vref therm rc=%d\n", rc);
3135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 rc = pm_chg_charge_dis(chip, charging_disabled);
3137 if (rc) {
3138 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
3139 return rc;
3140 }
3141
3142 rc = pm_chg_auto_enable(chip, !charging_disabled);
3143 if (rc) {
3144 pr_err("Failed to enable charging rc=%d\n", rc);
3145 return rc;
3146 }
3147
3148 return 0;
3149}
3150
3151static int get_rt_status(void *data, u64 * val)
3152{
3153 int i = (int)data;
3154 int ret;
3155
3156 /* global irq number is passed in via data */
3157 ret = pm_chg_get_rt_status(the_chip, i);
3158 *val = ret;
3159 return 0;
3160}
3161DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
3162
3163static int get_fsm_status(void *data, u64 * val)
3164{
3165 u8 temp;
3166
3167 temp = pm_chg_get_fsm_state(the_chip);
3168 *val = temp;
3169 return 0;
3170}
3171DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3172
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003173static int get_reg_loop(void *data, u64 * val)
3174{
3175 u8 temp;
3176
3177 if (!the_chip) {
3178 pr_err("%s called before init\n", __func__);
3179 return -EINVAL;
3180 }
3181 temp = pm_chg_get_regulation_loop(the_chip);
3182 *val = temp;
3183 return 0;
3184}
3185DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187static int get_reg(void *data, u64 * val)
3188{
3189 int addr = (int)data;
3190 int ret;
3191 u8 temp;
3192
3193 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3194 if (ret) {
3195 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3196 addr, temp, ret);
3197 return -EAGAIN;
3198 }
3199 *val = temp;
3200 return 0;
3201}
3202
3203static int set_reg(void *data, u64 val)
3204{
3205 int addr = (int)data;
3206 int ret;
3207 u8 temp;
3208
3209 temp = (u8) val;
3210 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3211 if (ret) {
3212 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3213 addr, temp, ret);
3214 return -EAGAIN;
3215 }
3216 return 0;
3217}
3218DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3219
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003220enum {
3221 BAT_WARM_ZONE,
3222 BAT_COOL_ZONE,
3223};
3224static int get_warm_cool(void *data, u64 * val)
3225{
3226 if (!the_chip) {
3227 pr_err("%s called before init\n", __func__);
3228 return -EINVAL;
3229 }
3230 if ((int)data == BAT_WARM_ZONE)
3231 *val = the_chip->is_bat_warm;
3232 if ((int)data == BAT_COOL_ZONE)
3233 *val = the_chip->is_bat_cool;
3234 return 0;
3235}
3236DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3239{
3240 int i;
3241
3242 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3243
3244 if (IS_ERR(chip->dent)) {
3245 pr_err("pmic charger couldnt create debugfs dir\n");
3246 return;
3247 }
3248
3249 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3250 (void *)CHG_CNTRL, &reg_fops);
3251 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3252 (void *)CHG_CNTRL_2, &reg_fops);
3253 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3254 (void *)CHG_CNTRL_3, &reg_fops);
3255 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3256 (void *)PBL_ACCESS1, &reg_fops);
3257 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3258 (void *)PBL_ACCESS2, &reg_fops);
3259 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3260 (void *)SYS_CONFIG_1, &reg_fops);
3261 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3262 (void *)SYS_CONFIG_2, &reg_fops);
3263 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3264 (void *)CHG_VDD_MAX, &reg_fops);
3265 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3266 (void *)CHG_VDD_SAFE, &reg_fops);
3267 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3268 (void *)CHG_VBAT_DET, &reg_fops);
3269 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3270 (void *)CHG_IBAT_MAX, &reg_fops);
3271 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3272 (void *)CHG_IBAT_SAFE, &reg_fops);
3273 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3274 (void *)CHG_VIN_MIN, &reg_fops);
3275 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3276 (void *)CHG_VTRICKLE, &reg_fops);
3277 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3278 (void *)CHG_ITRICKLE, &reg_fops);
3279 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3280 (void *)CHG_ITERM, &reg_fops);
3281 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3282 (void *)CHG_TCHG_MAX, &reg_fops);
3283 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3284 (void *)CHG_TWDOG, &reg_fops);
3285 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3286 (void *)CHG_TEMP_THRESH, &reg_fops);
3287 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3288 (void *)CHG_COMP_OVR, &reg_fops);
3289 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3290 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3291 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3292 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3293 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3294 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3295 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3296 (void *)CHG_TEST, &reg_fops);
3297
3298 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3299 &fsm_fops);
3300
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003301 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3302 &reg_loop_fops);
3303
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003304 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3305 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3306 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3307 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3310 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3311 debugfs_create_file(chg_irq_data[i].name, 0444,
3312 chip->dent,
3313 (void *)chg_irq_data[i].irq_id,
3314 &rt_fops);
3315 }
3316}
3317
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003318static int pm8921_charger_suspend_noirq(struct device *dev)
3319{
3320 int rc;
3321 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3322
3323 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3324 if (rc)
3325 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3326 pm8921_chg_set_hw_clk_switching(chip);
3327 return 0;
3328}
3329
3330static int pm8921_charger_resume_noirq(struct device *dev)
3331{
3332 int rc;
3333 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3334
3335 pm8921_chg_force_19p2mhz_clk(chip);
3336
3337 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3338 VREF_BATT_THERM_FORCE_ON);
3339 if (rc)
3340 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3341 return 0;
3342}
3343
David Keitelf2226022011-12-13 15:55:50 -08003344static int pm8921_charger_resume(struct device *dev)
3345{
3346 int rc;
3347 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3348
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003349 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003350 && !(chip->keep_btm_on_suspend)) {
3351 rc = pm8xxx_adc_btm_configure(&btm_config);
3352 if (rc)
3353 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3354
3355 rc = pm8xxx_adc_btm_start();
3356 if (rc)
3357 pr_err("couldn't restart btm rc=%d\n", rc);
3358 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003359 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3360 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3361 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3362 }
David Keitelf2226022011-12-13 15:55:50 -08003363 return 0;
3364}
3365
3366static int pm8921_charger_suspend(struct device *dev)
3367{
3368 int rc;
3369 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3370
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003371 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003372 && !(chip->keep_btm_on_suspend)) {
3373 rc = pm8xxx_adc_btm_end();
3374 if (rc)
3375 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3376 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003377
3378 if (is_usb_chg_plugged_in(chip)) {
3379 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3380 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3381 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003382
David Keitelf2226022011-12-13 15:55:50 -08003383 return 0;
3384}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3386{
3387 int rc = 0;
3388 struct pm8921_chg_chip *chip;
3389 const struct pm8921_charger_platform_data *pdata
3390 = pdev->dev.platform_data;
3391
3392 if (!pdata) {
3393 pr_err("missing platform data\n");
3394 return -EINVAL;
3395 }
3396
3397 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3398 GFP_KERNEL);
3399 if (!chip) {
3400 pr_err("Cannot allocate pm_chg_chip\n");
3401 return -ENOMEM;
3402 }
3403
3404 chip->dev = &pdev->dev;
3405 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003406 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003408 chip->max_voltage_mv = pdata->max_voltage;
3409 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003410 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003411 chip->term_current = pdata->term_current;
3412 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003413 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003414 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3415 chip->batt_id_min = pdata->batt_id_min;
3416 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003417 if (pdata->cool_temp != INT_MIN)
3418 chip->cool_temp_dc = pdata->cool_temp * 10;
3419 else
3420 chip->cool_temp_dc = INT_MIN;
3421
3422 if (pdata->warm_temp != INT_MIN)
3423 chip->warm_temp_dc = pdata->warm_temp * 10;
3424 else
3425 chip->warm_temp_dc = INT_MIN;
3426
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003427 chip->temp_check_period = pdata->temp_check_period;
3428 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3429 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3430 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3431 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3432 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003433 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003434 chip->trkl_voltage = pdata->trkl_voltage;
3435 chip->weak_voltage = pdata->weak_voltage;
3436 chip->trkl_current = pdata->trkl_current;
3437 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003438 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003439 chip->thermal_mitigation = pdata->thermal_mitigation;
3440 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003442 chip->cold_thr = pdata->cold_thr;
3443 chip->hot_thr = pdata->hot_thr;
3444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003445 rc = pm8921_chg_hw_init(chip);
3446 if (rc) {
3447 pr_err("couldn't init hardware rc=%d\n", rc);
3448 goto free_chip;
3449 }
3450
3451 chip->usb_psy.name = "usb",
3452 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3453 chip->usb_psy.supplied_to = pm_power_supplied_to,
3454 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3455 chip->usb_psy.properties = pm_power_props,
3456 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3457 chip->usb_psy.get_property = pm_power_get_property,
3458
David Keitel6ed71a52012-01-30 12:42:18 -08003459 chip->dc_psy.name = "pm8921-dc",
3460 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3461 chip->dc_psy.supplied_to = pm_power_supplied_to,
3462 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3463 chip->dc_psy.properties = pm_power_props,
3464 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
3465 chip->dc_psy.get_property = pm_power_get_property,
3466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 chip->batt_psy.name = "battery",
3468 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3469 chip->batt_psy.properties = msm_batt_power_props,
3470 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3471 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003472 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 rc = power_supply_register(chip->dev, &chip->usb_psy);
3474 if (rc < 0) {
3475 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003476 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003477 }
3478
David Keitel6ed71a52012-01-30 12:42:18 -08003479 rc = power_supply_register(chip->dev, &chip->dc_psy);
3480 if (rc < 0) {
3481 pr_err("power_supply_register usb failed rc = %d\n", rc);
3482 goto unregister_usb;
3483 }
3484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003485 rc = power_supply_register(chip->dev, &chip->batt_psy);
3486 if (rc < 0) {
3487 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003488 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489 }
3490
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003491 platform_set_drvdata(pdev, chip);
3492 the_chip = chip;
3493
3494 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
David Keitel8c5201a2012-02-24 16:08:54 -08003495 wake_lock_init(&chip->unplug_ovp_fet_open_wake_lock,
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003496 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003497 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitel8c5201a2012-02-24 16:08:54 -08003498 INIT_WORK(&chip->unplug_ovp_fet_open_work,
3499 unplug_ovp_fet_open_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003500 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003502 rc = request_irqs(chip, pdev);
3503 if (rc) {
3504 pr_err("couldn't register interrupts rc=%d\n", rc);
3505 goto unregister_batt;
3506 }
3507
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003508 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3509 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3510 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003511 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3512 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003513 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003514 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003515 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003516 * care for jeita compliance
3517 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003518 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003519 rc = configure_btm(chip);
3520 if (rc) {
3521 pr_err("couldn't register with btm rc=%d\n", rc);
3522 goto free_irq;
3523 }
3524 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526 create_debugfs_entries(chip);
3527
3528 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003529 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003531 /* determine what state the charger is in */
3532 determine_initial_state(chip);
3533
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003534 if (chip->update_time) {
3535 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3536 update_heartbeat);
3537 schedule_delayed_work(&chip->update_heartbeat_work,
3538 round_jiffies_relative(msecs_to_jiffies
3539 (chip->update_time)));
3540 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003541 return 0;
3542
3543free_irq:
3544 free_irqs(chip);
3545unregister_batt:
3546 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003547unregister_dc:
3548 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549unregister_usb:
3550 power_supply_unregister(&chip->usb_psy);
3551free_chip:
3552 kfree(chip);
3553 return rc;
3554}
3555
3556static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3557{
3558 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3559
3560 free_irqs(chip);
3561 platform_set_drvdata(pdev, NULL);
3562 the_chip = NULL;
3563 kfree(chip);
3564 return 0;
3565}
David Keitelf2226022011-12-13 15:55:50 -08003566static const struct dev_pm_ops pm8921_pm_ops = {
3567 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003568 .suspend_noirq = pm8921_charger_suspend_noirq,
3569 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003570 .resume = pm8921_charger_resume,
3571};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003572static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003573 .probe = pm8921_charger_probe,
3574 .remove = __devexit_p(pm8921_charger_remove),
3575 .driver = {
3576 .name = PM8921_CHARGER_DEV_NAME,
3577 .owner = THIS_MODULE,
3578 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579 },
3580};
3581
3582static int __init pm8921_charger_init(void)
3583{
3584 return platform_driver_register(&pm8921_charger_driver);
3585}
3586
3587static void __exit pm8921_charger_exit(void)
3588{
3589 platform_driver_unregister(&pm8921_charger_driver);
3590}
3591
3592late_initcall(pm8921_charger_init);
3593module_exit(pm8921_charger_exit);
3594
3595MODULE_LICENSE("GPL v2");
3596MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3597MODULE_VERSION("1.0");
3598MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);