blob: fa8f86647a3bd5450fb8e51623b5a648447559de [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;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800259 struct delayed_work unplug_wrkarnd_restore_work;
260 struct delayed_work unplug_check_work;
261 struct wake_lock unplug_wrkarnd_restore_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
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -0800418static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip)
419{
420 u8 temp = 0;
421
422 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
423 return !!(temp & CHG_CHARGE_DIS_BIT);
424}
425
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426#define PM8921_CHG_V_MIN_MV 3240
427#define PM8921_CHG_V_STEP_MV 20
David Keitelcf867232012-01-27 18:40:12 -0800428#define PM8921_CHG_V_STEP_10_MV_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429#define PM8921_CHG_VDDMAX_MAX 4500
430#define PM8921_CHG_VDDMAX_MIN 3400
431#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800432static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433{
David Keitelcf867232012-01-27 18:40:12 -0800434 int remainder, voltage_20_step;
435 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436
David Keitelcf867232012-01-27 18:40:12 -0800437 voltage_20_step = voltage;
438 remainder = voltage % 20;
439 if (remainder >= 10) {
440 voltage_20_step += 10;
441 temp = PM8921_CHG_V_STEP_10_MV_BIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442 }
David Keitelcf867232012-01-27 18:40:12 -0800443
444 temp |= (voltage_20_step - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800446 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447}
448
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700449static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
450{
451 u8 temp;
452 int rc;
453
454 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
455 if (rc) {
456 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700457 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700458 return rc;
459 }
460 temp &= PM8921_CHG_V_MASK;
461 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
David Keitelcf867232012-01-27 18:40:12 -0800462 if (temp & PM8921_CHG_V_STEP_10_MV_BIT)
463 *voltage = *voltage - 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700464 return 0;
465}
466
David Keitelcf867232012-01-27 18:40:12 -0800467static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
468{
469 int current_mv, ret, steps, i;
470 bool increase;
471
472 ret = 0;
473
474 if (voltage < PM8921_CHG_VDDMAX_MIN
475 || voltage > PM8921_CHG_VDDMAX_MAX) {
476 pr_err("bad mV=%d asked to set\n", voltage);
477 return -EINVAL;
478 }
479
480 ret = pm_chg_vddmax_get(chip, &current_mv);
481 if (ret) {
482 pr_err("Failed to read vddmax rc=%d\n", ret);
483 return -EINVAL;
484 }
485 if (current_mv == voltage)
486 return 0;
487
488 /* Only change in increments when USB is present */
489 if (is_usb_chg_plugged_in(chip)) {
490 if (current_mv < voltage) {
491 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
492 increase = true;
493 } else {
494 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
495 increase = false;
496 }
497 for (i = 0; i < steps; i++) {
498 if (increase)
499 current_mv += PM8921_CHG_V_STEP_MV;
500 else
501 current_mv -= PM8921_CHG_V_STEP_MV;
502 ret |= __pm_chg_vddmax_set(chip, current_mv);
503 }
504 }
505 ret |= __pm_chg_vddmax_set(chip, voltage);
506 return ret;
507}
508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509#define PM8921_CHG_VDDSAFE_MIN 3400
510#define PM8921_CHG_VDDSAFE_MAX 4500
511static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
512{
513 u8 temp;
514
515 if (voltage < PM8921_CHG_VDDSAFE_MIN
516 || voltage > PM8921_CHG_VDDSAFE_MAX) {
517 pr_err("bad mV=%d asked to set\n", voltage);
518 return -EINVAL;
519 }
520 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
521 pr_debug("voltage=%d setting %02x\n", voltage, temp);
522 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
523}
524
525#define PM8921_CHG_VBATDET_MIN 3240
526#define PM8921_CHG_VBATDET_MAX 5780
527static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
528{
529 u8 temp;
530
531 if (voltage < PM8921_CHG_VBATDET_MIN
532 || voltage > PM8921_CHG_VBATDET_MAX) {
533 pr_err("bad mV=%d asked to set\n", voltage);
534 return -EINVAL;
535 }
536 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
537 pr_debug("voltage=%d setting %02x\n", voltage, temp);
538 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
539}
540
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700541#define PM8921_CHG_VINMIN_MIN_MV 3800
542#define PM8921_CHG_VINMIN_STEP_MV 100
543#define PM8921_CHG_VINMIN_USABLE_MAX 6500
544#define PM8921_CHG_VINMIN_USABLE_MIN 4300
545#define PM8921_CHG_VINMIN_MASK 0x1F
546static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
547{
548 u8 temp;
549
550 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
551 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
552 pr_err("bad mV=%d asked to set\n", voltage);
553 return -EINVAL;
554 }
555 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
556 pr_debug("voltage=%d setting %02x\n", voltage, temp);
557 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
558 temp);
559}
560
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800561static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
562{
563 u8 temp;
564 int rc, voltage_mv;
565
566 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
567 temp &= PM8921_CHG_VINMIN_MASK;
568
569 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
570 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
571
572 return voltage_mv;
573}
574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575#define PM8921_CHG_IBATMAX_MIN 325
576#define PM8921_CHG_IBATMAX_MAX 2000
577#define PM8921_CHG_I_MIN_MA 225
578#define PM8921_CHG_I_STEP_MA 50
579#define PM8921_CHG_I_MASK 0x3F
580static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
581{
582 u8 temp;
583
584 if (chg_current < PM8921_CHG_IBATMAX_MIN
585 || chg_current > PM8921_CHG_IBATMAX_MAX) {
586 pr_err("bad mA=%d asked to set\n", chg_current);
587 return -EINVAL;
588 }
589 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
590 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
591}
592
593#define PM8921_CHG_IBATSAFE_MIN 225
594#define PM8921_CHG_IBATSAFE_MAX 3375
595static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
596{
597 u8 temp;
598
599 if (chg_current < PM8921_CHG_IBATSAFE_MIN
600 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
601 pr_err("bad mA=%d asked to set\n", chg_current);
602 return -EINVAL;
603 }
604 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
605 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
606 PM8921_CHG_I_MASK, temp);
607}
608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700610#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611#define PM8921_CHG_ITERM_STEP_MA 10
612#define PM8921_CHG_ITERM_MASK 0xF
613static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
614{
615 u8 temp;
616
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700617 if (chg_current < PM8921_CHG_ITERM_MIN_MA
618 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 pr_err("bad mA=%d asked to set\n", chg_current);
620 return -EINVAL;
621 }
622
623 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
624 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700625 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 temp);
627}
628
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700629static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
630{
631 u8 temp;
632 int rc;
633
634 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
635 if (rc) {
636 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700637 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700638 return rc;
639 }
640 temp &= PM8921_CHG_ITERM_MASK;
641 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
642 + PM8921_CHG_ITERM_MIN_MA;
643 return 0;
644}
645
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800646struct usb_ma_limit_entry {
647 int usb_ma;
648 u8 chg_iusb_value;
649};
650
651static struct usb_ma_limit_entry usb_ma_table[] = {
652 {100, 0},
653 {500, 1},
654 {700, 2},
655 {850, 3},
656 {900, 4},
657 {1100, 5},
658 {1300, 6},
659 {1500, 7},
660};
661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662#define PM8921_CHG_IUSB_MASK 0x1C
663#define PM8921_CHG_IUSB_MAX 7
664#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700665static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666{
667 u8 temp;
668
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700669 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
670 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 return -EINVAL;
672 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700673 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
675 temp);
676}
677
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800678static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
679{
680 u8 temp;
681 int i, rc;
682
683 *mA = 0;
684 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
685 if (rc) {
686 pr_err("err=%d reading PBL_ACCESS2\n", rc);
687 return rc;
688 }
689 temp &= PM8921_CHG_IUSB_MASK;
690 temp = temp >> 2;
691 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
692 if (usb_ma_table[i].chg_iusb_value == temp)
693 *mA = usb_ma_table[i].usb_ma;
694 }
695 return rc;
696}
697
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698#define PM8921_CHG_WD_MASK 0x1F
699static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
700{
701 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700702 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
703}
704
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700705#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700706#define PM8921_CHG_TCHG_MIN 4
707#define PM8921_CHG_TCHG_MAX 512
708#define PM8921_CHG_TCHG_STEP 4
709static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
710{
711 u8 temp;
712
713 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
714 pr_err("bad max minutes =%d asked to set\n", minutes);
715 return -EINVAL;
716 }
717
718 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
719 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
720 temp);
721}
722
723#define PM8921_CHG_TTRKL_MASK 0x1F
724#define PM8921_CHG_TTRKL_MIN 1
725#define PM8921_CHG_TTRKL_MAX 64
726static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
727{
728 u8 temp;
729
730 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
731 pr_err("bad max minutes =%d asked to set\n", minutes);
732 return -EINVAL;
733 }
734
735 temp = minutes - 1;
736 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
737 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738}
739
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700740#define PM8921_CHG_VTRKL_MIN_MV 2050
741#define PM8921_CHG_VTRKL_MAX_MV 2800
742#define PM8921_CHG_VTRKL_STEP_MV 50
743#define PM8921_CHG_VTRKL_SHIFT 4
744#define PM8921_CHG_VTRKL_MASK 0xF0
745static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
746{
747 u8 temp;
748
749 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
750 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
751 pr_err("bad voltage = %dmV asked to set\n", millivolts);
752 return -EINVAL;
753 }
754
755 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
756 temp = temp << PM8921_CHG_VTRKL_SHIFT;
757 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
758 temp);
759}
760
761#define PM8921_CHG_VWEAK_MIN_MV 2100
762#define PM8921_CHG_VWEAK_MAX_MV 3600
763#define PM8921_CHG_VWEAK_STEP_MV 100
764#define PM8921_CHG_VWEAK_MASK 0x0F
765static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
766{
767 u8 temp;
768
769 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
770 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
771 pr_err("bad voltage = %dmV asked to set\n", millivolts);
772 return -EINVAL;
773 }
774
775 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
776 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
777 temp);
778}
779
780#define PM8921_CHG_ITRKL_MIN_MA 50
781#define PM8921_CHG_ITRKL_MAX_MA 200
782#define PM8921_CHG_ITRKL_MASK 0x0F
783#define PM8921_CHG_ITRKL_STEP_MA 10
784static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
785{
786 u8 temp;
787
788 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
789 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
790 pr_err("bad current = %dmA asked to set\n", milliamps);
791 return -EINVAL;
792 }
793
794 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
795
796 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
797 temp);
798}
799
800#define PM8921_CHG_IWEAK_MIN_MA 325
801#define PM8921_CHG_IWEAK_MAX_MA 525
802#define PM8921_CHG_IWEAK_SHIFT 7
803#define PM8921_CHG_IWEAK_MASK 0x80
804static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
805{
806 u8 temp;
807
808 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
809 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
810 pr_err("bad current = %dmA asked to set\n", milliamps);
811 return -EINVAL;
812 }
813
814 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
815 temp = 0;
816 else
817 temp = 1;
818
819 temp = temp << PM8921_CHG_IWEAK_SHIFT;
820 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
821 temp);
822}
823
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700824#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
825#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
826static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
827 enum pm8921_chg_cold_thr cold_thr)
828{
829 u8 temp;
830
831 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
832 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
833 return pm_chg_masked_write(chip, CHG_CNTRL_2,
834 PM8921_CHG_BATT_TEMP_THR_COLD,
835 temp);
836}
837
838#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
839#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
840static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
841 enum pm8921_chg_hot_thr hot_thr)
842{
843 u8 temp;
844
845 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
846 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
847 return pm_chg_masked_write(chip, CHG_CNTRL_2,
848 PM8921_CHG_BATT_TEMP_THR_HOT,
849 temp);
850}
851
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700852static int64_t read_battery_id(struct pm8921_chg_chip *chip)
853{
854 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700855 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700856
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700857 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700858 if (rc) {
859 pr_err("error reading batt id channel = %d, rc = %d\n",
860 chip->vbat_channel, rc);
861 return rc;
862 }
863 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
864 result.measurement);
865 return result.physical;
866}
867
868static int is_battery_valid(struct pm8921_chg_chip *chip)
869{
870 int64_t rc;
871
872 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
873 return 1;
874
875 rc = read_battery_id(chip);
876 if (rc < 0) {
877 pr_err("error reading batt id channel = %d, rc = %lld\n",
878 chip->vbat_channel, rc);
879 /* assume battery id is valid when adc error happens */
880 return 1;
881 }
882
883 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
884 pr_err("batt_id phy =%lld is not valid\n", rc);
885 return 0;
886 }
887 return 1;
888}
889
890static void check_battery_valid(struct pm8921_chg_chip *chip)
891{
892 if (is_battery_valid(chip) == 0) {
893 pr_err("batt_id not valid, disbling charging\n");
894 pm_chg_auto_enable(chip, 0);
895 } else {
896 pm_chg_auto_enable(chip, !charging_disabled);
897 }
898}
899
900static void battery_id_valid(struct work_struct *work)
901{
902 struct pm8921_chg_chip *chip = container_of(work,
903 struct pm8921_chg_chip, battery_id_valid_work);
904
905 check_battery_valid(chip);
906}
907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
909{
910 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
911 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
912 enable_irq(chip->pmic_chg_irq[interrupt]);
913 }
914}
915
916static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
917{
918 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
919 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
920 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
921 }
922}
923
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800924static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
925{
926 return test_bit(interrupt, chip->enabled_irqs);
927}
928
Amir Samuelovd31ef502011-10-26 14:41:36 +0200929static bool is_ext_charging(struct pm8921_chg_chip *chip)
930{
David Keitel88e1b572012-01-11 11:57:14 -0800931 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200932
David Keitel88e1b572012-01-11 11:57:14 -0800933 if (!chip->ext_psy)
934 return false;
935 if (chip->ext_psy->get_property(chip->ext_psy,
936 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
937 return false;
938 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
939 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200940
941 return false;
942}
943
944static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
945{
David Keitel88e1b572012-01-11 11:57:14 -0800946 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200947
David Keitel88e1b572012-01-11 11:57:14 -0800948 if (!chip->ext_psy)
949 return false;
950 if (chip->ext_psy->get_property(chip->ext_psy,
951 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
952 return false;
953 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +0200954 return true;
955
956 return false;
957}
958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959static int is_battery_charging(int fsm_state)
960{
Amir Samuelovd31ef502011-10-26 14:41:36 +0200961 if (is_ext_charging(the_chip))
962 return 1;
963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 switch (fsm_state) {
965 case FSM_STATE_ATC_2A:
966 case FSM_STATE_ATC_2B:
967 case FSM_STATE_ON_CHG_AND_BAT_6:
968 case FSM_STATE_FAST_CHG_7:
969 case FSM_STATE_TRKL_CHG_8:
970 return 1;
971 }
972 return 0;
973}
974
975static void bms_notify(struct work_struct *work)
976{
977 struct bms_notify *n = container_of(work, struct bms_notify, work);
978
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700979 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700981 } else {
982 pm8921_bms_charging_end(n->is_battery_full);
983 n->is_battery_full = 0;
984 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985}
986
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -0700987static void bms_notify_check(struct pm8921_chg_chip *chip)
988{
989 int fsm_state, new_is_charging;
990
991 fsm_state = pm_chg_get_fsm_state(chip);
992 new_is_charging = is_battery_charging(fsm_state);
993
994 if (chip->bms_notify.is_charging ^ new_is_charging) {
995 chip->bms_notify.is_charging = new_is_charging;
996 schedule_work(&(chip->bms_notify.work));
997 }
998}
999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000static enum power_supply_property pm_power_props[] = {
1001 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001002 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003};
1004
1005static char *pm_power_supplied_to[] = {
1006 "battery",
1007};
1008
David Keitel6ed71a52012-01-30 12:42:18 -08001009#define USB_WALL_THRESHOLD_MA 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010static int pm_power_get_property(struct power_supply *psy,
1011 enum power_supply_property psp,
1012 union power_supply_propval *val)
1013{
David Keitel6ed71a52012-01-30 12:42:18 -08001014 int current_max;
1015
1016 /* Check if called before init */
1017 if (!the_chip)
1018 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019
1020 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001021 case POWER_SUPPLY_PROP_CURRENT_MAX:
1022 pm_chg_iusbmax_get(the_chip, &current_max);
1023 val->intval = current_max;
1024 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001026 case POWER_SUPPLY_PROP_ONLINE:
David Keitel6ed71a52012-01-30 12:42:18 -08001027 if (pm_is_chg_charge_dis_bit_set(the_chip) ||
1028 !is_usb_chg_plugged_in(the_chip))
1029 val->intval = 0;
1030 else if (psy->type == POWER_SUPPLY_TYPE_USB ||
1031 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
1032 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
1033 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
1034 val->intval = 1;
1035 } else if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
1036 pm_chg_iusbmax_get(the_chip, &current_max);
1037 if (current_max > USB_WALL_THRESHOLD_MA)
1038 val->intval = 1;
Abhijeet Dharmapurikarbe054882012-01-03 20:27:07 -08001039 else
David Keitel6ed71a52012-01-30 12:42:18 -08001040 val->intval = 0;
1041 } else {
1042 val->intval = 0;
1043 pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 }
1045 break;
1046 default:
1047 return -EINVAL;
1048 }
1049 return 0;
1050}
1051
1052static enum power_supply_property msm_batt_power_props[] = {
1053 POWER_SUPPLY_PROP_STATUS,
1054 POWER_SUPPLY_PROP_CHARGE_TYPE,
1055 POWER_SUPPLY_PROP_HEALTH,
1056 POWER_SUPPLY_PROP_PRESENT,
1057 POWER_SUPPLY_PROP_TECHNOLOGY,
1058 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1059 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1060 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1061 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001062 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001063 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001064 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065};
1066
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001067static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068{
1069 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001070 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001072 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 if (rc) {
1074 pr_err("error reading adc channel = %d, rc = %d\n",
1075 chip->vbat_channel, rc);
1076 return rc;
1077 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001078 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 result.measurement);
1080 return (int)result.physical;
1081}
1082
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001083static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1084{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001085 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1086 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1087 unsigned int low_voltage = chip->min_voltage_mv;
1088 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001089
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001090 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001091 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001092 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001093 return 100;
1094 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001095 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001096 / (high_voltage - low_voltage);
1097}
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1100{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001101 int percent_soc = pm8921_bms_get_percent_charge();
1102
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001103 if (percent_soc == -ENXIO)
1104 percent_soc = voltage_based_capacity(chip);
1105
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001106 if (percent_soc <= 10)
1107 pr_warn("low battery charge = %d%%\n", percent_soc);
1108
1109 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110}
1111
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001112static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1113{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001114 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001115
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001116 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001117 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001118 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001119 }
1120
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001121 if (rc) {
1122 pr_err("unable to get batt current rc = %d\n", rc);
1123 return rc;
1124 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001125 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001126 }
1127}
1128
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001129static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1130{
1131 int rc;
1132
1133 rc = pm8921_bms_get_fcc();
1134 if (rc < 0)
1135 pr_err("unable to get batt fcc rc = %d\n", rc);
1136 return rc;
1137}
1138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1140{
1141 int temp;
1142
1143 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1144 if (temp)
1145 return POWER_SUPPLY_HEALTH_OVERHEAT;
1146
1147 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1148 if (temp)
1149 return POWER_SUPPLY_HEALTH_COLD;
1150
1151 return POWER_SUPPLY_HEALTH_GOOD;
1152}
1153
1154static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1155{
1156 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1157}
1158
1159static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1160{
1161 int temp;
1162
Amir Samuelovd31ef502011-10-26 14:41:36 +02001163 if (!get_prop_batt_present(chip))
1164 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1165
1166 if (is_ext_trickle_charging(chip))
1167 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1168
1169 if (is_ext_charging(chip))
1170 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1173 if (temp)
1174 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1175
1176 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1177 if (temp)
1178 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1179
1180 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1181}
1182
1183static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1184{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001185 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1186 int fsm_state = pm_chg_get_fsm_state(chip);
1187 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188
David Keitel88e1b572012-01-11 11:57:14 -08001189 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001190 if (chip->ext_charge_done)
1191 return POWER_SUPPLY_STATUS_FULL;
1192 if (chip->ext_charging)
1193 return POWER_SUPPLY_STATUS_CHARGING;
1194 }
1195
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001196 for (i = 0; i < ARRAY_SIZE(map); i++)
1197 if (map[i].fsm_state == fsm_state)
1198 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001199
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001200 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1201 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1202 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001203 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1204 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001205
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001206 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001207 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001208 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209}
1210
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001211#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001212static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1213{
1214 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001215 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001216
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001217 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001218 if (rc) {
1219 pr_err("error reading adc channel = %d, rc = %d\n",
1220 chip->vbat_channel, rc);
1221 return rc;
1222 }
1223 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1224 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001225 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1226 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1227 (int) result.physical);
1228
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001229 return (int)result.physical;
1230}
1231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232static int pm_batt_power_get_property(struct power_supply *psy,
1233 enum power_supply_property psp,
1234 union power_supply_propval *val)
1235{
1236 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1237 batt_psy);
1238
1239 switch (psp) {
1240 case POWER_SUPPLY_PROP_STATUS:
1241 val->intval = get_prop_batt_status(chip);
1242 break;
1243 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1244 val->intval = get_prop_charge_type(chip);
1245 break;
1246 case POWER_SUPPLY_PROP_HEALTH:
1247 val->intval = get_prop_batt_health(chip);
1248 break;
1249 case POWER_SUPPLY_PROP_PRESENT:
1250 val->intval = get_prop_batt_present(chip);
1251 break;
1252 case POWER_SUPPLY_PROP_TECHNOLOGY:
1253 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1254 break;
1255 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001256 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 break;
1258 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001259 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 break;
1261 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001262 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263 break;
1264 case POWER_SUPPLY_PROP_CAPACITY:
1265 val->intval = get_prop_batt_capacity(chip);
1266 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001267 case POWER_SUPPLY_PROP_CURRENT_NOW:
1268 val->intval = get_prop_batt_current(chip);
1269 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001270 case POWER_SUPPLY_PROP_TEMP:
1271 val->intval = get_prop_batt_temp(chip);
1272 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001273 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001274 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001275 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 default:
1277 return -EINVAL;
1278 }
1279
1280 return 0;
1281}
1282
1283static void (*notify_vbus_state_func_ptr)(int);
1284static int usb_chg_current;
1285static DEFINE_SPINLOCK(vbus_lock);
1286
1287int pm8921_charger_register_vbus_sn(void (*callback)(int))
1288{
1289 pr_debug("%p\n", callback);
1290 notify_vbus_state_func_ptr = callback;
1291 return 0;
1292}
1293EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1294
1295/* this is passed to the hsusb via platform_data msm_otg_pdata */
1296void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1297{
1298 pr_debug("%p\n", callback);
1299 notify_vbus_state_func_ptr = NULL;
1300}
1301EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1302
1303static void notify_usb_of_the_plugin_event(int plugin)
1304{
1305 plugin = !!plugin;
1306 if (notify_vbus_state_func_ptr) {
1307 pr_debug("notifying plugin\n");
1308 (*notify_vbus_state_func_ptr) (plugin);
1309 } else {
1310 pr_debug("unable to notify plugin\n");
1311 }
1312}
1313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314/* assumes vbus_lock is held */
1315static void __pm8921_charger_vbus_draw(unsigned int mA)
1316{
1317 int i, rc;
1318
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001319 if (usb_max_current && mA > usb_max_current) {
1320 pr_warn("restricting usb current to %d instead of %d\n",
1321 usb_max_current, mA);
1322 mA = usb_max_current;
1323 }
1324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 if (mA > 0 && mA <= 2) {
1326 usb_chg_current = 0;
1327 rc = pm_chg_iusbmax_set(the_chip,
1328 usb_ma_table[0].chg_iusb_value);
1329 if (rc) {
1330 pr_err("unable to set iusb to %d rc = %d\n",
1331 usb_ma_table[0].chg_iusb_value, rc);
1332 }
1333 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1334 if (rc)
1335 pr_err("fail to set suspend bit rc=%d\n", rc);
1336 } else {
1337 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1338 if (rc)
1339 pr_err("fail to reset suspend bit rc=%d\n", rc);
1340 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1341 if (usb_ma_table[i].usb_ma <= mA)
1342 break;
1343 }
1344 if (i < 0)
1345 i = 0;
1346 rc = pm_chg_iusbmax_set(the_chip,
1347 usb_ma_table[i].chg_iusb_value);
1348 if (rc) {
1349 pr_err("unable to set iusb to %d rc = %d\n",
1350 usb_ma_table[i].chg_iusb_value, rc);
1351 }
1352 }
1353}
1354
1355/* USB calls these to tell us how much max usb current the system can draw */
1356void pm8921_charger_vbus_draw(unsigned int mA)
1357{
1358 unsigned long flags;
1359
1360 pr_debug("Enter charge=%d\n", mA);
1361 spin_lock_irqsave(&vbus_lock, flags);
1362 if (the_chip) {
1363 __pm8921_charger_vbus_draw(mA);
1364 } else {
1365 /*
1366 * called before pmic initialized,
1367 * save this value and use it at probe
1368 */
1369 usb_chg_current = mA;
1370 }
1371 spin_unlock_irqrestore(&vbus_lock, flags);
1372}
1373EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1374
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001375int pm8921_charger_enable(bool enable)
1376{
1377 int rc;
1378
1379 if (!the_chip) {
1380 pr_err("called before init\n");
1381 return -EINVAL;
1382 }
1383 enable = !!enable;
1384 rc = pm_chg_auto_enable(the_chip, enable);
1385 if (rc)
1386 pr_err("Failed rc=%d\n", rc);
1387 return rc;
1388}
1389EXPORT_SYMBOL(pm8921_charger_enable);
1390
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001391int pm8921_is_usb_chg_plugged_in(void)
1392{
1393 if (!the_chip) {
1394 pr_err("called before init\n");
1395 return -EINVAL;
1396 }
1397 return is_usb_chg_plugged_in(the_chip);
1398}
1399EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1400
1401int pm8921_is_dc_chg_plugged_in(void)
1402{
1403 if (!the_chip) {
1404 pr_err("called before init\n");
1405 return -EINVAL;
1406 }
1407 return is_dc_chg_plugged_in(the_chip);
1408}
1409EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1410
1411int pm8921_is_battery_present(void)
1412{
1413 if (!the_chip) {
1414 pr_err("called before init\n");
1415 return -EINVAL;
1416 }
1417 return get_prop_batt_present(the_chip);
1418}
1419EXPORT_SYMBOL(pm8921_is_battery_present);
1420
David Keitel012deef2011-12-02 11:49:33 -08001421/*
1422 * Disabling the charge current limit causes current
1423 * current limits to have no monitoring. An adequate charger
1424 * capable of supplying high current while sustaining VIN_MIN
1425 * is required if the limiting is disabled.
1426 */
1427int pm8921_disable_input_current_limit(bool disable)
1428{
1429 if (!the_chip) {
1430 pr_err("called before init\n");
1431 return -EINVAL;
1432 }
1433 if (disable) {
1434 pr_warn("Disabling input current limit!\n");
1435
1436 return pm8xxx_writeb(the_chip->dev->parent,
1437 CHG_BUCK_CTRL_TEST3, 0xF2);
1438 }
1439 return 0;
1440}
1441EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1442
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001443int pm8921_set_max_battery_charge_current(int ma)
1444{
1445 if (!the_chip) {
1446 pr_err("called before init\n");
1447 return -EINVAL;
1448 }
1449 return pm_chg_ibatmax_set(the_chip, ma);
1450}
1451EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1452
1453int pm8921_disable_source_current(bool disable)
1454{
1455 if (!the_chip) {
1456 pr_err("called before init\n");
1457 return -EINVAL;
1458 }
1459 if (disable)
1460 pr_warn("current drawn from chg=0, battery provides current\n");
1461 return pm_chg_charge_dis(the_chip, disable);
1462}
1463EXPORT_SYMBOL(pm8921_disable_source_current);
1464
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001465int pm8921_regulate_input_voltage(int voltage)
1466{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001467 int rc;
1468
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001469 if (!the_chip) {
1470 pr_err("called before init\n");
1471 return -EINVAL;
1472 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001473 rc = pm_chg_vinmin_set(the_chip, voltage);
1474
1475 if (rc == 0)
1476 the_chip->vin_min = voltage;
1477
1478 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001479}
1480
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001481#define USB_OV_THRESHOLD_MASK 0x60
1482#define USB_OV_THRESHOLD_SHIFT 5
1483int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1484{
1485 u8 temp;
1486
1487 if (!the_chip) {
1488 pr_err("called before init\n");
1489 return -EINVAL;
1490 }
1491
1492 if (ov > PM_USB_OV_7V) {
1493 pr_err("limiting to over voltage threshold to 7volts\n");
1494 ov = PM_USB_OV_7V;
1495 }
1496
1497 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1498
1499 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1500 USB_OV_THRESHOLD_MASK, temp);
1501}
1502EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1503
1504#define USB_DEBOUNCE_TIME_MASK 0x06
1505#define USB_DEBOUNCE_TIME_SHIFT 1
1506int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1507{
1508 u8 temp;
1509
1510 if (!the_chip) {
1511 pr_err("called before init\n");
1512 return -EINVAL;
1513 }
1514
1515 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1516 pr_err("limiting debounce to 80.5ms\n");
1517 ms = PM_USB_DEBOUNCE_80P5MS;
1518 }
1519
1520 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1521
1522 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1523 USB_DEBOUNCE_TIME_MASK, temp);
1524}
1525EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1526
1527#define USB_OVP_DISABLE_MASK 0x80
1528int pm8921_usb_ovp_disable(int disable)
1529{
1530 u8 temp = 0;
1531
1532 if (!the_chip) {
1533 pr_err("called before init\n");
1534 return -EINVAL;
1535 }
1536
1537 if (disable)
1538 temp = USB_OVP_DISABLE_MASK;
1539
1540 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1541 USB_OVP_DISABLE_MASK, temp);
1542}
1543
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001544bool pm8921_is_battery_charging(int *source)
1545{
1546 int fsm_state, is_charging, dc_present, usb_present;
1547
1548 if (!the_chip) {
1549 pr_err("called before init\n");
1550 return -EINVAL;
1551 }
1552 fsm_state = pm_chg_get_fsm_state(the_chip);
1553 is_charging = is_battery_charging(fsm_state);
1554 if (is_charging == 0) {
1555 *source = PM8921_CHG_SRC_NONE;
1556 return is_charging;
1557 }
1558
1559 if (source == NULL)
1560 return is_charging;
1561
1562 /* the battery is charging, the source is requested, find it */
1563 dc_present = is_dc_chg_plugged_in(the_chip);
1564 usb_present = is_usb_chg_plugged_in(the_chip);
1565
1566 if (dc_present && !usb_present)
1567 *source = PM8921_CHG_SRC_DC;
1568
1569 if (usb_present && !dc_present)
1570 *source = PM8921_CHG_SRC_USB;
1571
1572 if (usb_present && dc_present)
1573 /*
1574 * The system always chooses dc for charging since it has
1575 * higher priority.
1576 */
1577 *source = PM8921_CHG_SRC_DC;
1578
1579 return is_charging;
1580}
1581EXPORT_SYMBOL(pm8921_is_battery_charging);
1582
David Keitel6df9cea2011-12-21 12:36:45 -08001583int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1584{
1585 if (!the_chip) {
1586 pr_err("called before init\n");
1587 return -EINVAL;
1588 }
1589
1590 if (type < POWER_SUPPLY_TYPE_USB)
1591 return -EINVAL;
1592
1593 the_chip->usb_psy.type = type;
1594 power_supply_changed(&the_chip->usb_psy);
1595 return 0;
1596}
1597EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1598
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001599int pm8921_batt_temperature(void)
1600{
1601 if (!the_chip) {
1602 pr_err("called before init\n");
1603 return -EINVAL;
1604 }
1605 return get_prop_batt_temp(the_chip);
1606}
1607
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1609{
1610 int usb_present;
1611
1612 usb_present = is_usb_chg_plugged_in(chip);
1613 if (chip->usb_present ^ usb_present) {
1614 notify_usb_of_the_plugin_event(usb_present);
1615 chip->usb_present = usb_present;
1616 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001617 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001619 if (usb_present) {
1620 schedule_delayed_work(&chip->unplug_check_work,
1621 round_jiffies_relative(msecs_to_jiffies
1622 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1623 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001624 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625}
1626
Amir Samuelovd31ef502011-10-26 14:41:36 +02001627static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1628{
David Keitel88e1b572012-01-11 11:57:14 -08001629 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001630 pr_debug("external charger not registered.\n");
1631 return;
1632 }
1633
1634 if (!chip->ext_charging) {
1635 pr_debug("already not charging.\n");
1636 return;
1637 }
1638
David Keitel88e1b572012-01-11 11:57:14 -08001639 power_supply_set_charge_type(chip->ext_psy,
1640 POWER_SUPPLY_CHARGE_TYPE_NONE);
1641 pm8921_disable_source_current(false); /* release BATFET */
Amir Samuelovd31ef502011-10-26 14:41:36 +02001642 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001643 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001644 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001645}
1646
1647static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1648{
1649 int dc_present;
1650 int batt_present;
1651 int batt_temp_ok;
1652 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001653 unsigned long delay =
1654 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1655
David Keitel88e1b572012-01-11 11:57:14 -08001656 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001657 pr_debug("external charger not registered.\n");
1658 return;
1659 }
1660
1661 if (chip->ext_charging) {
1662 pr_debug("already charging.\n");
1663 return;
1664 }
1665
David Keitel88e1b572012-01-11 11:57:14 -08001666 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001667 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1668 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001669
1670 if (!dc_present) {
1671 pr_warn("%s. dc not present.\n", __func__);
1672 return;
1673 }
1674 if (!batt_present) {
1675 pr_warn("%s. battery not present.\n", __func__);
1676 return;
1677 }
1678 if (!batt_temp_ok) {
1679 pr_warn("%s. battery temperature not ok.\n", __func__);
1680 return;
1681 }
David Keitel88e1b572012-01-11 11:57:14 -08001682 pm8921_disable_source_current(true); /* Force BATFET=ON */
1683 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001684 if (vbat_ov) {
1685 pr_warn("%s. battery over voltage.\n", __func__);
1686 return;
1687 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001688
David Keitel88e1b572012-01-11 11:57:14 -08001689 power_supply_set_charge_type(chip->ext_psy,
1690 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001691 chip->ext_charging = true;
1692 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001693 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001694 /* Start BMS */
1695 schedule_delayed_work(&chip->eoc_work, delay);
1696 wake_lock(&chip->eoc_wake_lock);
1697}
1698
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001699#define WRITE_BANK_4 0xC0
1700static void unplug_wrkarnd_restore_worker(struct work_struct *work)
1701{
1702 u8 temp;
1703 int rc;
1704 struct delayed_work *dwork = to_delayed_work(work);
1705 struct pm8921_chg_chip *chip = container_of(dwork,
1706 struct pm8921_chg_chip,
1707 unplug_wrkarnd_restore_work);
1708
1709 pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
1710 rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
1711
1712 temp = WRITE_BANK_4 | 0xA;
1713 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1714 if (rc) {
1715 pr_err("Error %d writing %d to addr %d\n", rc,
1716 temp, CHG_BUCK_CTRL_TEST3);
1717 }
1718 wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
1719}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1721{
1722 handle_usb_insertion_removal(data);
1723 return IRQ_HANDLED;
1724}
1725
1726static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1727{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001728 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 return IRQ_HANDLED;
1730}
1731
1732static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1733{
1734 struct pm8921_chg_chip *chip = data;
1735 int status;
1736
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001737 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1738 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001739 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 pr_debug("battery present=%d", status);
1741 power_supply_changed(&chip->batt_psy);
1742 return IRQ_HANDLED;
1743}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001744
1745/*
1746 * this interrupt used to restart charging a battery.
1747 *
1748 * Note: When DC-inserted the VBAT can't go low.
1749 * VPH_PWR is provided by the ext-charger.
1750 * After End-Of-Charging from DC, charging can be resumed only
1751 * if DC is removed and then inserted after the battery was in use.
1752 * Therefore the handle_start_ext_chg() is not called.
1753 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1755{
1756 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001757 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001759 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001760
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001761 if (high_transition) {
1762 /* enable auto charging */
1763 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001764 pr_info("batt fell below resume voltage %s\n",
1765 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001766 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 power_supply_changed(&chip->batt_psy);
1770 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 return IRQ_HANDLED;
1773}
1774
1775static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1776{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001777 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 return IRQ_HANDLED;
1779}
1780
1781static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1782{
1783 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1784 return IRQ_HANDLED;
1785}
1786
1787static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1788{
1789 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1790 return IRQ_HANDLED;
1791}
1792
1793static irqreturn_t vcp_irq_handler(int irq, void *data)
1794{
1795 pr_warning("VCP triggered BATDET forced on\n");
1796 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1797 return IRQ_HANDLED;
1798}
1799
1800static irqreturn_t atcdone_irq_handler(int irq, void *data)
1801{
1802 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1803 return IRQ_HANDLED;
1804}
1805
1806static irqreturn_t atcfail_irq_handler(int irq, void *data)
1807{
1808 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1809 return IRQ_HANDLED;
1810}
1811
1812static irqreturn_t chgdone_irq_handler(int irq, void *data)
1813{
1814 struct pm8921_chg_chip *chip = data;
1815
1816 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001817
1818 handle_stop_ext_chg(chip);
1819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 power_supply_changed(&chip->batt_psy);
1821 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001822
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001823 bms_notify_check(chip);
1824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 return IRQ_HANDLED;
1826}
1827
1828static irqreturn_t chgfail_irq_handler(int irq, void *data)
1829{
1830 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001831 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832
David Keitel753ec8d2011-11-02 10:56:37 -07001833 ret = pm_chg_failed_clear(chip, 1);
1834 if (ret)
1835 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1836
1837 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1838 get_prop_batt_present(chip),
1839 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1840 pm_chg_get_fsm_state(data));
1841
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 power_supply_changed(&chip->batt_psy);
1843 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 return IRQ_HANDLED;
1845}
1846
1847static irqreturn_t chgstate_irq_handler(int irq, void *data)
1848{
1849 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850
1851 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1852 power_supply_changed(&chip->batt_psy);
1853 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001854
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001855 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 return IRQ_HANDLED;
1858}
1859
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001860#define VIN_ACTIVE_BIT BIT(0)
1861#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
1862#define VIN_MIN_INCREASE_MV 100
1863static void unplug_check_worker(struct work_struct *work)
1864{
1865 struct delayed_work *dwork = to_delayed_work(work);
1866 struct pm8921_chg_chip *chip = container_of(dwork,
1867 struct pm8921_chg_chip, unplug_check_work);
1868 u8 reg_loop;
1869 int ibat, usb_chg_plugged_in;
1870
1871 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1872 if (!usb_chg_plugged_in) {
1873 pr_debug("Stopping Unplug Check Worker since USB is removed"
1874 "reg_loop = %d, fsm = %d ibat = %d\n",
1875 pm_chg_get_regulation_loop(chip),
1876 pm_chg_get_fsm_state(chip),
1877 get_prop_batt_current(chip)
1878 );
1879 return;
1880 }
1881 reg_loop = pm_chg_get_regulation_loop(chip);
1882 pr_debug("reg_loop=0x%x\n", reg_loop);
1883
1884 if (reg_loop & VIN_ACTIVE_BIT) {
1885 ibat = get_prop_batt_current(chip);
1886
1887 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
1888 ibat, pm_chg_get_fsm_state(chip), reg_loop);
1889 if (ibat > 0) {
1890 int err;
1891 u8 temp;
1892
1893 temp = WRITE_BANK_4 | 0xE;
1894 err = pm8xxx_writeb(chip->dev->parent,
1895 CHG_BUCK_CTRL_TEST3, temp);
1896 if (err) {
1897 pr_err("Error %d writing %d to addr %d\n", err,
1898 temp, CHG_BUCK_CTRL_TEST3);
1899 }
1900
1901 pm_chg_vinmin_set(chip,
1902 chip->vin_min + VIN_MIN_INCREASE_MV);
1903
1904 wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
1905 schedule_delayed_work(
1906 &chip->unplug_wrkarnd_restore_work,
1907 round_jiffies_relative(usecs_to_jiffies
1908 (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
1909 }
1910 }
1911
1912 schedule_delayed_work(&chip->unplug_check_work,
1913 round_jiffies_relative(msecs_to_jiffies
1914 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1915}
1916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917static irqreturn_t loop_change_irq_handler(int irq, void *data)
1918{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001919 struct pm8921_chg_chip *chip = data;
1920
1921 pr_debug("fsm_state=%d reg_loop=0x%x\n",
1922 pm_chg_get_fsm_state(data),
1923 pm_chg_get_regulation_loop(data));
1924 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 return IRQ_HANDLED;
1926}
1927
1928static irqreturn_t fastchg_irq_handler(int irq, void *data)
1929{
1930 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001931 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001932
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001933 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1934 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
1935 wake_lock(&chip->eoc_wake_lock);
1936 schedule_delayed_work(&chip->eoc_work,
1937 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001938 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001939 }
1940 power_supply_changed(&chip->batt_psy);
1941 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 return IRQ_HANDLED;
1943}
1944
1945static irqreturn_t trklchg_irq_handler(int irq, void *data)
1946{
1947 struct pm8921_chg_chip *chip = data;
1948
1949 power_supply_changed(&chip->batt_psy);
1950 return IRQ_HANDLED;
1951}
1952
1953static irqreturn_t batt_removed_irq_handler(int irq, void *data)
1954{
1955 struct pm8921_chg_chip *chip = data;
1956 int status;
1957
1958 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
1959 pr_debug("battery present=%d state=%d", !status,
1960 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001961 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 power_supply_changed(&chip->batt_psy);
1963 return IRQ_HANDLED;
1964}
1965
1966static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
1967{
1968 struct pm8921_chg_chip *chip = data;
1969
Amir Samuelovd31ef502011-10-26 14:41:36 +02001970 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 power_supply_changed(&chip->batt_psy);
1972 return IRQ_HANDLED;
1973}
1974
1975static irqreturn_t chghot_irq_handler(int irq, void *data)
1976{
1977 struct pm8921_chg_chip *chip = data;
1978
1979 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
1980 power_supply_changed(&chip->batt_psy);
1981 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08001982 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 return IRQ_HANDLED;
1984}
1985
1986static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
1987{
1988 struct pm8921_chg_chip *chip = data;
1989
1990 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001991 handle_stop_ext_chg(chip);
1992
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 power_supply_changed(&chip->batt_psy);
1994 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001995 return IRQ_HANDLED;
1996}
1997
1998static irqreturn_t chg_gone_irq_handler(int irq, void *data)
1999{
2000 struct pm8921_chg_chip *chip = data;
2001
2002 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2003 power_supply_changed(&chip->batt_psy);
2004 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002005 return IRQ_HANDLED;
2006}
David Keitel52fda532011-11-10 10:43:44 -08002007/*
2008 *
2009 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2010 * fire for two cases:
2011 *
2012 * If the interrupt line switches to high temperature is okay
2013 * and thus charging begins.
2014 * If bat_temp_ok is low this means the temperature is now
2015 * too hot or cold, so charging is stopped.
2016 *
2017 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2019{
David Keitel52fda532011-11-10 10:43:44 -08002020 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 struct pm8921_chg_chip *chip = data;
2022
David Keitel52fda532011-11-10 10:43:44 -08002023 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2024
2025 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2026 bat_temp_ok, pm_chg_get_fsm_state(data));
2027
2028 if (bat_temp_ok)
2029 handle_start_ext_chg(chip);
2030 else
2031 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 power_supply_changed(&chip->batt_psy);
2034 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002035 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002036 return IRQ_HANDLED;
2037}
2038
2039static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2040{
2041 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2042 return IRQ_HANDLED;
2043}
2044
2045static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2046{
2047 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2048 return IRQ_HANDLED;
2049}
2050
2051static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2052{
2053 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2054 return IRQ_HANDLED;
2055}
2056
2057static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2058{
2059 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2060 return IRQ_HANDLED;
2061}
2062
2063static irqreturn_t batfet_irq_handler(int irq, void *data)
2064{
2065 struct pm8921_chg_chip *chip = data;
2066
2067 pr_debug("vreg ov\n");
2068 power_supply_changed(&chip->batt_psy);
2069 return IRQ_HANDLED;
2070}
2071
2072static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2073{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002074 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002075 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002076
David Keitel88e1b572012-01-11 11:57:14 -08002077 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2078 if (chip->ext_psy)
2079 power_supply_set_online(chip->ext_psy, dc_present);
2080 chip->dc_present = dc_present;
2081 if (dc_present)
2082 handle_start_ext_chg(chip);
2083 else
2084 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 return IRQ_HANDLED;
2086}
2087
2088static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2089{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002090 struct pm8921_chg_chip *chip = data;
2091
Amir Samuelovd31ef502011-10-26 14:41:36 +02002092 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 return IRQ_HANDLED;
2094}
2095
2096static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2097{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002098 struct pm8921_chg_chip *chip = data;
2099
Amir Samuelovd31ef502011-10-26 14:41:36 +02002100 handle_stop_ext_chg(chip);
2101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 return IRQ_HANDLED;
2103}
2104
David Keitel88e1b572012-01-11 11:57:14 -08002105static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2106{
2107 struct power_supply *psy = &the_chip->batt_psy;
2108 struct power_supply *epsy = dev_get_drvdata(dev);
2109 int i, dcin_irq;
2110
2111 /* Only search for external supply if none is registered */
2112 if (!the_chip->ext_psy) {
2113 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2114 for (i = 0; i < epsy->num_supplicants; i++) {
2115 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2116 if (!strncmp(epsy->name, "dc", 2)) {
2117 the_chip->ext_psy = epsy;
2118 dcin_valid_irq_handler(dcin_irq,
2119 the_chip);
2120 }
2121 }
2122 }
2123 }
2124 return 0;
2125}
2126
2127static void pm_batt_external_power_changed(struct power_supply *psy)
2128{
2129 /* Only look for an external supply if it hasn't been registered */
2130 if (!the_chip->ext_psy)
2131 class_for_each_device(power_supply_class, NULL, psy,
2132 __pm_batt_external_power_changed_work);
2133}
2134
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002135/**
2136 * update_heartbeat - internal function to update userspace
2137 * per update_time minutes
2138 *
2139 */
2140static void update_heartbeat(struct work_struct *work)
2141{
2142 struct delayed_work *dwork = to_delayed_work(work);
2143 struct pm8921_chg_chip *chip = container_of(dwork,
2144 struct pm8921_chg_chip, update_heartbeat_work);
2145
2146 power_supply_changed(&chip->batt_psy);
2147 schedule_delayed_work(&chip->update_heartbeat_work,
2148 round_jiffies_relative(msecs_to_jiffies
2149 (chip->update_time)));
2150}
2151
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002152enum {
2153 CHG_IN_PROGRESS,
2154 CHG_NOT_IN_PROGRESS,
2155 CHG_FINISHED,
2156};
2157
2158#define VBAT_TOLERANCE_MV 70
2159#define CHG_DISABLE_MSLEEP 100
2160static int is_charging_finished(struct pm8921_chg_chip *chip)
2161{
2162 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2163 int ichg_meas_ma, iterm_programmed;
2164 int regulation_loop, fast_chg, vcp;
2165 int rc;
2166 static int last_vbat_programmed = -EINVAL;
2167
2168 if (!is_ext_charging(chip)) {
2169 /* return if the battery is not being fastcharged */
2170 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2171 pr_debug("fast_chg = %d\n", fast_chg);
2172 if (fast_chg == 0)
2173 return CHG_NOT_IN_PROGRESS;
2174
2175 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2176 pr_debug("vcp = %d\n", vcp);
2177 if (vcp == 1)
2178 return CHG_IN_PROGRESS;
2179
2180 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2181 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2182 if (vbatdet_low == 1)
2183 return CHG_IN_PROGRESS;
2184
2185 /* reset count if battery is hot/cold */
2186 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2187 pr_debug("batt_temp_ok = %d\n", rc);
2188 if (rc == 0)
2189 return CHG_IN_PROGRESS;
2190
2191 /* reset count if battery voltage is less than vddmax */
2192 vbat_meas_uv = get_prop_battery_uvolts(chip);
2193 if (vbat_meas_uv < 0)
2194 return CHG_IN_PROGRESS;
2195 vbat_meas_mv = vbat_meas_uv / 1000;
2196
2197 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2198 if (rc) {
2199 pr_err("couldnt read vddmax rc = %d\n", rc);
2200 return CHG_IN_PROGRESS;
2201 }
2202 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2203 vbat_programmed, vbat_meas_mv);
2204 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2205 return CHG_IN_PROGRESS;
2206
2207 if (last_vbat_programmed == -EINVAL)
2208 last_vbat_programmed = vbat_programmed;
2209 if (last_vbat_programmed != vbat_programmed) {
2210 /* vddmax changed, reset and check again */
2211 pr_debug("vddmax = %d last_vdd_max=%d\n",
2212 vbat_programmed, last_vbat_programmed);
2213 last_vbat_programmed = vbat_programmed;
2214 return CHG_IN_PROGRESS;
2215 }
2216
2217 /*
2218 * TODO if charging from an external charger
2219 * check SOC instead of regulation loop
2220 */
2221 regulation_loop = pm_chg_get_regulation_loop(chip);
2222 if (regulation_loop < 0) {
2223 pr_err("couldnt read the regulation loop err=%d\n",
2224 regulation_loop);
2225 return CHG_IN_PROGRESS;
2226 }
2227 pr_debug("regulation_loop=%d\n", regulation_loop);
2228
2229 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2230 return CHG_IN_PROGRESS;
2231 } /* !is_ext_charging */
2232
2233 /* reset count if battery chg current is more than iterm */
2234 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2235 if (rc) {
2236 pr_err("couldnt read iterm rc = %d\n", rc);
2237 return CHG_IN_PROGRESS;
2238 }
2239
2240 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2241 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2242 iterm_programmed, ichg_meas_ma);
2243 /*
2244 * ichg_meas_ma < 0 means battery is drawing current
2245 * ichg_meas_ma > 0 means battery is providing current
2246 */
2247 if (ichg_meas_ma > 0)
2248 return CHG_IN_PROGRESS;
2249
2250 if (ichg_meas_ma * -1 > iterm_programmed)
2251 return CHG_IN_PROGRESS;
2252
2253 return CHG_FINISHED;
2254}
2255
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002256/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002257 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002258 * has happened
2259 *
2260 * If all conditions favouring, if the charge current is
2261 * less than the term current for three consecutive times
2262 * an EOC has happened.
2263 * The wakelock is released if there is no need to reshedule
2264 * - this happens when the battery is removed or EOC has
2265 * happened
2266 */
2267#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002268static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002269{
2270 struct delayed_work *dwork = to_delayed_work(work);
2271 struct pm8921_chg_chip *chip = container_of(dwork,
2272 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002273 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002274 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002275
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002276 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002277 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002278 count = 0;
2279 wake_unlock(&chip->eoc_wake_lock);
2280 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002281 }
2282
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002283 if (end == CHG_FINISHED) {
2284 count++;
2285 } else {
2286 count = 0;
2287 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002288
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002289 if (count == CONSECUTIVE_COUNT) {
2290 count = 0;
2291 pr_info("End of Charging\n");
2292
2293 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002294
Amir Samuelovd31ef502011-10-26 14:41:36 +02002295 if (is_ext_charging(chip))
2296 chip->ext_charge_done = true;
2297
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002298 if (chip->is_bat_warm || chip->is_bat_cool)
2299 chip->bms_notify.is_battery_full = 0;
2300 else
2301 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002302 /* declare end of charging by invoking chgdone interrupt */
2303 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2304 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002305 } else {
2306 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002307 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002308 round_jiffies_relative(msecs_to_jiffies
2309 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002310 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002311}
2312
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002313static void btm_configure_work(struct work_struct *work)
2314{
2315 int rc;
2316
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002317 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002318 if (rc)
2319 pr_err("failed to configure btm rc=%d", rc);
2320}
2321
2322DECLARE_WORK(btm_config_work, btm_configure_work);
2323
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002324static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2325{
2326 unsigned int chg_current = chip->max_bat_chg_current;
2327
2328 if (chip->is_bat_cool)
2329 chg_current = min(chg_current, chip->cool_bat_chg_current);
2330
2331 if (chip->is_bat_warm)
2332 chg_current = min(chg_current, chip->warm_bat_chg_current);
2333
David Keitelfdef3a42011-12-14 19:02:54 -08002334 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002335 chg_current = min(chg_current,
2336 chip->thermal_mitigation[thermal_mitigation]);
2337
2338 pm_chg_ibatmax_set(the_chip, chg_current);
2339}
2340
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002341#define TEMP_HYSTERISIS_DEGC 2
2342static void battery_cool(bool enter)
2343{
2344 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002345 if (enter == the_chip->is_bat_cool)
2346 return;
2347 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002348 if (enter) {
2349 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002350 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002351 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002352 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002353 pm_chg_vbatdet_set(the_chip,
2354 the_chip->cool_bat_voltage
2355 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002356 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002357 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002358 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002359 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002360 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002361 the_chip->max_voltage_mv
2362 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002363 }
2364 schedule_work(&btm_config_work);
2365}
2366
2367static void battery_warm(bool enter)
2368{
2369 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002370 if (enter == the_chip->is_bat_warm)
2371 return;
2372 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002373 if (enter) {
2374 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002375 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002376 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002377 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002378 pm_chg_vbatdet_set(the_chip,
2379 the_chip->warm_bat_voltage
2380 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002381 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002382 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002383 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002384 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002385 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002386 the_chip->max_voltage_mv
2387 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002388 }
2389 schedule_work(&btm_config_work);
2390}
2391
2392static int configure_btm(struct pm8921_chg_chip *chip)
2393{
2394 int rc;
2395
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002396 if (chip->warm_temp_dc != INT_MIN)
2397 btm_config.btm_warm_fn = battery_warm;
2398 else
2399 btm_config.btm_warm_fn = NULL;
2400
2401 if (chip->cool_temp_dc != INT_MIN)
2402 btm_config.btm_cool_fn = battery_cool;
2403 else
2404 btm_config.btm_cool_fn = NULL;
2405
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002406 btm_config.low_thr_temp = chip->cool_temp_dc;
2407 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002408 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002409 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002410 if (rc)
2411 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002412 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002413 if (rc)
2414 pr_err("failed to start btm rc = %d\n", rc);
2415
2416 return rc;
2417}
2418
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002419/**
2420 * set_disable_status_param -
2421 *
2422 * Internal function to disable battery charging and also disable drawing
2423 * any current from the source. The device is forced to run on a battery
2424 * after this.
2425 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426static int set_disable_status_param(const char *val, struct kernel_param *kp)
2427{
2428 int ret;
2429 struct pm8921_chg_chip *chip = the_chip;
2430
2431 ret = param_set_int(val, kp);
2432 if (ret) {
2433 pr_err("error setting value %d\n", ret);
2434 return ret;
2435 }
2436 pr_info("factory set disable param to %d\n", charging_disabled);
2437 if (chip) {
2438 pm_chg_auto_enable(chip, !charging_disabled);
2439 pm_chg_charge_dis(chip, charging_disabled);
2440 }
2441 return 0;
2442}
2443module_param_call(disabled, set_disable_status_param, param_get_uint,
2444 &charging_disabled, 0644);
2445
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002446/**
2447 * set_thermal_mitigation_level -
2448 *
2449 * Internal function to control battery charging current to reduce
2450 * temperature
2451 */
2452static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2453{
2454 int ret;
2455 struct pm8921_chg_chip *chip = the_chip;
2456
2457 ret = param_set_int(val, kp);
2458 if (ret) {
2459 pr_err("error setting value %d\n", ret);
2460 return ret;
2461 }
2462
2463 if (!chip) {
2464 pr_err("called before init\n");
2465 return -EINVAL;
2466 }
2467
2468 if (!chip->thermal_mitigation) {
2469 pr_err("no thermal mitigation\n");
2470 return -EINVAL;
2471 }
2472
2473 if (thermal_mitigation < 0
2474 || thermal_mitigation >= chip->thermal_levels) {
2475 pr_err("out of bound level selected\n");
2476 return -EINVAL;
2477 }
2478
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002479 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002480 return ret;
2481}
2482module_param_call(thermal_mitigation, set_therm_mitigation_level,
2483 param_get_uint,
2484 &thermal_mitigation, 0644);
2485
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002486static int set_usb_max_current(const char *val, struct kernel_param *kp)
2487{
2488 int ret, mA;
2489 struct pm8921_chg_chip *chip = the_chip;
2490
2491 ret = param_set_int(val, kp);
2492 if (ret) {
2493 pr_err("error setting value %d\n", ret);
2494 return ret;
2495 }
2496 if (chip) {
2497 pr_warn("setting current max to %d\n", usb_max_current);
2498 pm_chg_iusbmax_get(chip, &mA);
2499 if (mA > usb_max_current)
2500 pm8921_charger_vbus_draw(usb_max_current);
2501 return 0;
2502 }
2503 return -EINVAL;
2504}
2505module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2506 &usb_max_current, 0644);
2507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508static void free_irqs(struct pm8921_chg_chip *chip)
2509{
2510 int i;
2511
2512 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2513 if (chip->pmic_chg_irq[i]) {
2514 free_irq(chip->pmic_chg_irq[i], chip);
2515 chip->pmic_chg_irq[i] = 0;
2516 }
2517}
2518
David Keitel88e1b572012-01-11 11:57:14 -08002519/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2521{
2522 unsigned long flags;
2523 int fsm_state;
2524
2525 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2526 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2527
2528 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002529 if (chip->usb_present) {
2530 schedule_delayed_work(&chip->unplug_check_work,
2531 round_jiffies_relative(msecs_to_jiffies
2532 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2533 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534
2535 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2536 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2537 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002538 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2539 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2540 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2541 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2542 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002543 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002544 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2545 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002546 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547
2548 spin_lock_irqsave(&vbus_lock, flags);
2549 if (usb_chg_current) {
2550 /* reissue a vbus draw call */
2551 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002552 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553 }
2554 spin_unlock_irqrestore(&vbus_lock, flags);
2555
2556 fsm_state = pm_chg_get_fsm_state(chip);
2557 if (is_battery_charging(fsm_state)) {
2558 chip->bms_notify.is_charging = 1;
2559 pm8921_bms_charging_began();
2560 }
2561
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002562 check_battery_valid(chip);
2563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2565 chip->usb_present,
2566 chip->dc_present,
2567 get_prop_batt_present(chip),
2568 fsm_state);
2569}
2570
2571struct pm_chg_irq_init_data {
2572 unsigned int irq_id;
2573 char *name;
2574 unsigned long flags;
2575 irqreturn_t (*handler)(int, void *);
2576};
2577
2578#define CHG_IRQ(_id, _flags, _handler) \
2579{ \
2580 .irq_id = _id, \
2581 .name = #_id, \
2582 .flags = _flags, \
2583 .handler = _handler, \
2584}
2585struct pm_chg_irq_init_data chg_irq_data[] = {
2586 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2587 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002588 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2590 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002591 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2592 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2594 usbin_uv_irq_handler),
2595 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2596 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2597 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2598 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2599 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2600 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2601 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2602 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2603 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002604 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2605 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2607 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2608 batt_removed_irq_handler),
2609 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2610 batttemp_hot_irq_handler),
2611 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2612 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2613 batttemp_cold_irq_handler),
2614 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002615 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2616 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2618 coarse_det_low_irq_handler),
2619 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2620 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2621 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2622 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2623 batfet_irq_handler),
2624 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2625 dcin_valid_irq_handler),
2626 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2627 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002628 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629};
2630
2631static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2632 struct platform_device *pdev)
2633{
2634 struct resource *res;
2635 int ret, i;
2636
2637 ret = 0;
2638 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2639
2640 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2641 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2642 chg_irq_data[i].name);
2643 if (res == NULL) {
2644 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2645 goto err_out;
2646 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002647 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002648 ret = request_irq(res->start, chg_irq_data[i].handler,
2649 chg_irq_data[i].flags,
2650 chg_irq_data[i].name, chip);
2651 if (ret < 0) {
2652 pr_err("couldn't request %d (%s) %d\n", res->start,
2653 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002654 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655 goto err_out;
2656 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2658 }
2659 return 0;
2660
2661err_out:
2662 free_irqs(chip);
2663 return -EINVAL;
2664}
2665
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002666static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2667{
2668 int err;
2669 u8 temp;
2670
2671 temp = 0xD1;
2672 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2673 if (err) {
2674 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2675 return;
2676 }
2677
2678 temp = 0xD3;
2679 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2680 if (err) {
2681 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2682 return;
2683 }
2684
2685 temp = 0xD1;
2686 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2687 if (err) {
2688 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2689 return;
2690 }
2691
2692 temp = 0xD5;
2693 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2694 if (err) {
2695 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2696 return;
2697 }
2698
2699 udelay(183);
2700
2701 temp = 0xD1;
2702 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2703 if (err) {
2704 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2705 return;
2706 }
2707
2708 temp = 0xD0;
2709 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2710 if (err) {
2711 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2712 return;
2713 }
2714 udelay(32);
2715
2716 temp = 0xD1;
2717 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2718 if (err) {
2719 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2720 return;
2721 }
2722
2723 temp = 0xD3;
2724 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2725 if (err) {
2726 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2727 return;
2728 }
2729}
2730
2731static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2732{
2733 int err;
2734 u8 temp;
2735
2736 temp = 0xD1;
2737 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2738 if (err) {
2739 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2740 return;
2741 }
2742
2743 temp = 0xD0;
2744 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2745 if (err) {
2746 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2747 return;
2748 }
2749}
2750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751#define ENUM_TIMER_STOP_BIT BIT(1)
2752#define BOOT_DONE_BIT BIT(6)
2753#define CHG_BATFET_ON_BIT BIT(3)
2754#define CHG_VCP_EN BIT(0)
2755#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2756#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002757#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2759{
2760 int rc;
2761
2762 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2763 BOOT_DONE_BIT, BOOT_DONE_BIT);
2764 if (rc) {
2765 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2766 return rc;
2767 }
2768
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002769 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770 if (rc) {
2771 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002772 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 return rc;
2774 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002775 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002776 chip->max_voltage_mv
2777 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 if (rc) {
2779 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002780 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002781 return rc;
2782 }
2783
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002784 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 if (rc) {
2786 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002787 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 return rc;
2789 }
2790 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2791 if (rc) {
2792 pr_err("Failed to set max voltage to %d rc=%d\n",
2793 SAFE_CURRENT_MA, rc);
2794 return rc;
2795 }
2796
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002797 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 if (rc) {
2799 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2800 return rc;
2801 }
2802
2803 rc = pm_chg_iterm_set(chip, chip->term_current);
2804 if (rc) {
2805 pr_err("Failed to set term current to %d rc=%d\n",
2806 chip->term_current, rc);
2807 return rc;
2808 }
2809
2810 /* Disable the ENUM TIMER */
2811 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2812 ENUM_TIMER_STOP_BIT);
2813 if (rc) {
2814 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2815 return rc;
2816 }
2817
2818 /* init with the lowest USB current */
2819 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
2820 if (rc) {
2821 pr_err("Failed to set usb max to %d rc=%d\n",
2822 usb_ma_table[0].chg_iusb_value, rc);
2823 return rc;
2824 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002825
2826 if (chip->safety_time != 0) {
2827 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
2828 if (rc) {
2829 pr_err("Failed to set max time to %d minutes rc=%d\n",
2830 chip->safety_time, rc);
2831 return rc;
2832 }
2833 }
2834
2835 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07002836 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002837 if (rc) {
2838 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
2839 chip->safety_time, rc);
2840 return rc;
2841 }
2842 }
2843
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002844 if (chip->vin_min != 0) {
2845 rc = pm_chg_vinmin_set(chip, chip->vin_min);
2846 if (rc) {
2847 pr_err("Failed to set vin min to %d mV rc=%d\n",
2848 chip->vin_min, rc);
2849 return rc;
2850 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002851 } else {
2852 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002853 }
2854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855 rc = pm_chg_disable_wd(chip);
2856 if (rc) {
2857 pr_err("Failed to disable wd rc=%d\n", rc);
2858 return rc;
2859 }
2860
2861 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
2862 CHG_BAT_TEMP_DIS_BIT, 0);
2863 if (rc) {
2864 pr_err("Failed to enable temp control chg rc=%d\n", rc);
2865 return rc;
2866 }
2867 /* switch to a 3.2Mhz for the buck */
2868 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
2869 if (rc) {
2870 pr_err("Failed to switch buck clk rc=%d\n", rc);
2871 return rc;
2872 }
2873
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07002874 if (chip->trkl_voltage != 0) {
2875 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
2876 if (rc) {
2877 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
2878 chip->trkl_voltage, rc);
2879 return rc;
2880 }
2881 }
2882
2883 if (chip->weak_voltage != 0) {
2884 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
2885 if (rc) {
2886 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
2887 chip->weak_voltage, rc);
2888 return rc;
2889 }
2890 }
2891
2892 if (chip->trkl_current != 0) {
2893 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
2894 if (rc) {
2895 pr_err("Failed to set trkl current to %dmA rc=%d\n",
2896 chip->trkl_voltage, rc);
2897 return rc;
2898 }
2899 }
2900
2901 if (chip->weak_current != 0) {
2902 rc = pm_chg_iweak_set(chip, chip->weak_current);
2903 if (rc) {
2904 pr_err("Failed to set weak current to %dmA rc=%d\n",
2905 chip->weak_current, rc);
2906 return rc;
2907 }
2908 }
2909
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07002910 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
2911 if (rc) {
2912 pr_err("Failed to set cold config %d rc=%d\n",
2913 chip->cold_thr, rc);
2914 }
2915
2916 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
2917 if (rc) {
2918 pr_err("Failed to set hot config %d rc=%d\n",
2919 chip->hot_thr, rc);
2920 }
2921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922 /* Workarounds for die 1.1 and 1.0 */
2923 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
2924 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002925 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
2926 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002927
2928 /* software workaround for correct battery_id detection */
2929 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
2930 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
2931 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
2932 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
2933 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
2934 udelay(100);
2935 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 }
2937
David Keitelb51995e2011-11-18 17:03:31 -08002938 /* Workarounds for die 3.0 */
2939 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
2940 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
2941
2942 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
2943
David Keitela3c0d822011-11-03 14:18:52 -07002944 /* Disable EOC FSM processing */
2945 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
2946
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002947 pm8921_chg_force_19p2mhz_clk(chip);
2948
2949 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
2950 VREF_BATT_THERM_FORCE_ON);
2951 if (rc)
2952 pr_err("Failed to Force Vref therm rc=%d\n", rc);
2953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 rc = pm_chg_charge_dis(chip, charging_disabled);
2955 if (rc) {
2956 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
2957 return rc;
2958 }
2959
2960 rc = pm_chg_auto_enable(chip, !charging_disabled);
2961 if (rc) {
2962 pr_err("Failed to enable charging rc=%d\n", rc);
2963 return rc;
2964 }
2965
2966 return 0;
2967}
2968
2969static int get_rt_status(void *data, u64 * val)
2970{
2971 int i = (int)data;
2972 int ret;
2973
2974 /* global irq number is passed in via data */
2975 ret = pm_chg_get_rt_status(the_chip, i);
2976 *val = ret;
2977 return 0;
2978}
2979DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
2980
2981static int get_fsm_status(void *data, u64 * val)
2982{
2983 u8 temp;
2984
2985 temp = pm_chg_get_fsm_state(the_chip);
2986 *val = temp;
2987 return 0;
2988}
2989DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
2990
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002991static int get_reg_loop(void *data, u64 * val)
2992{
2993 u8 temp;
2994
2995 if (!the_chip) {
2996 pr_err("%s called before init\n", __func__);
2997 return -EINVAL;
2998 }
2999 temp = pm_chg_get_regulation_loop(the_chip);
3000 *val = temp;
3001 return 0;
3002}
3003DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005static int get_reg(void *data, u64 * val)
3006{
3007 int addr = (int)data;
3008 int ret;
3009 u8 temp;
3010
3011 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3012 if (ret) {
3013 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3014 addr, temp, ret);
3015 return -EAGAIN;
3016 }
3017 *val = temp;
3018 return 0;
3019}
3020
3021static int set_reg(void *data, u64 val)
3022{
3023 int addr = (int)data;
3024 int ret;
3025 u8 temp;
3026
3027 temp = (u8) val;
3028 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3029 if (ret) {
3030 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3031 addr, temp, ret);
3032 return -EAGAIN;
3033 }
3034 return 0;
3035}
3036DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3037
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003038enum {
3039 BAT_WARM_ZONE,
3040 BAT_COOL_ZONE,
3041};
3042static int get_warm_cool(void *data, u64 * val)
3043{
3044 if (!the_chip) {
3045 pr_err("%s called before init\n", __func__);
3046 return -EINVAL;
3047 }
3048 if ((int)data == BAT_WARM_ZONE)
3049 *val = the_chip->is_bat_warm;
3050 if ((int)data == BAT_COOL_ZONE)
3051 *val = the_chip->is_bat_cool;
3052 return 0;
3053}
3054DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3057{
3058 int i;
3059
3060 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3061
3062 if (IS_ERR(chip->dent)) {
3063 pr_err("pmic charger couldnt create debugfs dir\n");
3064 return;
3065 }
3066
3067 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3068 (void *)CHG_CNTRL, &reg_fops);
3069 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3070 (void *)CHG_CNTRL_2, &reg_fops);
3071 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3072 (void *)CHG_CNTRL_3, &reg_fops);
3073 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3074 (void *)PBL_ACCESS1, &reg_fops);
3075 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3076 (void *)PBL_ACCESS2, &reg_fops);
3077 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3078 (void *)SYS_CONFIG_1, &reg_fops);
3079 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3080 (void *)SYS_CONFIG_2, &reg_fops);
3081 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3082 (void *)CHG_VDD_MAX, &reg_fops);
3083 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3084 (void *)CHG_VDD_SAFE, &reg_fops);
3085 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3086 (void *)CHG_VBAT_DET, &reg_fops);
3087 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3088 (void *)CHG_IBAT_MAX, &reg_fops);
3089 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3090 (void *)CHG_IBAT_SAFE, &reg_fops);
3091 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3092 (void *)CHG_VIN_MIN, &reg_fops);
3093 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3094 (void *)CHG_VTRICKLE, &reg_fops);
3095 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3096 (void *)CHG_ITRICKLE, &reg_fops);
3097 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3098 (void *)CHG_ITERM, &reg_fops);
3099 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3100 (void *)CHG_TCHG_MAX, &reg_fops);
3101 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3102 (void *)CHG_TWDOG, &reg_fops);
3103 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3104 (void *)CHG_TEMP_THRESH, &reg_fops);
3105 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3106 (void *)CHG_COMP_OVR, &reg_fops);
3107 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3108 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3109 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3110 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3111 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3112 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3113 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3114 (void *)CHG_TEST, &reg_fops);
3115
3116 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3117 &fsm_fops);
3118
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003119 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3120 &reg_loop_fops);
3121
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003122 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3123 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3124 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3125 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3128 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3129 debugfs_create_file(chg_irq_data[i].name, 0444,
3130 chip->dent,
3131 (void *)chg_irq_data[i].irq_id,
3132 &rt_fops);
3133 }
3134}
3135
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003136static int pm8921_charger_suspend_noirq(struct device *dev)
3137{
3138 int rc;
3139 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3140
3141 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3142 if (rc)
3143 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3144 pm8921_chg_set_hw_clk_switching(chip);
3145 return 0;
3146}
3147
3148static int pm8921_charger_resume_noirq(struct device *dev)
3149{
3150 int rc;
3151 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3152
3153 pm8921_chg_force_19p2mhz_clk(chip);
3154
3155 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3156 VREF_BATT_THERM_FORCE_ON);
3157 if (rc)
3158 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3159 return 0;
3160}
3161
David Keitelf2226022011-12-13 15:55:50 -08003162static int pm8921_charger_resume(struct device *dev)
3163{
3164 int rc;
3165 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3166
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003167 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003168 && !(chip->keep_btm_on_suspend)) {
3169 rc = pm8xxx_adc_btm_configure(&btm_config);
3170 if (rc)
3171 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3172
3173 rc = pm8xxx_adc_btm_start();
3174 if (rc)
3175 pr_err("couldn't restart btm rc=%d\n", rc);
3176 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003177 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3178 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3179 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3180 }
David Keitelf2226022011-12-13 15:55:50 -08003181 return 0;
3182}
3183
3184static int pm8921_charger_suspend(struct device *dev)
3185{
3186 int rc;
3187 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3188
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003189 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003190 && !(chip->keep_btm_on_suspend)) {
3191 rc = pm8xxx_adc_btm_end();
3192 if (rc)
3193 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3194 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003195
3196 if (is_usb_chg_plugged_in(chip)) {
3197 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3198 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3199 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003200
David Keitelf2226022011-12-13 15:55:50 -08003201 return 0;
3202}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3204{
3205 int rc = 0;
3206 struct pm8921_chg_chip *chip;
3207 const struct pm8921_charger_platform_data *pdata
3208 = pdev->dev.platform_data;
3209
3210 if (!pdata) {
3211 pr_err("missing platform data\n");
3212 return -EINVAL;
3213 }
3214
3215 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3216 GFP_KERNEL);
3217 if (!chip) {
3218 pr_err("Cannot allocate pm_chg_chip\n");
3219 return -ENOMEM;
3220 }
3221
3222 chip->dev = &pdev->dev;
3223 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003224 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003225 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003226 chip->max_voltage_mv = pdata->max_voltage;
3227 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003228 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003229 chip->term_current = pdata->term_current;
3230 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003231 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003232 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3233 chip->batt_id_min = pdata->batt_id_min;
3234 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003235 if (pdata->cool_temp != INT_MIN)
3236 chip->cool_temp_dc = pdata->cool_temp * 10;
3237 else
3238 chip->cool_temp_dc = INT_MIN;
3239
3240 if (pdata->warm_temp != INT_MIN)
3241 chip->warm_temp_dc = pdata->warm_temp * 10;
3242 else
3243 chip->warm_temp_dc = INT_MIN;
3244
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003245 chip->temp_check_period = pdata->temp_check_period;
3246 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3247 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3248 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3249 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3250 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003251 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003252 chip->trkl_voltage = pdata->trkl_voltage;
3253 chip->weak_voltage = pdata->weak_voltage;
3254 chip->trkl_current = pdata->trkl_current;
3255 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003256 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003257 chip->thermal_mitigation = pdata->thermal_mitigation;
3258 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003260 chip->cold_thr = pdata->cold_thr;
3261 chip->hot_thr = pdata->hot_thr;
3262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263 rc = pm8921_chg_hw_init(chip);
3264 if (rc) {
3265 pr_err("couldn't init hardware rc=%d\n", rc);
3266 goto free_chip;
3267 }
3268
3269 chip->usb_psy.name = "usb",
3270 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3271 chip->usb_psy.supplied_to = pm_power_supplied_to,
3272 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3273 chip->usb_psy.properties = pm_power_props,
3274 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3275 chip->usb_psy.get_property = pm_power_get_property,
3276
David Keitel6ed71a52012-01-30 12:42:18 -08003277 chip->dc_psy.name = "pm8921-dc",
3278 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3279 chip->dc_psy.supplied_to = pm_power_supplied_to,
3280 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3281 chip->dc_psy.properties = pm_power_props,
3282 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
3283 chip->dc_psy.get_property = pm_power_get_property,
3284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285 chip->batt_psy.name = "battery",
3286 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3287 chip->batt_psy.properties = msm_batt_power_props,
3288 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3289 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003290 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291 rc = power_supply_register(chip->dev, &chip->usb_psy);
3292 if (rc < 0) {
3293 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003294 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003295 }
3296
David Keitel6ed71a52012-01-30 12:42:18 -08003297 rc = power_supply_register(chip->dev, &chip->dc_psy);
3298 if (rc < 0) {
3299 pr_err("power_supply_register usb failed rc = %d\n", rc);
3300 goto unregister_usb;
3301 }
3302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303 rc = power_supply_register(chip->dev, &chip->batt_psy);
3304 if (rc < 0) {
3305 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003306 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 }
3308
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003309 platform_set_drvdata(pdev, chip);
3310 the_chip = chip;
3311
3312 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003313 wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
3314 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003315 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003316 INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
3317 unplug_wrkarnd_restore_worker);
3318 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 rc = request_irqs(chip, pdev);
3321 if (rc) {
3322 pr_err("couldn't register interrupts rc=%d\n", rc);
3323 goto unregister_batt;
3324 }
3325
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003326 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3327 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3328 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003329 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3330 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003331 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003332 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003333 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003334 * care for jeita compliance
3335 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003336 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003337 rc = configure_btm(chip);
3338 if (rc) {
3339 pr_err("couldn't register with btm rc=%d\n", rc);
3340 goto free_irq;
3341 }
3342 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 create_debugfs_entries(chip);
3345
3346 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003347 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003348
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349 /* determine what state the charger is in */
3350 determine_initial_state(chip);
3351
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003352 if (chip->update_time) {
3353 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3354 update_heartbeat);
3355 schedule_delayed_work(&chip->update_heartbeat_work,
3356 round_jiffies_relative(msecs_to_jiffies
3357 (chip->update_time)));
3358 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 return 0;
3360
3361free_irq:
3362 free_irqs(chip);
3363unregister_batt:
3364 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003365unregister_dc:
3366 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003367unregister_usb:
3368 power_supply_unregister(&chip->usb_psy);
3369free_chip:
3370 kfree(chip);
3371 return rc;
3372}
3373
3374static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3375{
3376 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3377
3378 free_irqs(chip);
3379 platform_set_drvdata(pdev, NULL);
3380 the_chip = NULL;
3381 kfree(chip);
3382 return 0;
3383}
David Keitelf2226022011-12-13 15:55:50 -08003384static const struct dev_pm_ops pm8921_pm_ops = {
3385 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003386 .suspend_noirq = pm8921_charger_suspend_noirq,
3387 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003388 .resume = pm8921_charger_resume,
3389};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003390static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003391 .probe = pm8921_charger_probe,
3392 .remove = __devexit_p(pm8921_charger_remove),
3393 .driver = {
3394 .name = PM8921_CHARGER_DEV_NAME,
3395 .owner = THIS_MODULE,
3396 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 },
3398};
3399
3400static int __init pm8921_charger_init(void)
3401{
3402 return platform_driver_register(&pm8921_charger_driver);
3403}
3404
3405static void __exit pm8921_charger_exit(void)
3406{
3407 platform_driver_unregister(&pm8921_charger_driver);
3408}
3409
3410late_initcall(pm8921_charger_init);
3411module_exit(pm8921_charger_exit);
3412
3413MODULE_LICENSE("GPL v2");
3414MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3415MODULE_VERSION("1.0");
3416MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);