blob: aca724ae2b93c1151d5988e842bf387c289db5bd [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
418#define PM8921_CHG_V_MIN_MV 3240
419#define PM8921_CHG_V_STEP_MV 20
David Keitelcf867232012-01-27 18:40:12 -0800420#define PM8921_CHG_V_STEP_10_MV_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421#define PM8921_CHG_VDDMAX_MAX 4500
422#define PM8921_CHG_VDDMAX_MIN 3400
423#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800424static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425{
David Keitelcf867232012-01-27 18:40:12 -0800426 int remainder, voltage_20_step;
427 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428
David Keitelcf867232012-01-27 18:40:12 -0800429 voltage_20_step = voltage;
430 remainder = voltage % 20;
431 if (remainder >= 10) {
432 voltage_20_step += 10;
433 temp = PM8921_CHG_V_STEP_10_MV_BIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 }
David Keitelcf867232012-01-27 18:40:12 -0800435
436 temp |= (voltage_20_step - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800438 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439}
440
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700441static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
442{
443 u8 temp;
444 int rc;
445
446 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
447 if (rc) {
448 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700449 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700450 return rc;
451 }
452 temp &= PM8921_CHG_V_MASK;
453 *voltage = (int)temp * PM8921_CHG_V_STEP_MV + PM8921_CHG_V_MIN_MV;
David Keitelcf867232012-01-27 18:40:12 -0800454 if (temp & PM8921_CHG_V_STEP_10_MV_BIT)
455 *voltage = *voltage - 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700456 return 0;
457}
458
David Keitelcf867232012-01-27 18:40:12 -0800459static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
460{
461 int current_mv, ret, steps, i;
462 bool increase;
463
464 ret = 0;
465
466 if (voltage < PM8921_CHG_VDDMAX_MIN
467 || voltage > PM8921_CHG_VDDMAX_MAX) {
468 pr_err("bad mV=%d asked to set\n", voltage);
469 return -EINVAL;
470 }
471
472 ret = pm_chg_vddmax_get(chip, &current_mv);
473 if (ret) {
474 pr_err("Failed to read vddmax rc=%d\n", ret);
475 return -EINVAL;
476 }
477 if (current_mv == voltage)
478 return 0;
479
480 /* Only change in increments when USB is present */
481 if (is_usb_chg_plugged_in(chip)) {
482 if (current_mv < voltage) {
483 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
484 increase = true;
485 } else {
486 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
487 increase = false;
488 }
489 for (i = 0; i < steps; i++) {
490 if (increase)
491 current_mv += PM8921_CHG_V_STEP_MV;
492 else
493 current_mv -= PM8921_CHG_V_STEP_MV;
494 ret |= __pm_chg_vddmax_set(chip, current_mv);
495 }
496 }
497 ret |= __pm_chg_vddmax_set(chip, voltage);
498 return ret;
499}
500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501#define PM8921_CHG_VDDSAFE_MIN 3400
502#define PM8921_CHG_VDDSAFE_MAX 4500
503static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
504{
505 u8 temp;
506
507 if (voltage < PM8921_CHG_VDDSAFE_MIN
508 || voltage > PM8921_CHG_VDDSAFE_MAX) {
509 pr_err("bad mV=%d asked to set\n", voltage);
510 return -EINVAL;
511 }
512 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
513 pr_debug("voltage=%d setting %02x\n", voltage, temp);
514 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
515}
516
517#define PM8921_CHG_VBATDET_MIN 3240
518#define PM8921_CHG_VBATDET_MAX 5780
519static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
520{
521 u8 temp;
522
523 if (voltage < PM8921_CHG_VBATDET_MIN
524 || voltage > PM8921_CHG_VBATDET_MAX) {
525 pr_err("bad mV=%d asked to set\n", voltage);
526 return -EINVAL;
527 }
528 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
529 pr_debug("voltage=%d setting %02x\n", voltage, temp);
530 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
531}
532
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700533#define PM8921_CHG_VINMIN_MIN_MV 3800
534#define PM8921_CHG_VINMIN_STEP_MV 100
535#define PM8921_CHG_VINMIN_USABLE_MAX 6500
536#define PM8921_CHG_VINMIN_USABLE_MIN 4300
537#define PM8921_CHG_VINMIN_MASK 0x1F
538static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
539{
540 u8 temp;
541
542 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
543 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
544 pr_err("bad mV=%d asked to set\n", voltage);
545 return -EINVAL;
546 }
547 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
548 pr_debug("voltage=%d setting %02x\n", voltage, temp);
549 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
550 temp);
551}
552
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800553static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
554{
555 u8 temp;
556 int rc, voltage_mv;
557
558 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
559 temp &= PM8921_CHG_VINMIN_MASK;
560
561 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
562 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
563
564 return voltage_mv;
565}
566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567#define PM8921_CHG_IBATMAX_MIN 325
568#define PM8921_CHG_IBATMAX_MAX 2000
569#define PM8921_CHG_I_MIN_MA 225
570#define PM8921_CHG_I_STEP_MA 50
571#define PM8921_CHG_I_MASK 0x3F
572static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
573{
574 u8 temp;
575
576 if (chg_current < PM8921_CHG_IBATMAX_MIN
577 || chg_current > PM8921_CHG_IBATMAX_MAX) {
578 pr_err("bad mA=%d asked to set\n", chg_current);
579 return -EINVAL;
580 }
581 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
582 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
583}
584
585#define PM8921_CHG_IBATSAFE_MIN 225
586#define PM8921_CHG_IBATSAFE_MAX 3375
587static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
588{
589 u8 temp;
590
591 if (chg_current < PM8921_CHG_IBATSAFE_MIN
592 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
593 pr_err("bad mA=%d asked to set\n", chg_current);
594 return -EINVAL;
595 }
596 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
597 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
598 PM8921_CHG_I_MASK, temp);
599}
600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700602#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603#define PM8921_CHG_ITERM_STEP_MA 10
604#define PM8921_CHG_ITERM_MASK 0xF
605static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
606{
607 u8 temp;
608
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700609 if (chg_current < PM8921_CHG_ITERM_MIN_MA
610 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 pr_err("bad mA=%d asked to set\n", chg_current);
612 return -EINVAL;
613 }
614
615 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
616 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700617 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 temp);
619}
620
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700621static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
622{
623 u8 temp;
624 int rc;
625
626 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
627 if (rc) {
628 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700629 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700630 return rc;
631 }
632 temp &= PM8921_CHG_ITERM_MASK;
633 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
634 + PM8921_CHG_ITERM_MIN_MA;
635 return 0;
636}
637
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800638struct usb_ma_limit_entry {
639 int usb_ma;
640 u8 chg_iusb_value;
641};
642
643static struct usb_ma_limit_entry usb_ma_table[] = {
644 {100, 0},
645 {500, 1},
646 {700, 2},
647 {850, 3},
648 {900, 4},
649 {1100, 5},
650 {1300, 6},
651 {1500, 7},
652};
653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654#define PM8921_CHG_IUSB_MASK 0x1C
655#define PM8921_CHG_IUSB_MAX 7
656#define PM8921_CHG_IUSB_MIN 0
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700657static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int reg_val)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658{
659 u8 temp;
660
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700661 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
662 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 return -EINVAL;
664 }
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700665 temp = reg_val << 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 return pm_chg_masked_write(chip, PBL_ACCESS2, PM8921_CHG_IUSB_MASK,
667 temp);
668}
669
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800670static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
671{
672 u8 temp;
673 int i, rc;
674
675 *mA = 0;
676 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
677 if (rc) {
678 pr_err("err=%d reading PBL_ACCESS2\n", rc);
679 return rc;
680 }
681 temp &= PM8921_CHG_IUSB_MASK;
682 temp = temp >> 2;
683 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
684 if (usb_ma_table[i].chg_iusb_value == temp)
685 *mA = usb_ma_table[i].usb_ma;
686 }
687 return rc;
688}
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690#define PM8921_CHG_WD_MASK 0x1F
691static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
692{
693 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700694 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
695}
696
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700697#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700698#define PM8921_CHG_TCHG_MIN 4
699#define PM8921_CHG_TCHG_MAX 512
700#define PM8921_CHG_TCHG_STEP 4
701static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
702{
703 u8 temp;
704
705 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
706 pr_err("bad max minutes =%d asked to set\n", minutes);
707 return -EINVAL;
708 }
709
710 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
711 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
712 temp);
713}
714
715#define PM8921_CHG_TTRKL_MASK 0x1F
716#define PM8921_CHG_TTRKL_MIN 1
717#define PM8921_CHG_TTRKL_MAX 64
718static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
719{
720 u8 temp;
721
722 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
723 pr_err("bad max minutes =%d asked to set\n", minutes);
724 return -EINVAL;
725 }
726
727 temp = minutes - 1;
728 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
729 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730}
731
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700732#define PM8921_CHG_VTRKL_MIN_MV 2050
733#define PM8921_CHG_VTRKL_MAX_MV 2800
734#define PM8921_CHG_VTRKL_STEP_MV 50
735#define PM8921_CHG_VTRKL_SHIFT 4
736#define PM8921_CHG_VTRKL_MASK 0xF0
737static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
738{
739 u8 temp;
740
741 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
742 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
743 pr_err("bad voltage = %dmV asked to set\n", millivolts);
744 return -EINVAL;
745 }
746
747 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
748 temp = temp << PM8921_CHG_VTRKL_SHIFT;
749 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
750 temp);
751}
752
753#define PM8921_CHG_VWEAK_MIN_MV 2100
754#define PM8921_CHG_VWEAK_MAX_MV 3600
755#define PM8921_CHG_VWEAK_STEP_MV 100
756#define PM8921_CHG_VWEAK_MASK 0x0F
757static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
758{
759 u8 temp;
760
761 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
762 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
763 pr_err("bad voltage = %dmV asked to set\n", millivolts);
764 return -EINVAL;
765 }
766
767 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
768 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
769 temp);
770}
771
772#define PM8921_CHG_ITRKL_MIN_MA 50
773#define PM8921_CHG_ITRKL_MAX_MA 200
774#define PM8921_CHG_ITRKL_MASK 0x0F
775#define PM8921_CHG_ITRKL_STEP_MA 10
776static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
777{
778 u8 temp;
779
780 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
781 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
782 pr_err("bad current = %dmA asked to set\n", milliamps);
783 return -EINVAL;
784 }
785
786 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
787
788 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
789 temp);
790}
791
792#define PM8921_CHG_IWEAK_MIN_MA 325
793#define PM8921_CHG_IWEAK_MAX_MA 525
794#define PM8921_CHG_IWEAK_SHIFT 7
795#define PM8921_CHG_IWEAK_MASK 0x80
796static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
797{
798 u8 temp;
799
800 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
801 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
802 pr_err("bad current = %dmA asked to set\n", milliamps);
803 return -EINVAL;
804 }
805
806 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
807 temp = 0;
808 else
809 temp = 1;
810
811 temp = temp << PM8921_CHG_IWEAK_SHIFT;
812 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
813 temp);
814}
815
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700816#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
817#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
818static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
819 enum pm8921_chg_cold_thr cold_thr)
820{
821 u8 temp;
822
823 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
824 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
825 return pm_chg_masked_write(chip, CHG_CNTRL_2,
826 PM8921_CHG_BATT_TEMP_THR_COLD,
827 temp);
828}
829
830#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
831#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
832static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
833 enum pm8921_chg_hot_thr hot_thr)
834{
835 u8 temp;
836
837 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
838 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
839 return pm_chg_masked_write(chip, CHG_CNTRL_2,
840 PM8921_CHG_BATT_TEMP_THR_HOT,
841 temp);
842}
843
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700844static int64_t read_battery_id(struct pm8921_chg_chip *chip)
845{
846 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700847 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700848
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -0700849 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -0700850 if (rc) {
851 pr_err("error reading batt id channel = %d, rc = %d\n",
852 chip->vbat_channel, rc);
853 return rc;
854 }
855 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
856 result.measurement);
857 return result.physical;
858}
859
860static int is_battery_valid(struct pm8921_chg_chip *chip)
861{
862 int64_t rc;
863
864 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
865 return 1;
866
867 rc = read_battery_id(chip);
868 if (rc < 0) {
869 pr_err("error reading batt id channel = %d, rc = %lld\n",
870 chip->vbat_channel, rc);
871 /* assume battery id is valid when adc error happens */
872 return 1;
873 }
874
875 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
876 pr_err("batt_id phy =%lld is not valid\n", rc);
877 return 0;
878 }
879 return 1;
880}
881
882static void check_battery_valid(struct pm8921_chg_chip *chip)
883{
884 if (is_battery_valid(chip) == 0) {
885 pr_err("batt_id not valid, disbling charging\n");
886 pm_chg_auto_enable(chip, 0);
887 } else {
888 pm_chg_auto_enable(chip, !charging_disabled);
889 }
890}
891
892static void battery_id_valid(struct work_struct *work)
893{
894 struct pm8921_chg_chip *chip = container_of(work,
895 struct pm8921_chg_chip, battery_id_valid_work);
896
897 check_battery_valid(chip);
898}
899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
901{
902 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
903 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
904 enable_irq(chip->pmic_chg_irq[interrupt]);
905 }
906}
907
908static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
909{
910 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
911 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
912 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
913 }
914}
915
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800916static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
917{
918 return test_bit(interrupt, chip->enabled_irqs);
919}
920
Amir Samuelovd31ef502011-10-26 14:41:36 +0200921static bool is_ext_charging(struct pm8921_chg_chip *chip)
922{
David Keitel88e1b572012-01-11 11:57:14 -0800923 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200924
David Keitel88e1b572012-01-11 11:57:14 -0800925 if (!chip->ext_psy)
926 return false;
927 if (chip->ext_psy->get_property(chip->ext_psy,
928 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
929 return false;
930 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
931 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200932
933 return false;
934}
935
936static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
937{
David Keitel88e1b572012-01-11 11:57:14 -0800938 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +0200939
David Keitel88e1b572012-01-11 11:57:14 -0800940 if (!chip->ext_psy)
941 return false;
942 if (chip->ext_psy->get_property(chip->ext_psy,
943 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
944 return false;
945 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +0200946 return true;
947
948 return false;
949}
950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951static int is_battery_charging(int fsm_state)
952{
Amir Samuelovd31ef502011-10-26 14:41:36 +0200953 if (is_ext_charging(the_chip))
954 return 1;
955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956 switch (fsm_state) {
957 case FSM_STATE_ATC_2A:
958 case FSM_STATE_ATC_2B:
959 case FSM_STATE_ON_CHG_AND_BAT_6:
960 case FSM_STATE_FAST_CHG_7:
961 case FSM_STATE_TRKL_CHG_8:
962 return 1;
963 }
964 return 0;
965}
966
967static void bms_notify(struct work_struct *work)
968{
969 struct bms_notify *n = container_of(work, struct bms_notify, work);
970
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700971 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700973 } else {
974 pm8921_bms_charging_end(n->is_battery_full);
975 n->is_battery_full = 0;
976 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977}
978
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -0700979static void bms_notify_check(struct pm8921_chg_chip *chip)
980{
981 int fsm_state, new_is_charging;
982
983 fsm_state = pm_chg_get_fsm_state(chip);
984 new_is_charging = is_battery_charging(fsm_state);
985
986 if (chip->bms_notify.is_charging ^ new_is_charging) {
987 chip->bms_notify.is_charging = new_is_charging;
988 schedule_work(&(chip->bms_notify.work));
989 }
990}
991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992static enum power_supply_property pm_power_props[] = {
993 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -0700994 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995};
996
997static char *pm_power_supplied_to[] = {
998 "battery",
999};
1000
David Keitel6ed71a52012-01-30 12:42:18 -08001001#define USB_WALL_THRESHOLD_MA 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002static int pm_power_get_property(struct power_supply *psy,
1003 enum power_supply_property psp,
1004 union power_supply_propval *val)
1005{
David Keitel6ed71a52012-01-30 12:42:18 -08001006 int current_max;
1007
1008 /* Check if called before init */
1009 if (!the_chip)
1010 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011
1012 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001013 case POWER_SUPPLY_PROP_CURRENT_MAX:
1014 pm_chg_iusbmax_get(the_chip, &current_max);
1015 val->intval = current_max;
1016 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001018 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001019 val->intval = 0;
1020 if (charging_disabled)
1021 return 0;
1022
1023 /* USB charging */
1024 if (psy->type == POWER_SUPPLY_TYPE_USB ||
David Keitel6ed71a52012-01-30 12:42:18 -08001025 psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
1026 psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
1027 psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
David Keitel63f71662012-02-08 20:30:00 -08001028 val->intval = is_usb_chg_plugged_in(the_chip);
1029 return 0;
1030 }
1031
1032 /* DC charging */
1033 if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
1034 /* external charger is connected */
1035 if (the_chip->dc_present || is_ext_charging(the_chip)) {
1036 val->intval = 1;
1037 return 0;
1038 }
1039 /* USB with max current greater than 500 mA connected */
David Keitel6ed71a52012-01-30 12:42:18 -08001040 pm_chg_iusbmax_get(the_chip, &current_max);
1041 if (current_max > USB_WALL_THRESHOLD_MA)
David Keitel63f71662012-02-08 20:30:00 -08001042 val->intval = is_usb_chg_plugged_in(the_chip);
1043 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 }
David Keitel63f71662012-02-08 20:30:00 -08001045
1046 pr_err("Unkown POWER_SUPPLY_TYPE %d\n", psy->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 break;
1048 default:
1049 return -EINVAL;
1050 }
1051 return 0;
1052}
1053
1054static enum power_supply_property msm_batt_power_props[] = {
1055 POWER_SUPPLY_PROP_STATUS,
1056 POWER_SUPPLY_PROP_CHARGE_TYPE,
1057 POWER_SUPPLY_PROP_HEALTH,
1058 POWER_SUPPLY_PROP_PRESENT,
1059 POWER_SUPPLY_PROP_TECHNOLOGY,
1060 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1061 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1062 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1063 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001064 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001065 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001066 POWER_SUPPLY_PROP_ENERGY_FULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067};
1068
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001069static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070{
1071 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001072 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001074 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075 if (rc) {
1076 pr_err("error reading adc channel = %d, rc = %d\n",
1077 chip->vbat_channel, rc);
1078 return rc;
1079 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001080 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 result.measurement);
1082 return (int)result.physical;
1083}
1084
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001085static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1086{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001087 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1088 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1089 unsigned int low_voltage = chip->min_voltage_mv;
1090 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001091
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001092 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001093 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001094 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001095 return 100;
1096 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001097 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001098 / (high_voltage - low_voltage);
1099}
1100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1102{
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001103 int percent_soc = pm8921_bms_get_percent_charge();
1104
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001105 if (percent_soc == -ENXIO)
1106 percent_soc = voltage_based_capacity(chip);
1107
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001108 if (percent_soc <= 10)
1109 pr_warn("low battery charge = %d%%\n", percent_soc);
1110
1111 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112}
1113
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001114static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1115{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001116 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001117
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001118 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001119 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001120 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001121 }
1122
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001123 if (rc) {
1124 pr_err("unable to get batt current rc = %d\n", rc);
1125 return rc;
1126 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001127 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001128 }
1129}
1130
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001131static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1132{
1133 int rc;
1134
1135 rc = pm8921_bms_get_fcc();
1136 if (rc < 0)
1137 pr_err("unable to get batt fcc rc = %d\n", rc);
1138 return rc;
1139}
1140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1142{
1143 int temp;
1144
1145 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1146 if (temp)
1147 return POWER_SUPPLY_HEALTH_OVERHEAT;
1148
1149 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1150 if (temp)
1151 return POWER_SUPPLY_HEALTH_COLD;
1152
1153 return POWER_SUPPLY_HEALTH_GOOD;
1154}
1155
1156static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1157{
1158 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1159}
1160
1161static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1162{
1163 int temp;
1164
Amir Samuelovd31ef502011-10-26 14:41:36 +02001165 if (!get_prop_batt_present(chip))
1166 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1167
1168 if (is_ext_trickle_charging(chip))
1169 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1170
1171 if (is_ext_charging(chip))
1172 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1175 if (temp)
1176 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1177
1178 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1179 if (temp)
1180 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1181
1182 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1183}
1184
1185static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1186{
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001187 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1188 int fsm_state = pm_chg_get_fsm_state(chip);
1189 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190
David Keitel88e1b572012-01-11 11:57:14 -08001191 if (chip->ext_psy) {
David Keiteld4e59ef2011-11-09 17:38:31 -08001192 if (chip->ext_charge_done)
1193 return POWER_SUPPLY_STATUS_FULL;
1194 if (chip->ext_charging)
1195 return POWER_SUPPLY_STATUS_CHARGING;
1196 }
1197
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001198 for (i = 0; i < ARRAY_SIZE(map); i++)
1199 if (map[i].fsm_state == fsm_state)
1200 batt_state = map[i].batt_state;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001201
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001202 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1203 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1204 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001205 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1206 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
Amir Samuelovd31ef502011-10-26 14:41:36 +02001207
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001208 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001209 }
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -07001210 return batt_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211}
1212
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001213#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001214static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1215{
1216 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001217 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001218
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001219 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001220 if (rc) {
1221 pr_err("error reading adc channel = %d, rc = %d\n",
1222 chip->vbat_channel, rc);
1223 return rc;
1224 }
1225 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1226 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001227 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1228 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1229 (int) result.physical);
1230
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001231 return (int)result.physical;
1232}
1233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234static int pm_batt_power_get_property(struct power_supply *psy,
1235 enum power_supply_property psp,
1236 union power_supply_propval *val)
1237{
1238 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1239 batt_psy);
1240
1241 switch (psp) {
1242 case POWER_SUPPLY_PROP_STATUS:
1243 val->intval = get_prop_batt_status(chip);
1244 break;
1245 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1246 val->intval = get_prop_charge_type(chip);
1247 break;
1248 case POWER_SUPPLY_PROP_HEALTH:
1249 val->intval = get_prop_batt_health(chip);
1250 break;
1251 case POWER_SUPPLY_PROP_PRESENT:
1252 val->intval = get_prop_batt_present(chip);
1253 break;
1254 case POWER_SUPPLY_PROP_TECHNOLOGY:
1255 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1256 break;
1257 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001258 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 break;
1260 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001261 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 break;
1263 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001264 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 break;
1266 case POWER_SUPPLY_PROP_CAPACITY:
1267 val->intval = get_prop_batt_capacity(chip);
1268 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001269 case POWER_SUPPLY_PROP_CURRENT_NOW:
1270 val->intval = get_prop_batt_current(chip);
1271 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001272 case POWER_SUPPLY_PROP_TEMP:
1273 val->intval = get_prop_batt_temp(chip);
1274 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001275 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001276 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001277 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 default:
1279 return -EINVAL;
1280 }
1281
1282 return 0;
1283}
1284
1285static void (*notify_vbus_state_func_ptr)(int);
1286static int usb_chg_current;
1287static DEFINE_SPINLOCK(vbus_lock);
1288
1289int pm8921_charger_register_vbus_sn(void (*callback)(int))
1290{
1291 pr_debug("%p\n", callback);
1292 notify_vbus_state_func_ptr = callback;
1293 return 0;
1294}
1295EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1296
1297/* this is passed to the hsusb via platform_data msm_otg_pdata */
1298void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1299{
1300 pr_debug("%p\n", callback);
1301 notify_vbus_state_func_ptr = NULL;
1302}
1303EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1304
1305static void notify_usb_of_the_plugin_event(int plugin)
1306{
1307 plugin = !!plugin;
1308 if (notify_vbus_state_func_ptr) {
1309 pr_debug("notifying plugin\n");
1310 (*notify_vbus_state_func_ptr) (plugin);
1311 } else {
1312 pr_debug("unable to notify plugin\n");
1313 }
1314}
1315
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316/* assumes vbus_lock is held */
1317static void __pm8921_charger_vbus_draw(unsigned int mA)
1318{
1319 int i, rc;
1320
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001321 if (usb_max_current && mA > usb_max_current) {
1322 pr_warn("restricting usb current to %d instead of %d\n",
1323 usb_max_current, mA);
1324 mA = usb_max_current;
1325 }
1326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 if (mA > 0 && mA <= 2) {
1328 usb_chg_current = 0;
1329 rc = pm_chg_iusbmax_set(the_chip,
1330 usb_ma_table[0].chg_iusb_value);
1331 if (rc) {
1332 pr_err("unable to set iusb to %d rc = %d\n",
1333 usb_ma_table[0].chg_iusb_value, rc);
1334 }
1335 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1336 if (rc)
1337 pr_err("fail to set suspend bit rc=%d\n", rc);
1338 } else {
1339 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1340 if (rc)
1341 pr_err("fail to reset suspend bit rc=%d\n", rc);
1342 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1343 if (usb_ma_table[i].usb_ma <= mA)
1344 break;
1345 }
1346 if (i < 0)
1347 i = 0;
1348 rc = pm_chg_iusbmax_set(the_chip,
1349 usb_ma_table[i].chg_iusb_value);
1350 if (rc) {
1351 pr_err("unable to set iusb to %d rc = %d\n",
1352 usb_ma_table[i].chg_iusb_value, rc);
1353 }
1354 }
1355}
1356
1357/* USB calls these to tell us how much max usb current the system can draw */
1358void pm8921_charger_vbus_draw(unsigned int mA)
1359{
1360 unsigned long flags;
1361
1362 pr_debug("Enter charge=%d\n", mA);
1363 spin_lock_irqsave(&vbus_lock, flags);
1364 if (the_chip) {
1365 __pm8921_charger_vbus_draw(mA);
1366 } else {
1367 /*
1368 * called before pmic initialized,
1369 * save this value and use it at probe
1370 */
1371 usb_chg_current = mA;
1372 }
1373 spin_unlock_irqrestore(&vbus_lock, flags);
1374}
1375EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1376
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07001377int pm8921_charger_enable(bool enable)
1378{
1379 int rc;
1380
1381 if (!the_chip) {
1382 pr_err("called before init\n");
1383 return -EINVAL;
1384 }
1385 enable = !!enable;
1386 rc = pm_chg_auto_enable(the_chip, enable);
1387 if (rc)
1388 pr_err("Failed rc=%d\n", rc);
1389 return rc;
1390}
1391EXPORT_SYMBOL(pm8921_charger_enable);
1392
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001393int pm8921_is_usb_chg_plugged_in(void)
1394{
1395 if (!the_chip) {
1396 pr_err("called before init\n");
1397 return -EINVAL;
1398 }
1399 return is_usb_chg_plugged_in(the_chip);
1400}
1401EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1402
1403int pm8921_is_dc_chg_plugged_in(void)
1404{
1405 if (!the_chip) {
1406 pr_err("called before init\n");
1407 return -EINVAL;
1408 }
1409 return is_dc_chg_plugged_in(the_chip);
1410}
1411EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1412
1413int pm8921_is_battery_present(void)
1414{
1415 if (!the_chip) {
1416 pr_err("called before init\n");
1417 return -EINVAL;
1418 }
1419 return get_prop_batt_present(the_chip);
1420}
1421EXPORT_SYMBOL(pm8921_is_battery_present);
1422
David Keitel012deef2011-12-02 11:49:33 -08001423/*
1424 * Disabling the charge current limit causes current
1425 * current limits to have no monitoring. An adequate charger
1426 * capable of supplying high current while sustaining VIN_MIN
1427 * is required if the limiting is disabled.
1428 */
1429int pm8921_disable_input_current_limit(bool disable)
1430{
1431 if (!the_chip) {
1432 pr_err("called before init\n");
1433 return -EINVAL;
1434 }
1435 if (disable) {
1436 pr_warn("Disabling input current limit!\n");
1437
1438 return pm8xxx_writeb(the_chip->dev->parent,
1439 CHG_BUCK_CTRL_TEST3, 0xF2);
1440 }
1441 return 0;
1442}
1443EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1444
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001445int pm8921_set_max_battery_charge_current(int ma)
1446{
1447 if (!the_chip) {
1448 pr_err("called before init\n");
1449 return -EINVAL;
1450 }
1451 return pm_chg_ibatmax_set(the_chip, ma);
1452}
1453EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1454
1455int pm8921_disable_source_current(bool disable)
1456{
1457 if (!the_chip) {
1458 pr_err("called before init\n");
1459 return -EINVAL;
1460 }
1461 if (disable)
1462 pr_warn("current drawn from chg=0, battery provides current\n");
1463 return pm_chg_charge_dis(the_chip, disable);
1464}
1465EXPORT_SYMBOL(pm8921_disable_source_current);
1466
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001467int pm8921_regulate_input_voltage(int voltage)
1468{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001469 int rc;
1470
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001471 if (!the_chip) {
1472 pr_err("called before init\n");
1473 return -EINVAL;
1474 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001475 rc = pm_chg_vinmin_set(the_chip, voltage);
1476
1477 if (rc == 0)
1478 the_chip->vin_min = voltage;
1479
1480 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001481}
1482
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08001483#define USB_OV_THRESHOLD_MASK 0x60
1484#define USB_OV_THRESHOLD_SHIFT 5
1485int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
1486{
1487 u8 temp;
1488
1489 if (!the_chip) {
1490 pr_err("called before init\n");
1491 return -EINVAL;
1492 }
1493
1494 if (ov > PM_USB_OV_7V) {
1495 pr_err("limiting to over voltage threshold to 7volts\n");
1496 ov = PM_USB_OV_7V;
1497 }
1498
1499 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
1500
1501 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1502 USB_OV_THRESHOLD_MASK, temp);
1503}
1504EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
1505
1506#define USB_DEBOUNCE_TIME_MASK 0x06
1507#define USB_DEBOUNCE_TIME_SHIFT 1
1508int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
1509{
1510 u8 temp;
1511
1512 if (!the_chip) {
1513 pr_err("called before init\n");
1514 return -EINVAL;
1515 }
1516
1517 if (ms > PM_USB_DEBOUNCE_80P5MS) {
1518 pr_err("limiting debounce to 80.5ms\n");
1519 ms = PM_USB_DEBOUNCE_80P5MS;
1520 }
1521
1522 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
1523
1524 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1525 USB_DEBOUNCE_TIME_MASK, temp);
1526}
1527EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
1528
1529#define USB_OVP_DISABLE_MASK 0x80
1530int pm8921_usb_ovp_disable(int disable)
1531{
1532 u8 temp = 0;
1533
1534 if (!the_chip) {
1535 pr_err("called before init\n");
1536 return -EINVAL;
1537 }
1538
1539 if (disable)
1540 temp = USB_OVP_DISABLE_MASK;
1541
1542 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
1543 USB_OVP_DISABLE_MASK, temp);
1544}
1545
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001546bool pm8921_is_battery_charging(int *source)
1547{
1548 int fsm_state, is_charging, dc_present, usb_present;
1549
1550 if (!the_chip) {
1551 pr_err("called before init\n");
1552 return -EINVAL;
1553 }
1554 fsm_state = pm_chg_get_fsm_state(the_chip);
1555 is_charging = is_battery_charging(fsm_state);
1556 if (is_charging == 0) {
1557 *source = PM8921_CHG_SRC_NONE;
1558 return is_charging;
1559 }
1560
1561 if (source == NULL)
1562 return is_charging;
1563
1564 /* the battery is charging, the source is requested, find it */
1565 dc_present = is_dc_chg_plugged_in(the_chip);
1566 usb_present = is_usb_chg_plugged_in(the_chip);
1567
1568 if (dc_present && !usb_present)
1569 *source = PM8921_CHG_SRC_DC;
1570
1571 if (usb_present && !dc_present)
1572 *source = PM8921_CHG_SRC_USB;
1573
1574 if (usb_present && dc_present)
1575 /*
1576 * The system always chooses dc for charging since it has
1577 * higher priority.
1578 */
1579 *source = PM8921_CHG_SRC_DC;
1580
1581 return is_charging;
1582}
1583EXPORT_SYMBOL(pm8921_is_battery_charging);
1584
David Keitel6df9cea2011-12-21 12:36:45 -08001585int pm8921_set_usb_power_supply_type(enum power_supply_type type)
1586{
1587 if (!the_chip) {
1588 pr_err("called before init\n");
1589 return -EINVAL;
1590 }
1591
1592 if (type < POWER_SUPPLY_TYPE_USB)
1593 return -EINVAL;
1594
1595 the_chip->usb_psy.type = type;
1596 power_supply_changed(&the_chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001597 power_supply_changed(&the_chip->dc_psy);
David Keitel6df9cea2011-12-21 12:36:45 -08001598 return 0;
1599}
1600EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
1601
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001602int pm8921_batt_temperature(void)
1603{
1604 if (!the_chip) {
1605 pr_err("called before init\n");
1606 return -EINVAL;
1607 }
1608 return get_prop_batt_temp(the_chip);
1609}
1610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
1612{
1613 int usb_present;
1614
1615 usb_present = is_usb_chg_plugged_in(chip);
1616 if (chip->usb_present ^ usb_present) {
1617 notify_usb_of_the_plugin_event(usb_present);
1618 chip->usb_present = usb_present;
1619 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07001620 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001622 if (usb_present) {
1623 schedule_delayed_work(&chip->unplug_check_work,
1624 round_jiffies_relative(msecs_to_jiffies
1625 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1626 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001627 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628}
1629
Amir Samuelovd31ef502011-10-26 14:41:36 +02001630static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
1631{
David Keitel88e1b572012-01-11 11:57:14 -08001632 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001633 pr_debug("external charger not registered.\n");
1634 return;
1635 }
1636
1637 if (!chip->ext_charging) {
1638 pr_debug("already not charging.\n");
1639 return;
1640 }
1641
David Keitel88e1b572012-01-11 11:57:14 -08001642 power_supply_set_charge_type(chip->ext_psy,
1643 POWER_SUPPLY_CHARGE_TYPE_NONE);
1644 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08001645 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001646 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08001647 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001648 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001649}
1650
1651static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
1652{
1653 int dc_present;
1654 int batt_present;
1655 int batt_temp_ok;
1656 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001657 unsigned long delay =
1658 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
1659
David Keitel88e1b572012-01-11 11:57:14 -08001660 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02001661 pr_debug("external charger not registered.\n");
1662 return;
1663 }
1664
1665 if (chip->ext_charging) {
1666 pr_debug("already charging.\n");
1667 return;
1668 }
1669
David Keitel88e1b572012-01-11 11:57:14 -08001670 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001671 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1672 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001673
1674 if (!dc_present) {
1675 pr_warn("%s. dc not present.\n", __func__);
1676 return;
1677 }
1678 if (!batt_present) {
1679 pr_warn("%s. battery not present.\n", __func__);
1680 return;
1681 }
1682 if (!batt_temp_ok) {
1683 pr_warn("%s. battery temperature not ok.\n", __func__);
1684 return;
1685 }
David Keitel88e1b572012-01-11 11:57:14 -08001686 pm8921_disable_source_current(true); /* Force BATFET=ON */
1687 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001688 if (vbat_ov) {
1689 pr_warn("%s. battery over voltage.\n", __func__);
1690 return;
1691 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02001692
David Keitel63f71662012-02-08 20:30:00 -08001693 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08001694 power_supply_set_charge_type(chip->ext_psy,
1695 POWER_SUPPLY_CHARGE_TYPE_FAST);
David Keitel63f71662012-02-08 20:30:00 -08001696 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001697 chip->ext_charging = true;
1698 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08001699 bms_notify_check(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001700 /* Start BMS */
1701 schedule_delayed_work(&chip->eoc_work, delay);
1702 wake_lock(&chip->eoc_wake_lock);
1703}
1704
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001705#define WRITE_BANK_4 0xC0
1706static void unplug_wrkarnd_restore_worker(struct work_struct *work)
1707{
1708 u8 temp;
1709 int rc;
1710 struct delayed_work *dwork = to_delayed_work(work);
1711 struct pm8921_chg_chip *chip = container_of(dwork,
1712 struct pm8921_chg_chip,
1713 unplug_wrkarnd_restore_work);
1714
1715 pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
1716 rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
1717
1718 temp = WRITE_BANK_4 | 0xA;
1719 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
1720 if (rc) {
1721 pr_err("Error %d writing %d to addr %d\n", rc,
1722 temp, CHG_BUCK_CTRL_TEST3);
1723 }
1724 wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
1725}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
1727{
1728 handle_usb_insertion_removal(data);
1729 return IRQ_HANDLED;
1730}
1731
1732static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
1733{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001734 pr_err("USB OverVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735 return IRQ_HANDLED;
1736}
1737
1738static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
1739{
1740 struct pm8921_chg_chip *chip = data;
1741 int status;
1742
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001743 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1744 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02001745 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 pr_debug("battery present=%d", status);
1747 power_supply_changed(&chip->batt_psy);
1748 return IRQ_HANDLED;
1749}
Amir Samuelovd31ef502011-10-26 14:41:36 +02001750
1751/*
1752 * this interrupt used to restart charging a battery.
1753 *
1754 * Note: When DC-inserted the VBAT can't go low.
1755 * VPH_PWR is provided by the ext-charger.
1756 * After End-Of-Charging from DC, charging can be resumed only
1757 * if DC is removed and then inserted after the battery was in use.
1758 * Therefore the handle_start_ext_chg() is not called.
1759 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001760static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
1761{
1762 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001763 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001765 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07001766
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001767 if (high_transition) {
1768 /* enable auto charging */
1769 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08001770 pr_info("batt fell below resume voltage %s\n",
1771 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001772 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001775 power_supply_changed(&chip->batt_psy);
1776 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001777 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 return IRQ_HANDLED;
1780}
1781
1782static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
1783{
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001784 pr_err("USB UnderVoltage\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 return IRQ_HANDLED;
1786}
1787
1788static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
1789{
1790 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1791 return IRQ_HANDLED;
1792}
1793
1794static irqreturn_t chgwdog_irq_handler(int irq, void *data)
1795{
1796 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1797 return IRQ_HANDLED;
1798}
1799
1800static irqreturn_t vcp_irq_handler(int irq, void *data)
1801{
1802 pr_warning("VCP triggered BATDET forced on\n");
1803 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1804 return IRQ_HANDLED;
1805}
1806
1807static irqreturn_t atcdone_irq_handler(int irq, void *data)
1808{
1809 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1810 return IRQ_HANDLED;
1811}
1812
1813static irqreturn_t atcfail_irq_handler(int irq, void *data)
1814{
1815 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
1816 return IRQ_HANDLED;
1817}
1818
1819static irqreturn_t chgdone_irq_handler(int irq, void *data)
1820{
1821 struct pm8921_chg_chip *chip = data;
1822
1823 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001824
1825 handle_stop_ext_chg(chip);
1826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 power_supply_changed(&chip->batt_psy);
1828 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001829 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001830
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001831 bms_notify_check(chip);
1832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833 return IRQ_HANDLED;
1834}
1835
1836static irqreturn_t chgfail_irq_handler(int irq, void *data)
1837{
1838 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07001839 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840
David Keitel753ec8d2011-11-02 10:56:37 -07001841 ret = pm_chg_failed_clear(chip, 1);
1842 if (ret)
1843 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
1844
1845 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
1846 get_prop_batt_present(chip),
1847 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
1848 pm_chg_get_fsm_state(data));
1849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 power_supply_changed(&chip->batt_psy);
1851 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001852 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001853 return IRQ_HANDLED;
1854}
1855
1856static irqreturn_t chgstate_irq_handler(int irq, void *data)
1857{
1858 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859
1860 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
1861 power_supply_changed(&chip->batt_psy);
1862 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08001863 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001865 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 return IRQ_HANDLED;
1868}
1869
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001870#define VIN_ACTIVE_BIT BIT(0)
1871#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
1872#define VIN_MIN_INCREASE_MV 100
1873static void unplug_check_worker(struct work_struct *work)
1874{
1875 struct delayed_work *dwork = to_delayed_work(work);
1876 struct pm8921_chg_chip *chip = container_of(dwork,
1877 struct pm8921_chg_chip, unplug_check_work);
1878 u8 reg_loop;
1879 int ibat, usb_chg_plugged_in;
1880
1881 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
1882 if (!usb_chg_plugged_in) {
1883 pr_debug("Stopping Unplug Check Worker since USB is removed"
1884 "reg_loop = %d, fsm = %d ibat = %d\n",
1885 pm_chg_get_regulation_loop(chip),
1886 pm_chg_get_fsm_state(chip),
1887 get_prop_batt_current(chip)
1888 );
1889 return;
1890 }
1891 reg_loop = pm_chg_get_regulation_loop(chip);
1892 pr_debug("reg_loop=0x%x\n", reg_loop);
1893
1894 if (reg_loop & VIN_ACTIVE_BIT) {
1895 ibat = get_prop_batt_current(chip);
1896
1897 pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
1898 ibat, pm_chg_get_fsm_state(chip), reg_loop);
1899 if (ibat > 0) {
1900 int err;
1901 u8 temp;
1902
1903 temp = WRITE_BANK_4 | 0xE;
1904 err = pm8xxx_writeb(chip->dev->parent,
1905 CHG_BUCK_CTRL_TEST3, temp);
1906 if (err) {
1907 pr_err("Error %d writing %d to addr %d\n", err,
1908 temp, CHG_BUCK_CTRL_TEST3);
1909 }
1910
1911 pm_chg_vinmin_set(chip,
1912 chip->vin_min + VIN_MIN_INCREASE_MV);
1913
1914 wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
1915 schedule_delayed_work(
1916 &chip->unplug_wrkarnd_restore_work,
1917 round_jiffies_relative(usecs_to_jiffies
1918 (UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
1919 }
1920 }
1921
1922 schedule_delayed_work(&chip->unplug_check_work,
1923 round_jiffies_relative(msecs_to_jiffies
1924 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
1925}
1926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927static irqreturn_t loop_change_irq_handler(int irq, void *data)
1928{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001929 struct pm8921_chg_chip *chip = data;
1930
1931 pr_debug("fsm_state=%d reg_loop=0x%x\n",
1932 pm_chg_get_fsm_state(data),
1933 pm_chg_get_regulation_loop(data));
1934 unplug_check_worker(&(chip->unplug_check_work.work));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 return IRQ_HANDLED;
1936}
1937
1938static irqreturn_t fastchg_irq_handler(int irq, void *data)
1939{
1940 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001941 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001943 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1944 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
1945 wake_lock(&chip->eoc_wake_lock);
1946 schedule_delayed_work(&chip->eoc_work,
1947 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07001948 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07001949 }
1950 power_supply_changed(&chip->batt_psy);
1951 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 return IRQ_HANDLED;
1953}
1954
1955static irqreturn_t trklchg_irq_handler(int irq, void *data)
1956{
1957 struct pm8921_chg_chip *chip = data;
1958
1959 power_supply_changed(&chip->batt_psy);
1960 return IRQ_HANDLED;
1961}
1962
1963static irqreturn_t batt_removed_irq_handler(int irq, void *data)
1964{
1965 struct pm8921_chg_chip *chip = data;
1966 int status;
1967
1968 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
1969 pr_debug("battery present=%d state=%d", !status,
1970 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02001971 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 power_supply_changed(&chip->batt_psy);
1973 return IRQ_HANDLED;
1974}
1975
1976static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
1977{
1978 struct pm8921_chg_chip *chip = data;
1979
Amir Samuelovd31ef502011-10-26 14:41:36 +02001980 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 power_supply_changed(&chip->batt_psy);
1982 return IRQ_HANDLED;
1983}
1984
1985static irqreturn_t chghot_irq_handler(int irq, void *data)
1986{
1987 struct pm8921_chg_chip *chip = data;
1988
1989 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
1990 power_supply_changed(&chip->batt_psy);
1991 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08001992 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001993 return IRQ_HANDLED;
1994}
1995
1996static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
1997{
1998 struct pm8921_chg_chip *chip = data;
1999
2000 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002001 handle_stop_ext_chg(chip);
2002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 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}
2007
2008static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2009{
2010 struct pm8921_chg_chip *chip = data;
2011
2012 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2013 power_supply_changed(&chip->batt_psy);
2014 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015 return IRQ_HANDLED;
2016}
David Keitel52fda532011-11-10 10:43:44 -08002017/*
2018 *
2019 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2020 * fire for two cases:
2021 *
2022 * If the interrupt line switches to high temperature is okay
2023 * and thus charging begins.
2024 * If bat_temp_ok is low this means the temperature is now
2025 * too hot or cold, so charging is stopped.
2026 *
2027 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2029{
David Keitel52fda532011-11-10 10:43:44 -08002030 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 struct pm8921_chg_chip *chip = data;
2032
David Keitel52fda532011-11-10 10:43:44 -08002033 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2034
2035 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2036 bat_temp_ok, pm_chg_get_fsm_state(data));
2037
2038 if (bat_temp_ok)
2039 handle_start_ext_chg(chip);
2040 else
2041 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043 power_supply_changed(&chip->batt_psy);
2044 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002045 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 return IRQ_HANDLED;
2047}
2048
2049static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2050{
2051 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2052 return IRQ_HANDLED;
2053}
2054
2055static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
2056{
2057 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2058 return IRQ_HANDLED;
2059}
2060
2061static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
2062{
2063 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2064 return IRQ_HANDLED;
2065}
2066
2067static irqreturn_t vbatdet_irq_handler(int irq, void *data)
2068{
2069 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2070 return IRQ_HANDLED;
2071}
2072
2073static irqreturn_t batfet_irq_handler(int irq, void *data)
2074{
2075 struct pm8921_chg_chip *chip = data;
2076
2077 pr_debug("vreg ov\n");
2078 power_supply_changed(&chip->batt_psy);
2079 return IRQ_HANDLED;
2080}
2081
2082static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
2083{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002084 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08002085 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002086
David Keitel88e1b572012-01-11 11:57:14 -08002087 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2088 if (chip->ext_psy)
2089 power_supply_set_online(chip->ext_psy, dc_present);
2090 chip->dc_present = dc_present;
2091 if (dc_present)
2092 handle_start_ext_chg(chip);
2093 else
2094 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095 return IRQ_HANDLED;
2096}
2097
2098static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
2099{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002100 struct pm8921_chg_chip *chip = data;
2101
Amir Samuelovd31ef502011-10-26 14:41:36 +02002102 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 return IRQ_HANDLED;
2104}
2105
2106static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
2107{
Amir Samuelovd31ef502011-10-26 14:41:36 +02002108 struct pm8921_chg_chip *chip = data;
2109
Amir Samuelovd31ef502011-10-26 14:41:36 +02002110 handle_stop_ext_chg(chip);
2111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112 return IRQ_HANDLED;
2113}
2114
David Keitel88e1b572012-01-11 11:57:14 -08002115static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
2116{
2117 struct power_supply *psy = &the_chip->batt_psy;
2118 struct power_supply *epsy = dev_get_drvdata(dev);
2119 int i, dcin_irq;
2120
2121 /* Only search for external supply if none is registered */
2122 if (!the_chip->ext_psy) {
2123 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
2124 for (i = 0; i < epsy->num_supplicants; i++) {
2125 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
2126 if (!strncmp(epsy->name, "dc", 2)) {
2127 the_chip->ext_psy = epsy;
2128 dcin_valid_irq_handler(dcin_irq,
2129 the_chip);
2130 }
2131 }
2132 }
2133 }
2134 return 0;
2135}
2136
2137static void pm_batt_external_power_changed(struct power_supply *psy)
2138{
2139 /* Only look for an external supply if it hasn't been registered */
2140 if (!the_chip->ext_psy)
2141 class_for_each_device(power_supply_class, NULL, psy,
2142 __pm_batt_external_power_changed_work);
2143}
2144
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07002145/**
2146 * update_heartbeat - internal function to update userspace
2147 * per update_time minutes
2148 *
2149 */
2150static void update_heartbeat(struct work_struct *work)
2151{
2152 struct delayed_work *dwork = to_delayed_work(work);
2153 struct pm8921_chg_chip *chip = container_of(dwork,
2154 struct pm8921_chg_chip, update_heartbeat_work);
2155
2156 power_supply_changed(&chip->batt_psy);
2157 schedule_delayed_work(&chip->update_heartbeat_work,
2158 round_jiffies_relative(msecs_to_jiffies
2159 (chip->update_time)));
2160}
2161
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002162enum {
2163 CHG_IN_PROGRESS,
2164 CHG_NOT_IN_PROGRESS,
2165 CHG_FINISHED,
2166};
2167
2168#define VBAT_TOLERANCE_MV 70
2169#define CHG_DISABLE_MSLEEP 100
2170static int is_charging_finished(struct pm8921_chg_chip *chip)
2171{
2172 int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
2173 int ichg_meas_ma, iterm_programmed;
2174 int regulation_loop, fast_chg, vcp;
2175 int rc;
2176 static int last_vbat_programmed = -EINVAL;
2177
2178 if (!is_ext_charging(chip)) {
2179 /* return if the battery is not being fastcharged */
2180 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2181 pr_debug("fast_chg = %d\n", fast_chg);
2182 if (fast_chg == 0)
2183 return CHG_NOT_IN_PROGRESS;
2184
2185 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
2186 pr_debug("vcp = %d\n", vcp);
2187 if (vcp == 1)
2188 return CHG_IN_PROGRESS;
2189
2190 vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
2191 pr_debug("vbatdet_low = %d\n", vbatdet_low);
2192 if (vbatdet_low == 1)
2193 return CHG_IN_PROGRESS;
2194
2195 /* reset count if battery is hot/cold */
2196 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2197 pr_debug("batt_temp_ok = %d\n", rc);
2198 if (rc == 0)
2199 return CHG_IN_PROGRESS;
2200
2201 /* reset count if battery voltage is less than vddmax */
2202 vbat_meas_uv = get_prop_battery_uvolts(chip);
2203 if (vbat_meas_uv < 0)
2204 return CHG_IN_PROGRESS;
2205 vbat_meas_mv = vbat_meas_uv / 1000;
2206
2207 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
2208 if (rc) {
2209 pr_err("couldnt read vddmax rc = %d\n", rc);
2210 return CHG_IN_PROGRESS;
2211 }
2212 pr_debug("vddmax = %d vbat_meas_mv=%d\n",
2213 vbat_programmed, vbat_meas_mv);
2214 if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
2215 return CHG_IN_PROGRESS;
2216
2217 if (last_vbat_programmed == -EINVAL)
2218 last_vbat_programmed = vbat_programmed;
2219 if (last_vbat_programmed != vbat_programmed) {
2220 /* vddmax changed, reset and check again */
2221 pr_debug("vddmax = %d last_vdd_max=%d\n",
2222 vbat_programmed, last_vbat_programmed);
2223 last_vbat_programmed = vbat_programmed;
2224 return CHG_IN_PROGRESS;
2225 }
2226
2227 /*
2228 * TODO if charging from an external charger
2229 * check SOC instead of regulation loop
2230 */
2231 regulation_loop = pm_chg_get_regulation_loop(chip);
2232 if (regulation_loop < 0) {
2233 pr_err("couldnt read the regulation loop err=%d\n",
2234 regulation_loop);
2235 return CHG_IN_PROGRESS;
2236 }
2237 pr_debug("regulation_loop=%d\n", regulation_loop);
2238
2239 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
2240 return CHG_IN_PROGRESS;
2241 } /* !is_ext_charging */
2242
2243 /* reset count if battery chg current is more than iterm */
2244 rc = pm_chg_iterm_get(chip, &iterm_programmed);
2245 if (rc) {
2246 pr_err("couldnt read iterm rc = %d\n", rc);
2247 return CHG_IN_PROGRESS;
2248 }
2249
2250 ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
2251 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
2252 iterm_programmed, ichg_meas_ma);
2253 /*
2254 * ichg_meas_ma < 0 means battery is drawing current
2255 * ichg_meas_ma > 0 means battery is providing current
2256 */
2257 if (ichg_meas_ma > 0)
2258 return CHG_IN_PROGRESS;
2259
2260 if (ichg_meas_ma * -1 > iterm_programmed)
2261 return CHG_IN_PROGRESS;
2262
2263 return CHG_FINISHED;
2264}
2265
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002266/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02002267 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002268 * has happened
2269 *
2270 * If all conditions favouring, if the charge current is
2271 * less than the term current for three consecutive times
2272 * an EOC has happened.
2273 * The wakelock is released if there is no need to reshedule
2274 * - this happens when the battery is removed or EOC has
2275 * happened
2276 */
2277#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02002278static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002279{
2280 struct delayed_work *dwork = to_delayed_work(work);
2281 struct pm8921_chg_chip *chip = container_of(dwork,
2282 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002283 static int count;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002284 int end = is_charging_finished(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002285
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002286 if (end == CHG_NOT_IN_PROGRESS) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002287 /* enable fastchg irq */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002288 count = 0;
2289 wake_unlock(&chip->eoc_wake_lock);
2290 return;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002291 }
2292
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002293 if (end == CHG_FINISHED) {
2294 count++;
2295 } else {
2296 count = 0;
2297 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002298
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002299 if (count == CONSECUTIVE_COUNT) {
2300 count = 0;
2301 pr_info("End of Charging\n");
2302
2303 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002304
Amir Samuelovd31ef502011-10-26 14:41:36 +02002305 if (is_ext_charging(chip))
2306 chip->ext_charge_done = true;
2307
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08002308 if (chip->is_bat_warm || chip->is_bat_cool)
2309 chip->bms_notify.is_battery_full = 0;
2310 else
2311 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002312 /* declare end of charging by invoking chgdone interrupt */
2313 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
2314 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002315 } else {
2316 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002317 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002318 round_jiffies_relative(msecs_to_jiffies
2319 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002320 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002321}
2322
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002323static void btm_configure_work(struct work_struct *work)
2324{
2325 int rc;
2326
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002327 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002328 if (rc)
2329 pr_err("failed to configure btm rc=%d", rc);
2330}
2331
2332DECLARE_WORK(btm_config_work, btm_configure_work);
2333
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002334static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
2335{
2336 unsigned int chg_current = chip->max_bat_chg_current;
2337
2338 if (chip->is_bat_cool)
2339 chg_current = min(chg_current, chip->cool_bat_chg_current);
2340
2341 if (chip->is_bat_warm)
2342 chg_current = min(chg_current, chip->warm_bat_chg_current);
2343
David Keitelfdef3a42011-12-14 19:02:54 -08002344 if (thermal_mitigation != 0 && chip->thermal_mitigation)
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002345 chg_current = min(chg_current,
2346 chip->thermal_mitigation[thermal_mitigation]);
2347
2348 pm_chg_ibatmax_set(the_chip, chg_current);
2349}
2350
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002351#define TEMP_HYSTERISIS_DEGC 2
2352static void battery_cool(bool enter)
2353{
2354 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002355 if (enter == the_chip->is_bat_cool)
2356 return;
2357 the_chip->is_bat_cool = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002358 if (enter) {
2359 btm_config.low_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002360 the_chip->cool_temp_dc + TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002361 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002362 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002363 pm_chg_vbatdet_set(the_chip,
2364 the_chip->cool_bat_voltage
2365 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002366 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002367 btm_config.low_thr_temp = the_chip->cool_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002368 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002369 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002370 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002371 the_chip->max_voltage_mv
2372 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002373 }
2374 schedule_work(&btm_config_work);
2375}
2376
2377static void battery_warm(bool enter)
2378{
2379 pr_debug("enter = %d\n", enter);
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002380 if (enter == the_chip->is_bat_warm)
2381 return;
2382 the_chip->is_bat_warm = enter;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002383 if (enter) {
2384 btm_config.high_thr_temp =
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002385 the_chip->warm_temp_dc - TEMP_HYSTERISIS_DEGC;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002386 set_appropriate_battery_current(the_chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002387 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002388 pm_chg_vbatdet_set(the_chip,
2389 the_chip->warm_bat_voltage
2390 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002391 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002392 btm_config.high_thr_temp = the_chip->warm_temp_dc;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002393 set_appropriate_battery_current(the_chip);
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002394 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002395 pm_chg_vbatdet_set(the_chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002396 the_chip->max_voltage_mv
2397 - the_chip->resume_voltage_delta);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002398 }
2399 schedule_work(&btm_config_work);
2400}
2401
2402static int configure_btm(struct pm8921_chg_chip *chip)
2403{
2404 int rc;
2405
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08002406 if (chip->warm_temp_dc != INT_MIN)
2407 btm_config.btm_warm_fn = battery_warm;
2408 else
2409 btm_config.btm_warm_fn = NULL;
2410
2411 if (chip->cool_temp_dc != INT_MIN)
2412 btm_config.btm_cool_fn = battery_cool;
2413 else
2414 btm_config.btm_cool_fn = NULL;
2415
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002416 btm_config.low_thr_temp = chip->cool_temp_dc;
2417 btm_config.high_thr_temp = chip->warm_temp_dc;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002418 btm_config.interval = chip->temp_check_period;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002419 rc = pm8xxx_adc_btm_configure(&btm_config);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002420 if (rc)
2421 pr_err("failed to configure btm rc = %d\n", rc);
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07002422 rc = pm8xxx_adc_btm_start();
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002423 if (rc)
2424 pr_err("failed to start btm rc = %d\n", rc);
2425
2426 return rc;
2427}
2428
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07002429/**
2430 * set_disable_status_param -
2431 *
2432 * Internal function to disable battery charging and also disable drawing
2433 * any current from the source. The device is forced to run on a battery
2434 * after this.
2435 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436static int set_disable_status_param(const char *val, struct kernel_param *kp)
2437{
2438 int ret;
2439 struct pm8921_chg_chip *chip = the_chip;
2440
2441 ret = param_set_int(val, kp);
2442 if (ret) {
2443 pr_err("error setting value %d\n", ret);
2444 return ret;
2445 }
2446 pr_info("factory set disable param to %d\n", charging_disabled);
2447 if (chip) {
2448 pm_chg_auto_enable(chip, !charging_disabled);
2449 pm_chg_charge_dis(chip, charging_disabled);
2450 }
2451 return 0;
2452}
2453module_param_call(disabled, set_disable_status_param, param_get_uint,
2454 &charging_disabled, 0644);
2455
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002456/**
2457 * set_thermal_mitigation_level -
2458 *
2459 * Internal function to control battery charging current to reduce
2460 * temperature
2461 */
2462static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
2463{
2464 int ret;
2465 struct pm8921_chg_chip *chip = the_chip;
2466
2467 ret = param_set_int(val, kp);
2468 if (ret) {
2469 pr_err("error setting value %d\n", ret);
2470 return ret;
2471 }
2472
2473 if (!chip) {
2474 pr_err("called before init\n");
2475 return -EINVAL;
2476 }
2477
2478 if (!chip->thermal_mitigation) {
2479 pr_err("no thermal mitigation\n");
2480 return -EINVAL;
2481 }
2482
2483 if (thermal_mitigation < 0
2484 || thermal_mitigation >= chip->thermal_levels) {
2485 pr_err("out of bound level selected\n");
2486 return -EINVAL;
2487 }
2488
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08002489 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07002490 return ret;
2491}
2492module_param_call(thermal_mitigation, set_therm_mitigation_level,
2493 param_get_uint,
2494 &thermal_mitigation, 0644);
2495
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08002496static int set_usb_max_current(const char *val, struct kernel_param *kp)
2497{
2498 int ret, mA;
2499 struct pm8921_chg_chip *chip = the_chip;
2500
2501 ret = param_set_int(val, kp);
2502 if (ret) {
2503 pr_err("error setting value %d\n", ret);
2504 return ret;
2505 }
2506 if (chip) {
2507 pr_warn("setting current max to %d\n", usb_max_current);
2508 pm_chg_iusbmax_get(chip, &mA);
2509 if (mA > usb_max_current)
2510 pm8921_charger_vbus_draw(usb_max_current);
2511 return 0;
2512 }
2513 return -EINVAL;
2514}
2515module_param_call(usb_max_current, set_usb_max_current, param_get_uint,
2516 &usb_max_current, 0644);
2517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518static void free_irqs(struct pm8921_chg_chip *chip)
2519{
2520 int i;
2521
2522 for (i = 0; i < PM_CHG_MAX_INTS; i++)
2523 if (chip->pmic_chg_irq[i]) {
2524 free_irq(chip->pmic_chg_irq[i], chip);
2525 chip->pmic_chg_irq[i] = 0;
2526 }
2527}
2528
David Keitel88e1b572012-01-11 11:57:14 -08002529/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002530static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
2531{
2532 unsigned long flags;
2533 int fsm_state;
2534
2535 chip->dc_present = !!is_dc_chg_plugged_in(chip);
2536 chip->usb_present = !!is_usb_chg_plugged_in(chip);
2537
2538 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002539 if (chip->usb_present) {
2540 schedule_delayed_work(&chip->unplug_check_work,
2541 round_jiffies_relative(msecs_to_jiffies
2542 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2543 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544
2545 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
2546 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
2547 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002548 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
2549 pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
2550 pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
2551 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
2552 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07002553 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002554 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
2555 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08002556 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557
2558 spin_lock_irqsave(&vbus_lock, flags);
2559 if (usb_chg_current) {
2560 /* reissue a vbus draw call */
2561 __pm8921_charger_vbus_draw(usb_chg_current);
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002562 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 }
2564 spin_unlock_irqrestore(&vbus_lock, flags);
2565
2566 fsm_state = pm_chg_get_fsm_state(chip);
2567 if (is_battery_charging(fsm_state)) {
2568 chip->bms_notify.is_charging = 1;
2569 pm8921_bms_charging_began();
2570 }
2571
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002572 check_battery_valid(chip);
2573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
2575 chip->usb_present,
2576 chip->dc_present,
2577 get_prop_batt_present(chip),
2578 fsm_state);
2579}
2580
2581struct pm_chg_irq_init_data {
2582 unsigned int irq_id;
2583 char *name;
2584 unsigned long flags;
2585 irqreturn_t (*handler)(int, void *);
2586};
2587
2588#define CHG_IRQ(_id, _flags, _handler) \
2589{ \
2590 .irq_id = _id, \
2591 .name = #_id, \
2592 .flags = _flags, \
2593 .handler = _handler, \
2594}
2595struct pm_chg_irq_init_data chg_irq_data[] = {
2596 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2597 usbin_valid_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002598 CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2600 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002601 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2602 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2604 usbin_uv_irq_handler),
2605 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
2606 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
2607 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
2608 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
2609 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
2610 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
2611 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
2612 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
2613 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002614 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2615 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
2617 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
2618 batt_removed_irq_handler),
2619 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
2620 batttemp_hot_irq_handler),
2621 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
2622 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
2623 batttemp_cold_irq_handler),
2624 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING, chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002625 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2626 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
2628 coarse_det_low_irq_handler),
2629 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
2630 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
2631 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
2632 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2633 batfet_irq_handler),
2634 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2635 dcin_valid_irq_handler),
2636 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
2637 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07002638 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639};
2640
2641static int __devinit request_irqs(struct pm8921_chg_chip *chip,
2642 struct platform_device *pdev)
2643{
2644 struct resource *res;
2645 int ret, i;
2646
2647 ret = 0;
2648 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
2649
2650 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
2651 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
2652 chg_irq_data[i].name);
2653 if (res == NULL) {
2654 pr_err("couldn't find %s\n", chg_irq_data[i].name);
2655 goto err_out;
2656 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002657 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 ret = request_irq(res->start, chg_irq_data[i].handler,
2659 chg_irq_data[i].flags,
2660 chg_irq_data[i].name, chip);
2661 if (ret < 0) {
2662 pr_err("couldn't request %d (%s) %d\n", res->start,
2663 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002664 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665 goto err_out;
2666 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
2668 }
2669 return 0;
2670
2671err_out:
2672 free_irqs(chip);
2673 return -EINVAL;
2674}
2675
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002676static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
2677{
2678 int err;
2679 u8 temp;
2680
2681 temp = 0xD1;
2682 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2683 if (err) {
2684 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2685 return;
2686 }
2687
2688 temp = 0xD3;
2689 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2690 if (err) {
2691 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2692 return;
2693 }
2694
2695 temp = 0xD1;
2696 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2697 if (err) {
2698 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2699 return;
2700 }
2701
2702 temp = 0xD5;
2703 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2704 if (err) {
2705 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2706 return;
2707 }
2708
2709 udelay(183);
2710
2711 temp = 0xD1;
2712 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2713 if (err) {
2714 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2715 return;
2716 }
2717
2718 temp = 0xD0;
2719 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2720 if (err) {
2721 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2722 return;
2723 }
2724 udelay(32);
2725
2726 temp = 0xD1;
2727 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2728 if (err) {
2729 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2730 return;
2731 }
2732
2733 temp = 0xD3;
2734 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2735 if (err) {
2736 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2737 return;
2738 }
2739}
2740
2741static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
2742{
2743 int err;
2744 u8 temp;
2745
2746 temp = 0xD1;
2747 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2748 if (err) {
2749 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2750 return;
2751 }
2752
2753 temp = 0xD0;
2754 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2755 if (err) {
2756 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2757 return;
2758 }
2759}
2760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002761#define ENUM_TIMER_STOP_BIT BIT(1)
2762#define BOOT_DONE_BIT BIT(6)
2763#define CHG_BATFET_ON_BIT BIT(3)
2764#define CHG_VCP_EN BIT(0)
2765#define CHG_BAT_TEMP_DIS_BIT BIT(2)
2766#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002767#define VREF_BATT_THERM_FORCE_ON BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002768static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
2769{
2770 int rc;
2771
2772 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
2773 BOOT_DONE_BIT, BOOT_DONE_BIT);
2774 if (rc) {
2775 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
2776 return rc;
2777 }
2778
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002779 rc = pm_chg_vddsafe_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 if (rc) {
2781 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002782 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 return rc;
2784 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07002785 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002786 chip->max_voltage_mv
2787 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 if (rc) {
2789 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002790 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791 return rc;
2792 }
2793
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002794 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795 if (rc) {
2796 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08002797 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002798 return rc;
2799 }
2800 rc = pm_chg_ibatsafe_set(chip, SAFE_CURRENT_MA);
2801 if (rc) {
2802 pr_err("Failed to set max voltage to %d rc=%d\n",
2803 SAFE_CURRENT_MA, rc);
2804 return rc;
2805 }
2806
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07002807 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 if (rc) {
2809 pr_err("Failed to set max current to 400 rc=%d\n", rc);
2810 return rc;
2811 }
2812
2813 rc = pm_chg_iterm_set(chip, chip->term_current);
2814 if (rc) {
2815 pr_err("Failed to set term current to %d rc=%d\n",
2816 chip->term_current, rc);
2817 return rc;
2818 }
2819
2820 /* Disable the ENUM TIMER */
2821 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
2822 ENUM_TIMER_STOP_BIT);
2823 if (rc) {
2824 pr_err("Failed to set enum timer stop rc=%d\n", rc);
2825 return rc;
2826 }
2827
2828 /* init with the lowest USB current */
2829 rc = pm_chg_iusbmax_set(chip, usb_ma_table[0].chg_iusb_value);
2830 if (rc) {
2831 pr_err("Failed to set usb max to %d rc=%d\n",
2832 usb_ma_table[0].chg_iusb_value, rc);
2833 return rc;
2834 }
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002835
2836 if (chip->safety_time != 0) {
2837 rc = pm_chg_tchg_max_set(chip, chip->safety_time);
2838 if (rc) {
2839 pr_err("Failed to set max time to %d minutes rc=%d\n",
2840 chip->safety_time, rc);
2841 return rc;
2842 }
2843 }
2844
2845 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07002846 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002847 if (rc) {
2848 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
2849 chip->safety_time, rc);
2850 return rc;
2851 }
2852 }
2853
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002854 if (chip->vin_min != 0) {
2855 rc = pm_chg_vinmin_set(chip, chip->vin_min);
2856 if (rc) {
2857 pr_err("Failed to set vin min to %d mV rc=%d\n",
2858 chip->vin_min, rc);
2859 return rc;
2860 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002861 } else {
2862 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002863 }
2864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 rc = pm_chg_disable_wd(chip);
2866 if (rc) {
2867 pr_err("Failed to disable wd rc=%d\n", rc);
2868 return rc;
2869 }
2870
2871 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
2872 CHG_BAT_TEMP_DIS_BIT, 0);
2873 if (rc) {
2874 pr_err("Failed to enable temp control chg rc=%d\n", rc);
2875 return rc;
2876 }
2877 /* switch to a 3.2Mhz for the buck */
2878 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CLOCK_CTRL, 0x15);
2879 if (rc) {
2880 pr_err("Failed to switch buck clk rc=%d\n", rc);
2881 return rc;
2882 }
2883
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07002884 if (chip->trkl_voltage != 0) {
2885 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
2886 if (rc) {
2887 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
2888 chip->trkl_voltage, rc);
2889 return rc;
2890 }
2891 }
2892
2893 if (chip->weak_voltage != 0) {
2894 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
2895 if (rc) {
2896 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
2897 chip->weak_voltage, rc);
2898 return rc;
2899 }
2900 }
2901
2902 if (chip->trkl_current != 0) {
2903 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
2904 if (rc) {
2905 pr_err("Failed to set trkl current to %dmA rc=%d\n",
2906 chip->trkl_voltage, rc);
2907 return rc;
2908 }
2909 }
2910
2911 if (chip->weak_current != 0) {
2912 rc = pm_chg_iweak_set(chip, chip->weak_current);
2913 if (rc) {
2914 pr_err("Failed to set weak current to %dmA rc=%d\n",
2915 chip->weak_current, rc);
2916 return rc;
2917 }
2918 }
2919
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07002920 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
2921 if (rc) {
2922 pr_err("Failed to set cold config %d rc=%d\n",
2923 chip->cold_thr, rc);
2924 }
2925
2926 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
2927 if (rc) {
2928 pr_err("Failed to set hot config %d rc=%d\n",
2929 chip->hot_thr, rc);
2930 }
2931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932 /* Workarounds for die 1.1 and 1.0 */
2933 if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
2934 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
2936 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002937
2938 /* software workaround for correct battery_id detection */
2939 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
2940 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
2941 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
2942 pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
2943 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
2944 udelay(100);
2945 pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002946 }
2947
David Keitelb51995e2011-11-18 17:03:31 -08002948 /* Workarounds for die 3.0 */
2949 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
2950 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
2951
2952 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
2953
David Keitela3c0d822011-11-03 14:18:52 -07002954 /* Disable EOC FSM processing */
2955 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
2956
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08002957 pm8921_chg_force_19p2mhz_clk(chip);
2958
2959 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
2960 VREF_BATT_THERM_FORCE_ON);
2961 if (rc)
2962 pr_err("Failed to Force Vref therm rc=%d\n", rc);
2963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964 rc = pm_chg_charge_dis(chip, charging_disabled);
2965 if (rc) {
2966 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
2967 return rc;
2968 }
2969
2970 rc = pm_chg_auto_enable(chip, !charging_disabled);
2971 if (rc) {
2972 pr_err("Failed to enable charging rc=%d\n", rc);
2973 return rc;
2974 }
2975
2976 return 0;
2977}
2978
2979static int get_rt_status(void *data, u64 * val)
2980{
2981 int i = (int)data;
2982 int ret;
2983
2984 /* global irq number is passed in via data */
2985 ret = pm_chg_get_rt_status(the_chip, i);
2986 *val = ret;
2987 return 0;
2988}
2989DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
2990
2991static int get_fsm_status(void *data, u64 * val)
2992{
2993 u8 temp;
2994
2995 temp = pm_chg_get_fsm_state(the_chip);
2996 *val = temp;
2997 return 0;
2998}
2999DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
3000
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003001static int get_reg_loop(void *data, u64 * val)
3002{
3003 u8 temp;
3004
3005 if (!the_chip) {
3006 pr_err("%s called before init\n", __func__);
3007 return -EINVAL;
3008 }
3009 temp = pm_chg_get_regulation_loop(the_chip);
3010 *val = temp;
3011 return 0;
3012}
3013DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
3014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003015static int get_reg(void *data, u64 * val)
3016{
3017 int addr = (int)data;
3018 int ret;
3019 u8 temp;
3020
3021 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
3022 if (ret) {
3023 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
3024 addr, temp, ret);
3025 return -EAGAIN;
3026 }
3027 *val = temp;
3028 return 0;
3029}
3030
3031static int set_reg(void *data, u64 val)
3032{
3033 int addr = (int)data;
3034 int ret;
3035 u8 temp;
3036
3037 temp = (u8) val;
3038 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
3039 if (ret) {
3040 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
3041 addr, temp, ret);
3042 return -EAGAIN;
3043 }
3044 return 0;
3045}
3046DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
3047
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003048enum {
3049 BAT_WARM_ZONE,
3050 BAT_COOL_ZONE,
3051};
3052static int get_warm_cool(void *data, u64 * val)
3053{
3054 if (!the_chip) {
3055 pr_err("%s called before init\n", __func__);
3056 return -EINVAL;
3057 }
3058 if ((int)data == BAT_WARM_ZONE)
3059 *val = the_chip->is_bat_warm;
3060 if ((int)data == BAT_COOL_ZONE)
3061 *val = the_chip->is_bat_cool;
3062 return 0;
3063}
3064DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
3065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066static void create_debugfs_entries(struct pm8921_chg_chip *chip)
3067{
3068 int i;
3069
3070 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
3071
3072 if (IS_ERR(chip->dent)) {
3073 pr_err("pmic charger couldnt create debugfs dir\n");
3074 return;
3075 }
3076
3077 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
3078 (void *)CHG_CNTRL, &reg_fops);
3079 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
3080 (void *)CHG_CNTRL_2, &reg_fops);
3081 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
3082 (void *)CHG_CNTRL_3, &reg_fops);
3083 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
3084 (void *)PBL_ACCESS1, &reg_fops);
3085 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
3086 (void *)PBL_ACCESS2, &reg_fops);
3087 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
3088 (void *)SYS_CONFIG_1, &reg_fops);
3089 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
3090 (void *)SYS_CONFIG_2, &reg_fops);
3091 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
3092 (void *)CHG_VDD_MAX, &reg_fops);
3093 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
3094 (void *)CHG_VDD_SAFE, &reg_fops);
3095 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
3096 (void *)CHG_VBAT_DET, &reg_fops);
3097 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
3098 (void *)CHG_IBAT_MAX, &reg_fops);
3099 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
3100 (void *)CHG_IBAT_SAFE, &reg_fops);
3101 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
3102 (void *)CHG_VIN_MIN, &reg_fops);
3103 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
3104 (void *)CHG_VTRICKLE, &reg_fops);
3105 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
3106 (void *)CHG_ITRICKLE, &reg_fops);
3107 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
3108 (void *)CHG_ITERM, &reg_fops);
3109 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
3110 (void *)CHG_TCHG_MAX, &reg_fops);
3111 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
3112 (void *)CHG_TWDOG, &reg_fops);
3113 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
3114 (void *)CHG_TEMP_THRESH, &reg_fops);
3115 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
3116 (void *)CHG_COMP_OVR, &reg_fops);
3117 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
3118 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
3119 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
3120 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
3121 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
3122 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
3123 debugfs_create_file("CHG_TEST", 0644, chip->dent,
3124 (void *)CHG_TEST, &reg_fops);
3125
3126 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
3127 &fsm_fops);
3128
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003129 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
3130 &reg_loop_fops);
3131
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003132 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
3133 (void *)BAT_WARM_ZONE, &warm_cool_fops);
3134 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
3135 (void *)BAT_COOL_ZONE, &warm_cool_fops);
3136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3138 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
3139 debugfs_create_file(chg_irq_data[i].name, 0444,
3140 chip->dent,
3141 (void *)chg_irq_data[i].irq_id,
3142 &rt_fops);
3143 }
3144}
3145
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003146static int pm8921_charger_suspend_noirq(struct device *dev)
3147{
3148 int rc;
3149 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3150
3151 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
3152 if (rc)
3153 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
3154 pm8921_chg_set_hw_clk_switching(chip);
3155 return 0;
3156}
3157
3158static int pm8921_charger_resume_noirq(struct device *dev)
3159{
3160 int rc;
3161 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3162
3163 pm8921_chg_force_19p2mhz_clk(chip);
3164
3165 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
3166 VREF_BATT_THERM_FORCE_ON);
3167 if (rc)
3168 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
3169 return 0;
3170}
3171
David Keitelf2226022011-12-13 15:55:50 -08003172static int pm8921_charger_resume(struct device *dev)
3173{
3174 int rc;
3175 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3176
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003177 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003178 && !(chip->keep_btm_on_suspend)) {
3179 rc = pm8xxx_adc_btm_configure(&btm_config);
3180 if (rc)
3181 pr_err("couldn't reconfigure btm rc=%d\n", rc);
3182
3183 rc = pm8xxx_adc_btm_start();
3184 if (rc)
3185 pr_err("couldn't restart btm rc=%d\n", rc);
3186 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003187 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
3188 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3189 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
3190 }
David Keitelf2226022011-12-13 15:55:50 -08003191 return 0;
3192}
3193
3194static int pm8921_charger_suspend(struct device *dev)
3195{
3196 int rc;
3197 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
3198
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003199 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
David Keitelf2226022011-12-13 15:55:50 -08003200 && !(chip->keep_btm_on_suspend)) {
3201 rc = pm8xxx_adc_btm_end();
3202 if (rc)
3203 pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
3204 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003205
3206 if (is_usb_chg_plugged_in(chip)) {
3207 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
3208 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
3209 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003210
David Keitelf2226022011-12-13 15:55:50 -08003211 return 0;
3212}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003213static int __devinit pm8921_charger_probe(struct platform_device *pdev)
3214{
3215 int rc = 0;
3216 struct pm8921_chg_chip *chip;
3217 const struct pm8921_charger_platform_data *pdata
3218 = pdev->dev.platform_data;
3219
3220 if (!pdata) {
3221 pr_err("missing platform data\n");
3222 return -EINVAL;
3223 }
3224
3225 chip = kzalloc(sizeof(struct pm8921_chg_chip),
3226 GFP_KERNEL);
3227 if (!chip) {
3228 pr_err("Cannot allocate pm_chg_chip\n");
3229 return -ENOMEM;
3230 }
3231
3232 chip->dev = &pdev->dev;
3233 chip->safety_time = pdata->safety_time;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003234 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003236 chip->max_voltage_mv = pdata->max_voltage;
3237 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003238 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003239 chip->term_current = pdata->term_current;
3240 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003241 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003242 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
3243 chip->batt_id_min = pdata->batt_id_min;
3244 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003245 if (pdata->cool_temp != INT_MIN)
3246 chip->cool_temp_dc = pdata->cool_temp * 10;
3247 else
3248 chip->cool_temp_dc = INT_MIN;
3249
3250 if (pdata->warm_temp != INT_MIN)
3251 chip->warm_temp_dc = pdata->warm_temp * 10;
3252 else
3253 chip->warm_temp_dc = INT_MIN;
3254
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003255 chip->temp_check_period = pdata->temp_check_period;
3256 chip->max_bat_chg_current = pdata->max_bat_chg_current;
3257 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
3258 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
3259 chip->cool_bat_voltage = pdata->cool_bat_voltage;
3260 chip->warm_bat_voltage = pdata->warm_bat_voltage;
David Keitelf2226022011-12-13 15:55:50 -08003261 chip->keep_btm_on_suspend = pdata->keep_btm_on_suspend;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07003262 chip->trkl_voltage = pdata->trkl_voltage;
3263 chip->weak_voltage = pdata->weak_voltage;
3264 chip->trkl_current = pdata->trkl_current;
3265 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003266 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003267 chip->thermal_mitigation = pdata->thermal_mitigation;
3268 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07003270 chip->cold_thr = pdata->cold_thr;
3271 chip->hot_thr = pdata->hot_thr;
3272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 rc = pm8921_chg_hw_init(chip);
3274 if (rc) {
3275 pr_err("couldn't init hardware rc=%d\n", rc);
3276 goto free_chip;
3277 }
3278
3279 chip->usb_psy.name = "usb",
3280 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
3281 chip->usb_psy.supplied_to = pm_power_supplied_to,
3282 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3283 chip->usb_psy.properties = pm_power_props,
3284 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
3285 chip->usb_psy.get_property = pm_power_get_property,
3286
David Keitel6ed71a52012-01-30 12:42:18 -08003287 chip->dc_psy.name = "pm8921-dc",
3288 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
3289 chip->dc_psy.supplied_to = pm_power_supplied_to,
3290 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
3291 chip->dc_psy.properties = pm_power_props,
3292 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
3293 chip->dc_psy.get_property = pm_power_get_property,
3294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003295 chip->batt_psy.name = "battery",
3296 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
3297 chip->batt_psy.properties = msm_batt_power_props,
3298 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
3299 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08003300 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301 rc = power_supply_register(chip->dev, &chip->usb_psy);
3302 if (rc < 0) {
3303 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003304 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305 }
3306
David Keitel6ed71a52012-01-30 12:42:18 -08003307 rc = power_supply_register(chip->dev, &chip->dc_psy);
3308 if (rc < 0) {
3309 pr_err("power_supply_register usb failed rc = %d\n", rc);
3310 goto unregister_usb;
3311 }
3312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003313 rc = power_supply_register(chip->dev, &chip->batt_psy);
3314 if (rc < 0) {
3315 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08003316 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 }
3318
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003319 platform_set_drvdata(pdev, chip);
3320 the_chip = chip;
3321
3322 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003323 wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
3324 WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
Amir Samuelovd31ef502011-10-26 14:41:36 +02003325 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003326 INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
3327 unplug_wrkarnd_restore_worker);
3328 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003330 rc = request_irqs(chip, pdev);
3331 if (rc) {
3332 pr_err("couldn't register interrupts rc=%d\n", rc);
3333 goto unregister_batt;
3334 }
3335
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003336 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
3337 enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
3338 enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08003339 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
3340 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003341 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003342 /*
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003343 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003344 * care for jeita compliance
3345 */
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08003346 if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003347 rc = configure_btm(chip);
3348 if (rc) {
3349 pr_err("couldn't register with btm rc=%d\n", rc);
3350 goto free_irq;
3351 }
3352 }
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07003353
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 create_debugfs_entries(chip);
3355
3356 INIT_WORK(&chip->bms_notify.work, bms_notify);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003357 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003358
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003359 /* determine what state the charger is in */
3360 determine_initial_state(chip);
3361
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003362 if (chip->update_time) {
3363 INIT_DELAYED_WORK(&chip->update_heartbeat_work,
3364 update_heartbeat);
3365 schedule_delayed_work(&chip->update_heartbeat_work,
3366 round_jiffies_relative(msecs_to_jiffies
3367 (chip->update_time)));
3368 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003369 return 0;
3370
3371free_irq:
3372 free_irqs(chip);
3373unregister_batt:
3374 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08003375unregister_dc:
3376 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003377unregister_usb:
3378 power_supply_unregister(&chip->usb_psy);
3379free_chip:
3380 kfree(chip);
3381 return rc;
3382}
3383
3384static int __devexit pm8921_charger_remove(struct platform_device *pdev)
3385{
3386 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
3387
3388 free_irqs(chip);
3389 platform_set_drvdata(pdev, NULL);
3390 the_chip = NULL;
3391 kfree(chip);
3392 return 0;
3393}
David Keitelf2226022011-12-13 15:55:50 -08003394static const struct dev_pm_ops pm8921_pm_ops = {
3395 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003396 .suspend_noirq = pm8921_charger_suspend_noirq,
3397 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08003398 .resume = pm8921_charger_resume,
3399};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08003401 .probe = pm8921_charger_probe,
3402 .remove = __devexit_p(pm8921_charger_remove),
3403 .driver = {
3404 .name = PM8921_CHARGER_DEV_NAME,
3405 .owner = THIS_MODULE,
3406 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003407 },
3408};
3409
3410static int __init pm8921_charger_init(void)
3411{
3412 return platform_driver_register(&pm8921_charger_driver);
3413}
3414
3415static void __exit pm8921_charger_exit(void)
3416{
3417 platform_driver_unregister(&pm8921_charger_driver);
3418}
3419
3420late_initcall(pm8921_charger_init);
3421module_exit(pm8921_charger_exit);
3422
3423MODULE_LICENSE("GPL v2");
3424MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
3425MODULE_VERSION("1.0");
3426MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);