blob: e39e9d74a9d0f59f5cee060791220dcd530a3bb7 [file] [log] [blame]
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07001/* Copyright (c) 2011-2012, The Linux Foundation. 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>
David Keitel8b079fb2012-06-28 19:14:30 -070030#include <linux/mfd/pm8xxx/batt-alarm.h>
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -070031#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032
33#include <mach/msm_xo.h>
34#include <mach/msm_hsusb.h>
35
36#define CHG_BUCK_CLOCK_CTRL 0x14
David Keitel3567bec2012-06-26 16:35:53 -070037#define CHG_BUCK_CLOCK_CTRL_8038 0xD
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define PBL_ACCESS1 0x04
40#define PBL_ACCESS2 0x05
41#define SYS_CONFIG_1 0x06
42#define SYS_CONFIG_2 0x07
43#define CHG_CNTRL 0x204
44#define CHG_IBAT_MAX 0x205
45#define CHG_TEST 0x206
46#define CHG_BUCK_CTRL_TEST1 0x207
47#define CHG_BUCK_CTRL_TEST2 0x208
48#define CHG_BUCK_CTRL_TEST3 0x209
49#define COMPARATOR_OVERRIDE 0x20A
50#define PSI_TXRX_SAMPLE_DATA_0 0x20B
51#define PSI_TXRX_SAMPLE_DATA_1 0x20C
52#define PSI_TXRX_SAMPLE_DATA_2 0x20D
53#define PSI_TXRX_SAMPLE_DATA_3 0x20E
54#define PSI_CONFIG_STATUS 0x20F
55#define CHG_IBAT_SAFE 0x210
56#define CHG_ITRICKLE 0x211
57#define CHG_CNTRL_2 0x212
58#define CHG_VBAT_DET 0x213
59#define CHG_VTRICKLE 0x214
60#define CHG_ITERM 0x215
61#define CHG_CNTRL_3 0x216
62#define CHG_VIN_MIN 0x217
63#define CHG_TWDOG 0x218
64#define CHG_TTRKL_MAX 0x219
65#define CHG_TEMP_THRESH 0x21A
66#define CHG_TCHG_MAX 0x21B
67#define USB_OVP_CONTROL 0x21C
68#define DC_OVP_CONTROL 0x21D
69#define USB_OVP_TEST 0x21E
70#define DC_OVP_TEST 0x21F
71#define CHG_VDD_MAX 0x220
72#define CHG_VDD_SAFE 0x221
73#define CHG_VBAT_BOOT_THRESH 0x222
74#define USB_OVP_TRIM 0x355
75#define BUCK_CONTROL_TRIM1 0x356
76#define BUCK_CONTROL_TRIM2 0x357
77#define BUCK_CONTROL_TRIM3 0x358
78#define BUCK_CONTROL_TRIM4 0x359
79#define CHG_DEFAULTS_TRIM 0x35A
80#define CHG_ITRIM 0x35B
81#define CHG_TTRIM 0x35C
82#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070083#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070084#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070086/* check EOC every 10 seconds */
87#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080088/* check for USB unplug every 200 msecs */
89#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
David Keitel1e3a82f2012-06-26 16:27:15 -070090#define USB_TRIM_ENTRIES 16
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092enum chg_fsm_state {
93 FSM_STATE_OFF_0 = 0,
94 FSM_STATE_BATFETDET_START_12 = 12,
95 FSM_STATE_BATFETDET_END_16 = 16,
96 FSM_STATE_ON_CHG_HIGHI_1 = 1,
97 FSM_STATE_ATC_2A = 2,
98 FSM_STATE_ATC_2B = 18,
99 FSM_STATE_ON_BAT_3 = 3,
100 FSM_STATE_ATC_FAIL_4 = 4 ,
101 FSM_STATE_DELAY_5 = 5,
102 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
103 FSM_STATE_FAST_CHG_7 = 7,
104 FSM_STATE_TRKL_CHG_8 = 8,
105 FSM_STATE_CHG_FAIL_9 = 9,
106 FSM_STATE_EOC_10 = 10,
107 FSM_STATE_ON_CHG_VREGOK_11 = 11,
108 FSM_STATE_ATC_PAUSE_13 = 13,
109 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
110 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
111 FSM_STATE_START_BOOT = 20,
112 FSM_STATE_FLCB_VREGOK = 21,
113 FSM_STATE_FLCB = 22,
114};
115
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700116struct fsm_state_to_batt_status {
117 enum chg_fsm_state fsm_state;
118 int batt_state;
119};
120
David Keitel8b079fb2012-06-28 19:14:30 -0700121static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
122 unsigned long status, void *unused);
123
124static struct notifier_block alarm_notifier = {
125 .notifier_call = pm8921_battery_gauge_alarm_notify,
126};
127
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700128static struct fsm_state_to_batt_status map[] = {
129 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
130 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
131 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
132 /*
133 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
134 * too hot/cold, charger too hot
135 */
136 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
137 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
138 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
139 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
140 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
141 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
142 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
143 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
144 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
145 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
146 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
147 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
149 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
150 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
151 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
152 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
153 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
154};
155
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700156enum chg_regulation_loop {
157 VDD_LOOP = BIT(3),
158 BAT_CURRENT_LOOP = BIT(2),
159 INPUT_CURRENT_LOOP = BIT(1),
160 INPUT_VOLTAGE_LOOP = BIT(0),
161 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
162 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
163};
164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165enum pmic_chg_interrupts {
166 USBIN_VALID_IRQ = 0,
167 USBIN_OV_IRQ,
168 BATT_INSERTED_IRQ,
169 VBATDET_LOW_IRQ,
170 USBIN_UV_IRQ,
171 VBAT_OV_IRQ,
172 CHGWDOG_IRQ,
173 VCP_IRQ,
174 ATCDONE_IRQ,
175 ATCFAIL_IRQ,
176 CHGDONE_IRQ,
177 CHGFAIL_IRQ,
178 CHGSTATE_IRQ,
179 LOOP_CHANGE_IRQ,
180 FASTCHG_IRQ,
181 TRKLCHG_IRQ,
182 BATT_REMOVED_IRQ,
183 BATTTEMP_HOT_IRQ,
184 CHGHOT_IRQ,
185 BATTTEMP_COLD_IRQ,
186 CHG_GONE_IRQ,
187 BAT_TEMP_OK_IRQ,
188 COARSE_DET_LOW_IRQ,
189 VDD_LOOP_IRQ,
190 VREG_OV_IRQ,
191 VBATDET_IRQ,
192 BATFET_IRQ,
193 PSI_IRQ,
194 DCIN_VALID_IRQ,
195 DCIN_OV_IRQ,
196 DCIN_UV_IRQ,
197 PM_CHG_MAX_INTS,
198};
199
200struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700201 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 int is_charging;
203 struct work_struct work;
204};
205
206/**
207 * struct pm8921_chg_chip -device information
208 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 * @usb_present: present status of usb
210 * @dc_present: present status of dc
211 * @usb_charger_current: usb current to charge the battery with used when
212 * the usb path is enabled or charging is resumed
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800214 * @max_voltage_mv: the max volts the batt should be charged up to
215 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700216 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
David Keitel8b079fb2012-06-28 19:14:30 -0700217 * @alarm_low_mv: the battery alarm voltage low
218 * @alarm_high_mv: the battery alarm voltage high
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800219 * @cool_temp_dc: the cool temp threshold in deciCelcius
220 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700221 * @resume_voltage_delta: the voltage delta from vdd max at which the
222 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 * @term_current: The charging based term current
224 *
225 */
226struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700227 struct device *dev;
228 unsigned int usb_present;
229 unsigned int dc_present;
230 unsigned int usb_charger_current;
231 unsigned int max_bat_chg_current;
232 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700233 unsigned int ttrkl_time;
234 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800235 unsigned int max_voltage_mv;
236 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700237 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikara8f35422012-10-19 10:50:36 -0700238 unsigned int safe_current_ma;
David Keitel8b079fb2012-06-28 19:14:30 -0700239 unsigned int alarm_low_mv;
240 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800241 int cool_temp_dc;
242 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700243 unsigned int temp_check_period;
244 unsigned int cool_bat_chg_current;
245 unsigned int warm_bat_chg_current;
246 unsigned int cool_bat_voltage;
247 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700248 unsigned int is_bat_cool;
249 unsigned int is_bat_warm;
250 unsigned int resume_voltage_delta;
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -0700251 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700252 unsigned int term_current;
253 unsigned int vbat_channel;
254 unsigned int batt_temp_channel;
255 unsigned int batt_id_channel;
256 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800257 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800258 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700259 struct power_supply batt_psy;
260 struct dentry *dent;
261 struct bms_notify bms_notify;
David Keitel1e3a82f2012-06-26 16:27:15 -0700262 int *usb_trim_table;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200263 bool ext_charging;
264 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700265 bool iusb_fine_res;
David Keitel8b079fb2012-06-28 19:14:30 -0700266 bool disable_hw_clock_switching;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700268 struct work_struct battery_id_valid_work;
269 int64_t batt_id_min;
270 int64_t batt_id_max;
271 int trkl_voltage;
272 int weak_voltage;
273 int trkl_current;
274 int weak_current;
275 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800276 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700277 int thermal_levels;
278 struct delayed_work update_heartbeat_work;
279 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800280 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800281 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700282 struct wake_lock eoc_wake_lock;
283 enum pm8921_chg_cold_thr cold_thr;
284 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800285 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700286 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700287 bool host_mode;
David Keitela3cf9432012-08-24 15:11:23 -0700288 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700289 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700290 int recent_reported_soc;
Abhijeet Dharmapurikarbbaef592012-10-10 10:07:51 -0700291 int battery_less_hardware;
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -0700292 int ibatmax_max_adj_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293};
294
David Keitelacf57c82012-03-07 18:48:50 -0800295/* user space parameter to limit usb current */
296static unsigned int usb_max_current;
297/*
298 * usb_target_ma is used for wall charger
299 * adaptive input current limiting only. Use
300 * pm_iusbmax_get() to get current maximum usb current setting.
301 */
302static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700304static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305
306static struct pm8921_chg_chip *the_chip;
307
308static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
309 u8 mask, u8 val)
310{
311 int rc;
312 u8 reg;
313
314 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
315 if (rc) {
316 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
317 return rc;
318 }
319 reg &= ~mask;
320 reg |= val & mask;
321 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
322 if (rc) {
323 pr_err("pm8xxx_writeb failed: addr=%03X, rc=%d\n", addr, rc);
324 return rc;
325 }
326 return 0;
327}
328
David Keitelcf867232012-01-27 18:40:12 -0800329static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
330{
331 return pm8xxx_read_irq_stat(chip->dev->parent,
332 chip->pmic_chg_irq[irq_id]);
333}
334
335/* Treat OverVoltage/UnderVoltage as source missing */
336static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
337{
338 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
339}
340
341/* Treat OverVoltage/UnderVoltage as source missing */
342static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
343{
344 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
345}
346
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700347static int is_batfet_closed(struct pm8921_chg_chip *chip)
348{
349 return pm_chg_get_rt_status(chip, BATFET_IRQ);
350}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351#define CAPTURE_FSM_STATE_CMD 0xC2
352#define READ_BANK_7 0x70
353#define READ_BANK_4 0x40
354static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
355{
356 u8 temp;
357 int err, ret = 0;
358
359 temp = CAPTURE_FSM_STATE_CMD;
360 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
361 if (err) {
362 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
363 return err;
364 }
365
366 temp = READ_BANK_7;
367 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
368 if (err) {
369 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
370 return err;
371 }
372
373 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
374 if (err) {
375 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
376 return err;
377 }
378 /* get the lower 4 bits */
379 ret = temp & 0xF;
380
381 temp = READ_BANK_4;
382 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
383 if (err) {
384 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
385 return err;
386 }
387
388 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
389 if (err) {
390 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
391 return err;
392 }
393 /* get the upper 1 bit */
394 ret |= (temp & 0x1) << 4;
395 return ret;
396}
397
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700398#define READ_BANK_6 0x60
399static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
400{
401 u8 temp;
402 int err;
403
404 temp = READ_BANK_6;
405 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
406 if (err) {
407 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
408 return err;
409 }
410
411 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
412 if (err) {
413 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
414 return err;
415 }
416
417 /* return the lower 4 bits */
418 return temp & CHG_ALL_LOOPS;
419}
420
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421#define CHG_USB_SUSPEND_BIT BIT(2)
422static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
423{
424 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
425 enable ? CHG_USB_SUSPEND_BIT : 0);
426}
427
428#define CHG_EN_BIT BIT(7)
429static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
430{
431 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
432 enable ? CHG_EN_BIT : 0);
433}
434
David Keitel753ec8d2011-11-02 10:56:37 -0700435#define CHG_FAILED_CLEAR BIT(0)
436#define ATC_FAILED_CLEAR BIT(1)
437static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
438{
439 int rc;
440
441 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
442 clear ? ATC_FAILED_CLEAR : 0);
443 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
444 clear ? CHG_FAILED_CLEAR : 0);
445 return rc;
446}
447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448#define CHG_CHARGE_DIS_BIT BIT(1)
449static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
450{
451 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
452 disable ? CHG_CHARGE_DIS_BIT : 0);
453}
454
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800455static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
456{
457 u8 temp;
458
459 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
460 return temp & CHG_CHARGE_DIS_BIT;
461}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462#define PM8921_CHG_V_MIN_MV 3240
463#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800464#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465#define PM8921_CHG_VDDMAX_MAX 4500
466#define PM8921_CHG_VDDMAX_MIN 3400
467#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800468static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800470 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800471 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800473 if (voltage < PM8921_CHG_VDDMAX_MIN
474 || voltage > PM8921_CHG_VDDMAX_MAX) {
475 pr_err("bad mV=%d asked to set\n", voltage);
476 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477 }
David Keitelcf867232012-01-27 18:40:12 -0800478
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800479 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
480
481 remainder = voltage % 20;
482 if (remainder >= 10) {
483 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
484 }
485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 pr_debug("voltage=%d setting %02x\n", voltage, temp);
David Keitelcf867232012-01-27 18:40:12 -0800487 return pm8xxx_writeb(chip->dev->parent, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488}
489
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700490static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
491{
492 u8 temp;
493 int rc;
494
495 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
496 if (rc) {
497 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700498 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700499 return rc;
500 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800501 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
502 + PM8921_CHG_V_MIN_MV;
503 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
504 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700505 return 0;
506}
507
David Keitelcf867232012-01-27 18:40:12 -0800508static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
509{
510 int current_mv, ret, steps, i;
511 bool increase;
512
513 ret = 0;
514
515 if (voltage < PM8921_CHG_VDDMAX_MIN
516 || voltage > PM8921_CHG_VDDMAX_MAX) {
517 pr_err("bad mV=%d asked to set\n", voltage);
518 return -EINVAL;
519 }
520
521 ret = pm_chg_vddmax_get(chip, &current_mv);
522 if (ret) {
523 pr_err("Failed to read vddmax rc=%d\n", ret);
524 return -EINVAL;
525 }
526 if (current_mv == voltage)
527 return 0;
528
529 /* Only change in increments when USB is present */
530 if (is_usb_chg_plugged_in(chip)) {
531 if (current_mv < voltage) {
532 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
533 increase = true;
534 } else {
535 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
536 increase = false;
537 }
538 for (i = 0; i < steps; i++) {
539 if (increase)
540 current_mv += PM8921_CHG_V_STEP_MV;
541 else
542 current_mv -= PM8921_CHG_V_STEP_MV;
543 ret |= __pm_chg_vddmax_set(chip, current_mv);
544 }
545 }
546 ret |= __pm_chg_vddmax_set(chip, voltage);
547 return ret;
548}
549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550#define PM8921_CHG_VDDSAFE_MIN 3400
551#define PM8921_CHG_VDDSAFE_MAX 4500
552static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
553{
554 u8 temp;
555
556 if (voltage < PM8921_CHG_VDDSAFE_MIN
557 || voltage > PM8921_CHG_VDDSAFE_MAX) {
558 pr_err("bad mV=%d asked to set\n", voltage);
559 return -EINVAL;
560 }
561 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
562 pr_debug("voltage=%d setting %02x\n", voltage, temp);
563 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
564}
565
566#define PM8921_CHG_VBATDET_MIN 3240
567#define PM8921_CHG_VBATDET_MAX 5780
568static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
569{
570 u8 temp;
571
572 if (voltage < PM8921_CHG_VBATDET_MIN
573 || voltage > PM8921_CHG_VBATDET_MAX) {
574 pr_err("bad mV=%d asked to set\n", voltage);
575 return -EINVAL;
576 }
577 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
578 pr_debug("voltage=%d setting %02x\n", voltage, temp);
579 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
580}
581
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700582#define PM8921_CHG_VINMIN_MIN_MV 3800
583#define PM8921_CHG_VINMIN_STEP_MV 100
584#define PM8921_CHG_VINMIN_USABLE_MAX 6500
585#define PM8921_CHG_VINMIN_USABLE_MIN 4300
586#define PM8921_CHG_VINMIN_MASK 0x1F
587static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
588{
589 u8 temp;
590
591 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
592 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
593 pr_err("bad mV=%d asked to set\n", voltage);
594 return -EINVAL;
595 }
596 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
597 pr_debug("voltage=%d setting %02x\n", voltage, temp);
598 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
599 temp);
600}
601
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800602static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
603{
604 u8 temp;
605 int rc, voltage_mv;
606
607 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
608 temp &= PM8921_CHG_VINMIN_MASK;
609
610 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
611 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
612
613 return voltage_mv;
614}
615
David Keitel0789fc62012-06-07 17:43:27 -0700616#define PM8917_USB_UVD_MIN_MV 3850
617#define PM8917_USB_UVD_MAX_MV 4350
618#define PM8917_USB_UVD_STEP_MV 100
619#define PM8917_USB_UVD_MASK 0x7
620static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
621{
622 u8 temp;
623
624 if (thresh_mv < PM8917_USB_UVD_MIN_MV
625 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
626 pr_err("bad mV=%d asked to set\n", thresh_mv);
627 return -EINVAL;
628 }
629 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
630 return pm_chg_masked_write(chip, OVP_USB_UVD,
631 PM8917_USB_UVD_MASK, temp);
632}
633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -0700635#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636#define PM8921_CHG_I_MIN_MA 225
637#define PM8921_CHG_I_STEP_MA 50
638#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -0700639static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
640{
641 u8 temp;
642 int rc;
643
644 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
645 if (rc) {
646 pr_err("rc = %d while reading ibat max\n", rc);
647 *ibat_ma = 0;
648 return rc;
649 }
650 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
651 + PM8921_CHG_I_MIN_MA;
652 return 0;
653}
654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
656{
657 u8 temp;
658
659 if (chg_current < PM8921_CHG_IBATMAX_MIN
660 || chg_current > PM8921_CHG_IBATMAX_MAX) {
661 pr_err("bad mA=%d asked to set\n", chg_current);
662 return -EINVAL;
663 }
664 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
665 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
666}
667
668#define PM8921_CHG_IBATSAFE_MIN 225
669#define PM8921_CHG_IBATSAFE_MAX 3375
670static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
671{
672 u8 temp;
673
674 if (chg_current < PM8921_CHG_IBATSAFE_MIN
675 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
676 pr_err("bad mA=%d asked to set\n", chg_current);
677 return -EINVAL;
678 }
679 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
680 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
681 PM8921_CHG_I_MASK, temp);
682}
683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700685#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686#define PM8921_CHG_ITERM_STEP_MA 10
687#define PM8921_CHG_ITERM_MASK 0xF
688static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
689{
690 u8 temp;
691
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700692 if (chg_current < PM8921_CHG_ITERM_MIN_MA
693 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 pr_err("bad mA=%d asked to set\n", chg_current);
695 return -EINVAL;
696 }
697
698 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
699 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700700 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701 temp);
702}
703
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700704static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
705{
706 u8 temp;
707 int rc;
708
709 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
710 if (rc) {
711 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700712 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700713 return rc;
714 }
715 temp &= PM8921_CHG_ITERM_MASK;
716 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
717 + PM8921_CHG_ITERM_MIN_MA;
718 return 0;
719}
720
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800721struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700722 int usb_ma;
723 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800724};
725
David Keitel1e3a82f2012-06-26 16:27:15 -0700726/* USB Trim tables */
727static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
728 0x0,
729 0x0,
730 -0x9,
731 0x0,
732 -0xD,
733 0x0,
734 -0x10,
735 -0x11,
736 0x0,
737 0x0,
738 -0x25,
739 0x0,
740 -0x28,
741 0x0,
742 -0x32,
743 0x0
744};
745
746static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
747 0x0,
748 0x0,
749 0xA,
750 0xC,
751 0x10,
752 0x10,
753 0x13,
754 0x14,
755 0x13,
756 0x16,
757 0x1A,
758 0x1D,
759 0x1D,
760 0x21,
761 0x24,
762 0x26
763};
764
765/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800766static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700767 {100, 0x0},
768 {200, 0x1},
769 {500, 0x2},
770 {600, 0x3},
771 {700, 0x4},
772 {800, 0x5},
773 {850, 0x6},
774 {900, 0x8},
775 {950, 0x7},
776 {1000, 0x9},
777 {1100, 0xA},
778 {1200, 0xB},
779 {1300, 0xC},
780 {1400, 0xD},
781 {1500, 0xE},
782 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800783};
784
David Keitel1e3a82f2012-06-26 16:27:15 -0700785#define REG_SBI_CONFIG 0x04F
786#define PAGE3_ENABLE_MASK 0x6
787#define USB_OVP_TRIM_MASK 0x3F
788#define USB_OVP_TRIM_MIN 0x00
789#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
790#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
791static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
792{
793 u8 temp, sbi_config, msb, lsb;
794 s8 trim;
795 int rc = 0;
796 static u8 usb_trim_reg_orig = 0xFF;
797
798 /* No trim data for PM8921 */
799 if (!chip->usb_trim_table)
800 return 0;
801
802 if (usb_trim_reg_orig == 0xFF) {
803 rc = pm8xxx_readb(chip->dev->parent,
804 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
805 if (rc) {
806 pr_err("error = %d reading sbi config reg\n", rc);
807 return rc;
808 }
809
810 rc = pm8xxx_readb(chip->dev->parent,
811 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
812 if (rc) {
813 pr_err("error = %d reading sbi config reg\n", rc);
814 return rc;
815 }
816
817 msb = msb >> 5;
818 lsb = lsb >> 5;
819 usb_trim_reg_orig = msb << 3 | lsb;
820 }
821
822 /* use the original trim value */
823 trim = usb_trim_reg_orig;
824
825 trim += chip->usb_trim_table[index];
826 if (trim < 0)
827 trim = 0;
828
829 pr_err("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
830 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
831
832 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
833 if (rc) {
834 pr_err("error = %d reading sbi config reg\n", rc);
835 return rc;
836 }
837
838 temp = sbi_config | PAGE3_ENABLE_MASK;
839 rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, temp);
840 if (rc) {
841 pr_err("error = %d writing sbi config reg\n", rc);
842 return rc;
843 }
844
845 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, USB_OVP_TRIM_MASK, trim);
846 if (rc) {
847 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
848 return rc;
849 }
850
851 rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
852 if (rc) {
853 pr_err("error = %d writing sbi config reg\n", rc);
854 return rc;
855 }
856 return rc;
857}
858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700860#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861#define PM8921_CHG_IUSB_MAX 7
862#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700863#define PM8917_IUSB_FINE_RES BIT(0)
David Keitel1e3a82f2012-06-26 16:27:15 -0700864static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865{
David Keitel1e3a82f2012-06-26 16:27:15 -0700866 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700867 int rc;
868
David Keitel1e3a82f2012-06-26 16:27:15 -0700869 reg_val = usb_ma_table[index].value >> 1;
870 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700872 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
873 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 return -EINVAL;
875 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700876 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
877
878 /* IUSB_FINE_RES */
879 if (chip->iusb_fine_res) {
880 /* Clear IUSB_FINE_RES bit to avoid overshoot */
881 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
882 PM8917_IUSB_FINE_RES, 0);
883
884 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
885 PM8921_CHG_IUSB_MASK, temp);
886
887 if (rc) {
888 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
889 return rc;
890 }
891
892 if (fineres) {
893 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
894 PM8917_IUSB_FINE_RES, fineres);
David Keitel1e3a82f2012-06-26 16:27:15 -0700895 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700896 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
897 rc);
David Keitel1e3a82f2012-06-26 16:27:15 -0700898 return rc;
899 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700900 }
901 } else {
902 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
903 PM8921_CHG_IUSB_MASK, temp);
David Keitel1e3a82f2012-06-26 16:27:15 -0700904 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700905 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
David Keitel1e3a82f2012-06-26 16:27:15 -0700906 return rc;
907 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700908 }
909
David Keitel1e3a82f2012-06-26 16:27:15 -0700910 rc = pm_chg_usb_trim(chip, index);
911 if (rc)
912 pr_err("unable to set usb trim rc = %d\n", rc);
913
David Keitel38bdd4f2012-04-19 15:39:13 -0700914 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915}
916
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800917static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
918{
David Keitel38bdd4f2012-04-19 15:39:13 -0700919 u8 temp, fineres;
920 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800921
David Keitel38bdd4f2012-04-19 15:39:13 -0700922 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800923 *mA = 0;
924 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
925 if (rc) {
926 pr_err("err=%d reading PBL_ACCESS2\n", rc);
927 return rc;
928 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700929
930 if (chip->iusb_fine_res) {
931 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
932 if (rc) {
933 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
934 return rc;
935 }
936 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800937 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -0700938 temp = temp >> PM8921_CHG_IUSB_SHIFT;
939
940 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
941 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
942 if (usb_ma_table[i].value == temp)
943 break;
944 }
945
Willie Ruan69566002012-11-15 11:56:36 -0800946 if (i < 0) {
947 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
948 i = 0;
949 }
950
David Keitel38bdd4f2012-04-19 15:39:13 -0700951 *mA = usb_ma_table[i].usb_ma;
952
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800953 return rc;
954}
955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956#define PM8921_CHG_WD_MASK 0x1F
957static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
958{
959 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700960 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
961}
962
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -0700963#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700964#define PM8921_CHG_TCHG_MIN 4
965#define PM8921_CHG_TCHG_MAX 512
966#define PM8921_CHG_TCHG_STEP 4
967static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
968{
969 u8 temp;
970
971 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
972 pr_err("bad max minutes =%d asked to set\n", minutes);
973 return -EINVAL;
974 }
975
976 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
977 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
978 temp);
979}
980
David Keitelfb81b0a2012-08-31 20:00:53 -0700981#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -0700982#define PM8921_CHG_TTRKL_MIN 1
983#define PM8921_CHG_TTRKL_MAX 64
984static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
985{
986 u8 temp;
987
988 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
989 pr_err("bad max minutes =%d asked to set\n", minutes);
990 return -EINVAL;
991 }
992
993 temp = minutes - 1;
994 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
995 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996}
997
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -0700998#define PM8921_CHG_VTRKL_MIN_MV 2050
999#define PM8921_CHG_VTRKL_MAX_MV 2800
1000#define PM8921_CHG_VTRKL_STEP_MV 50
1001#define PM8921_CHG_VTRKL_SHIFT 4
1002#define PM8921_CHG_VTRKL_MASK 0xF0
1003static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1004{
1005 u8 temp;
1006
1007 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1008 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1009 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1010 return -EINVAL;
1011 }
1012
1013 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1014 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1015 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1016 temp);
1017}
1018
1019#define PM8921_CHG_VWEAK_MIN_MV 2100
1020#define PM8921_CHG_VWEAK_MAX_MV 3600
1021#define PM8921_CHG_VWEAK_STEP_MV 100
1022#define PM8921_CHG_VWEAK_MASK 0x0F
1023static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1024{
1025 u8 temp;
1026
1027 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1028 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1029 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1030 return -EINVAL;
1031 }
1032
1033 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1034 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1035 temp);
1036}
1037
1038#define PM8921_CHG_ITRKL_MIN_MA 50
1039#define PM8921_CHG_ITRKL_MAX_MA 200
1040#define PM8921_CHG_ITRKL_MASK 0x0F
1041#define PM8921_CHG_ITRKL_STEP_MA 10
1042static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1043{
1044 u8 temp;
1045
1046 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1047 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1048 pr_err("bad current = %dmA asked to set\n", milliamps);
1049 return -EINVAL;
1050 }
1051
1052 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1053
1054 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1055 temp);
1056}
1057
1058#define PM8921_CHG_IWEAK_MIN_MA 325
1059#define PM8921_CHG_IWEAK_MAX_MA 525
1060#define PM8921_CHG_IWEAK_SHIFT 7
1061#define PM8921_CHG_IWEAK_MASK 0x80
1062static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1063{
1064 u8 temp;
1065
1066 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1067 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1068 pr_err("bad current = %dmA asked to set\n", milliamps);
1069 return -EINVAL;
1070 }
1071
1072 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1073 temp = 0;
1074 else
1075 temp = 1;
1076
1077 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1078 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1079 temp);
1080}
1081
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001082#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1083#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1084static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1085 enum pm8921_chg_cold_thr cold_thr)
1086{
1087 u8 temp;
1088
1089 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1090 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1091 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1092 PM8921_CHG_BATT_TEMP_THR_COLD,
1093 temp);
1094}
1095
1096#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1097#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1098static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1099 enum pm8921_chg_hot_thr hot_thr)
1100{
1101 u8 temp;
1102
1103 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1104 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1105 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1106 PM8921_CHG_BATT_TEMP_THR_HOT,
1107 temp);
1108}
1109
Jay Chokshid674a512012-03-15 14:06:04 -07001110#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1111#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1112static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1113 enum pm8921_chg_led_src_config led_src_config)
1114{
1115 u8 temp;
1116
1117 if (led_src_config < LED_SRC_GND ||
1118 led_src_config > LED_SRC_BYPASS)
1119 return -EINVAL;
1120
1121 if (led_src_config == LED_SRC_BYPASS)
1122 return 0;
1123
1124 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1125
1126 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1127 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1128}
1129
David Keitel8c5201a2012-02-24 16:08:54 -08001130
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001131static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1132{
1133 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001134 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001135
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001136 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001137 if (rc) {
1138 pr_err("error reading batt id channel = %d, rc = %d\n",
1139 chip->vbat_channel, rc);
1140 return rc;
1141 }
1142 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1143 result.measurement);
1144 return result.physical;
1145}
1146
1147static int is_battery_valid(struct pm8921_chg_chip *chip)
1148{
1149 int64_t rc;
1150
1151 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1152 return 1;
1153
1154 rc = read_battery_id(chip);
1155 if (rc < 0) {
1156 pr_err("error reading batt id channel = %d, rc = %lld\n",
1157 chip->vbat_channel, rc);
1158 /* assume battery id is valid when adc error happens */
1159 return 1;
1160 }
1161
1162 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1163 pr_err("batt_id phy =%lld is not valid\n", rc);
1164 return 0;
1165 }
1166 return 1;
1167}
1168
1169static void check_battery_valid(struct pm8921_chg_chip *chip)
1170{
1171 if (is_battery_valid(chip) == 0) {
1172 pr_err("batt_id not valid, disbling charging\n");
1173 pm_chg_auto_enable(chip, 0);
1174 } else {
1175 pm_chg_auto_enable(chip, !charging_disabled);
1176 }
1177}
1178
1179static void battery_id_valid(struct work_struct *work)
1180{
1181 struct pm8921_chg_chip *chip = container_of(work,
1182 struct pm8921_chg_chip, battery_id_valid_work);
1183
1184 check_battery_valid(chip);
1185}
1186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1188{
1189 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1190 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1191 enable_irq(chip->pmic_chg_irq[interrupt]);
1192 }
1193}
1194
1195static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1196{
1197 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1198 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1199 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1200 }
1201}
1202
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001203static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1204{
1205 return test_bit(interrupt, chip->enabled_irqs);
1206}
1207
Amir Samuelovd31ef502011-10-26 14:41:36 +02001208static bool is_ext_charging(struct pm8921_chg_chip *chip)
1209{
David Keitel88e1b572012-01-11 11:57:14 -08001210 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001211
David Keitel88e1b572012-01-11 11:57:14 -08001212 if (!chip->ext_psy)
1213 return false;
1214 if (chip->ext_psy->get_property(chip->ext_psy,
1215 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1216 return false;
1217 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1218 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001219
1220 return false;
1221}
1222
1223static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1224{
David Keitel88e1b572012-01-11 11:57:14 -08001225 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001226
David Keitel88e1b572012-01-11 11:57:14 -08001227 if (!chip->ext_psy)
1228 return false;
1229 if (chip->ext_psy->get_property(chip->ext_psy,
1230 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1231 return false;
1232 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001233 return true;
1234
1235 return false;
1236}
1237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238static int is_battery_charging(int fsm_state)
1239{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001240 if (is_ext_charging(the_chip))
1241 return 1;
1242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 switch (fsm_state) {
1244 case FSM_STATE_ATC_2A:
1245 case FSM_STATE_ATC_2B:
1246 case FSM_STATE_ON_CHG_AND_BAT_6:
1247 case FSM_STATE_FAST_CHG_7:
1248 case FSM_STATE_TRKL_CHG_8:
1249 return 1;
1250 }
1251 return 0;
1252}
1253
1254static void bms_notify(struct work_struct *work)
1255{
1256 struct bms_notify *n = container_of(work, struct bms_notify, work);
1257
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001258 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001260 } else {
1261 pm8921_bms_charging_end(n->is_battery_full);
1262 n->is_battery_full = 0;
1263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264}
1265
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001266static void bms_notify_check(struct pm8921_chg_chip *chip)
1267{
1268 int fsm_state, new_is_charging;
1269
1270 fsm_state = pm_chg_get_fsm_state(chip);
1271 new_is_charging = is_battery_charging(fsm_state);
1272
1273 if (chip->bms_notify.is_charging ^ new_is_charging) {
1274 chip->bms_notify.is_charging = new_is_charging;
1275 schedule_work(&(chip->bms_notify.work));
1276 }
1277}
1278
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001279static enum power_supply_property pm_power_props_usb[] = {
1280 POWER_SUPPLY_PROP_PRESENT,
1281 POWER_SUPPLY_PROP_ONLINE,
1282 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001283 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001284};
1285
1286static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001288 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289};
1290
1291static char *pm_power_supplied_to[] = {
1292 "battery",
1293};
1294
David Keitel6ed71a52012-01-30 12:42:18 -08001295#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001296static int pm_power_get_property_mains(struct power_supply *psy,
1297 enum power_supply_property psp,
1298 union power_supply_propval *val)
1299{
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001300 /* Check if called before init */
1301 if (!the_chip)
1302 return -EINVAL;
1303
1304 switch (psp) {
1305 case POWER_SUPPLY_PROP_PRESENT:
1306 case POWER_SUPPLY_PROP_ONLINE:
1307 val->intval = 0;
David Keitela3cf9432012-08-24 15:11:23 -07001308
1309 if (the_chip->has_dc_supply) {
1310 val->intval = 1;
1311 return 0;
1312 }
1313
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001314 if (charging_disabled)
1315 return 0;
1316
1317 /* check external charger first before the dc path */
1318 if (is_ext_charging(the_chip)) {
1319 val->intval = 1;
1320 return 0;
1321 }
1322
1323 if (pm_is_chg_charge_dis(the_chip)) {
1324 val->intval = 0;
1325 return 0;
1326 }
1327
1328 if (the_chip->dc_present) {
1329 val->intval = 1;
1330 return 0;
1331 }
1332
1333 /* USB with max current greater than 500 mA connected */
David Keitelacf57c82012-03-07 18:48:50 -08001334 if (usb_target_ma > USB_WALL_THRESHOLD_MA)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001335 val->intval = is_usb_chg_plugged_in(the_chip);
1336 return 0;
1337
1338 break;
1339 default:
1340 return -EINVAL;
1341 }
1342 return 0;
1343}
1344
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001345static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1346{
1347 int rc;
1348
1349 if (!chip->host_mode)
1350 return 0;
1351
1352 /* enable usbin valid comparator and remove force usb ovp fet off */
1353 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB2);
1354 if (rc < 0) {
1355 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1356 return rc;
1357 }
1358
1359 chip->host_mode = 0;
1360
1361 return 0;
1362}
1363
1364static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1365{
1366 int rc;
1367
1368 if (chip->host_mode)
1369 return 0;
1370
1371 /* disable usbin valid comparator and force usb ovp fet off */
1372 rc = pm8xxx_writeb(chip->dev->parent, USB_OVP_TEST, 0xB3);
1373 if (rc < 0) {
1374 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1375 return rc;
1376 }
1377
1378 chip->host_mode = 1;
1379
1380 return 0;
1381}
1382
1383static int pm_power_set_property_usb(struct power_supply *psy,
1384 enum power_supply_property psp,
1385 const union power_supply_propval *val)
1386{
1387 /* Check if called before init */
1388 if (!the_chip)
1389 return -EINVAL;
1390
1391 switch (psp) {
1392 case POWER_SUPPLY_PROP_SCOPE:
1393 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
1394 return switch_usb_to_host_mode(the_chip);
1395 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
1396 return switch_usb_to_charge_mode(the_chip);
1397 else
1398 return -EINVAL;
1399 break;
David Keitel0e651472012-06-06 14:44:38 -07001400 case POWER_SUPPLY_PROP_TYPE:
1401 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001402 default:
1403 return -EINVAL;
1404 }
1405 return 0;
1406}
1407
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001408static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 enum power_supply_property psp,
1410 union power_supply_propval *val)
1411{
David Keitel6ed71a52012-01-30 12:42:18 -08001412 int current_max;
1413
1414 /* Check if called before init */
1415 if (!the_chip)
1416 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417
1418 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001419 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001420 if (pm_is_chg_charge_dis(the_chip)) {
1421 val->intval = 0;
1422 } else {
1423 pm_chg_iusbmax_get(the_chip, &current_max);
1424 val->intval = current_max;
1425 }
David Keitel6ed71a52012-01-30 12:42:18 -08001426 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001428 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001429 val->intval = 0;
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001430
David Keitel63f71662012-02-08 20:30:00 -08001431 /* USB charging */
David Keitelaf515712012-04-13 17:25:31 -07001432 if (usb_target_ma < USB_WALL_THRESHOLD_MA)
David Keitel86034022012-04-18 12:33:58 -07001433 val->intval = is_usb_chg_plugged_in(the_chip);
David Keitelaf515712012-04-13 17:25:31 -07001434 else
1435 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001437
1438 case POWER_SUPPLY_PROP_SCOPE:
1439 if (the_chip->host_mode)
1440 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1441 else
1442 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1443 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 default:
1445 return -EINVAL;
1446 }
1447 return 0;
1448}
1449
1450static enum power_supply_property msm_batt_power_props[] = {
1451 POWER_SUPPLY_PROP_STATUS,
1452 POWER_SUPPLY_PROP_CHARGE_TYPE,
1453 POWER_SUPPLY_PROP_HEALTH,
1454 POWER_SUPPLY_PROP_PRESENT,
1455 POWER_SUPPLY_PROP_TECHNOLOGY,
1456 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1457 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1458 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1459 POWER_SUPPLY_PROP_CAPACITY,
Binqiang Qiu2e1819e2012-08-15 17:37:37 -07001460 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001461 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001462 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001463 POWER_SUPPLY_PROP_ENERGY_FULL,
Abhijeet Dharmapurikar4c78f462012-10-16 15:43:55 -07001464 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465};
1466
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001467static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468{
1469 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001470 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001472 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 if (rc) {
1474 pr_err("error reading adc channel = %d, rc = %d\n",
1475 chip->vbat_channel, rc);
1476 return rc;
1477 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001478 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479 result.measurement);
1480 return (int)result.physical;
1481}
1482
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001483static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1484{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001485 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1486 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1487 unsigned int low_voltage = chip->min_voltage_mv;
1488 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001489
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001490 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001491 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001492 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001493 return 100;
1494 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001495 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001496 / (high_voltage - low_voltage);
1497}
1498
David Keitel4f9397b2012-04-16 11:46:16 -07001499static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1500{
1501 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1502}
1503
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07001504static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1505{
1506 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1507 int fsm_state = pm_chg_get_fsm_state(chip);
1508 int i;
1509
1510 if (chip->ext_psy) {
1511 if (chip->ext_charge_done)
1512 return POWER_SUPPLY_STATUS_FULL;
1513 if (chip->ext_charging)
1514 return POWER_SUPPLY_STATUS_CHARGING;
1515 }
1516
1517 for (i = 0; i < ARRAY_SIZE(map); i++)
1518 if (map[i].fsm_state == fsm_state)
1519 batt_state = map[i].batt_state;
1520
1521 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1522 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1523 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1524 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1525 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1526
1527 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1528 }
1529 return batt_state;
1530}
1531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1533{
David Keitel4f9397b2012-04-16 11:46:16 -07001534 int percent_soc;
1535
Abhijeet Dharmapurikarbbaef592012-10-10 10:07:51 -07001536 if (chip->battery_less_hardware)
1537 return 100;
1538
David Keitel4f9397b2012-04-16 11:46:16 -07001539 if (!get_prop_batt_present(chip))
1540 percent_soc = voltage_based_capacity(chip);
1541 else
1542 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001543
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001544 if (percent_soc == -ENXIO)
1545 percent_soc = voltage_based_capacity(chip);
1546
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001547 if (percent_soc <= 10)
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07001548 pr_warn_ratelimited("low battery charge = %d%%\n",
1549 percent_soc);
1550
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07001551 if (percent_soc <= chip->resume_charge_percent
1552 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07001553 pr_debug("soc fell below %d. charging enabled.\n",
1554 chip->resume_charge_percent);
1555 if (chip->is_bat_warm)
1556 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1557 chip->is_bat_warm,
1558 chip->resume_charge_percent);
1559 else if (chip->is_bat_cool)
1560 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1561 chip->is_bat_cool,
1562 chip->resume_charge_percent);
1563 else
1564 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1565 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001566
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001567 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001568 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569}
1570
Binqiang Qiu2e1819e2012-08-15 17:37:37 -07001571static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1572{
1573 int rbatt, ibatt_ua, vbatt_uv, ocv_uv;
1574 int imax_ma;
1575 int rc;
1576
1577 rbatt = pm8921_bms_get_rbatt();
1578
1579 if (rbatt < 0) {
1580 rc = -ENXIO;
1581 return rc;
1582 }
1583
1584 rc = pm8921_bms_get_simultaneous_battery_voltage_and_current
1585 (&ibatt_ua, &vbatt_uv);
1586
1587 if (rc)
1588 return rc;
1589
1590 ocv_uv = vbatt_uv + ibatt_ua*rbatt/1000;
1591
1592 imax_ma = (ocv_uv - chip->min_voltage_mv*1000)/rbatt;
1593
1594 if (imax_ma < 0)
1595 imax_ma = 0;
1596
1597 return imax_ma*1000;
1598
1599}
1600
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001601static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1602{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001603 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001604
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001605 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001606 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001607 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001608 }
1609
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001610 if (rc) {
1611 pr_err("unable to get batt current rc = %d\n", rc);
1612 return rc;
1613 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001614 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001615 }
1616}
1617
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001618static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1619{
1620 int rc;
1621
1622 rc = pm8921_bms_get_fcc();
1623 if (rc < 0)
1624 pr_err("unable to get batt fcc rc = %d\n", rc);
1625 return rc;
1626}
1627
Abhijeet Dharmapurikar4c78f462012-10-16 15:43:55 -07001628static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1629{
1630 int rc;
1631 int cc_uah;
1632
1633 rc = pm8921_bms_cc_uah(&cc_uah);
1634
1635 if (rc == 0)
1636 return cc_uah;
1637
1638 pr_err("unable to get batt fcc rc = %d\n", rc);
1639 return rc;
1640}
1641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1643{
1644 int temp;
1645
1646 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1647 if (temp)
1648 return POWER_SUPPLY_HEALTH_OVERHEAT;
1649
1650 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1651 if (temp)
1652 return POWER_SUPPLY_HEALTH_COLD;
1653
1654 return POWER_SUPPLY_HEALTH_GOOD;
1655}
1656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1658{
1659 int temp;
1660
Amir Samuelovd31ef502011-10-26 14:41:36 +02001661 if (!get_prop_batt_present(chip))
1662 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1663
1664 if (is_ext_trickle_charging(chip))
1665 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1666
1667 if (is_ext_charging(chip))
1668 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1671 if (temp)
1672 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1673
1674 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1675 if (temp)
1676 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1677
1678 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1679}
1680
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001681#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001682static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1683{
1684 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001685 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001686
Abhijeet Dharmapurikarbbaef592012-10-10 10:07:51 -07001687 if (chip->battery_less_hardware)
1688 return 300;
1689
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001690 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001691 if (rc) {
1692 pr_err("error reading adc channel = %d, rc = %d\n",
1693 chip->vbat_channel, rc);
1694 return rc;
1695 }
1696 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1697 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001698 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1699 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1700 (int) result.physical);
1701
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001702 return (int)result.physical;
1703}
1704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705static int pm_batt_power_get_property(struct power_supply *psy,
1706 enum power_supply_property psp,
1707 union power_supply_propval *val)
1708{
1709 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1710 batt_psy);
1711
1712 switch (psp) {
1713 case POWER_SUPPLY_PROP_STATUS:
1714 val->intval = get_prop_batt_status(chip);
1715 break;
1716 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1717 val->intval = get_prop_charge_type(chip);
1718 break;
1719 case POWER_SUPPLY_PROP_HEALTH:
1720 val->intval = get_prop_batt_health(chip);
1721 break;
1722 case POWER_SUPPLY_PROP_PRESENT:
1723 val->intval = get_prop_batt_present(chip);
1724 break;
1725 case POWER_SUPPLY_PROP_TECHNOLOGY:
1726 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1727 break;
1728 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001729 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 break;
1731 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001732 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 break;
1734 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001735 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 break;
1737 case POWER_SUPPLY_PROP_CAPACITY:
1738 val->intval = get_prop_batt_capacity(chip);
1739 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001740 case POWER_SUPPLY_PROP_CURRENT_NOW:
1741 val->intval = get_prop_batt_current(chip);
1742 break;
Binqiang Qiu2e1819e2012-08-15 17:37:37 -07001743 case POWER_SUPPLY_PROP_CURRENT_MAX:
1744 val->intval = get_prop_batt_current_max(chip);
1745 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001746 case POWER_SUPPLY_PROP_TEMP:
1747 val->intval = get_prop_batt_temp(chip);
1748 break;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001749 case POWER_SUPPLY_PROP_ENERGY_FULL:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001750 val->intval = get_prop_batt_fcc(chip) * 1000;
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001751 break;
Abhijeet Dharmapurikar4c78f462012-10-16 15:43:55 -07001752 case POWER_SUPPLY_PROP_CHARGE_NOW:
1753 val->intval = get_prop_batt_charge_now(chip);
1754 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 default:
1756 return -EINVAL;
1757 }
1758
1759 return 0;
1760}
1761
1762static void (*notify_vbus_state_func_ptr)(int);
1763static int usb_chg_current;
1764static DEFINE_SPINLOCK(vbus_lock);
1765
1766int pm8921_charger_register_vbus_sn(void (*callback)(int))
1767{
1768 pr_debug("%p\n", callback);
1769 notify_vbus_state_func_ptr = callback;
1770 return 0;
1771}
1772EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1773
1774/* this is passed to the hsusb via platform_data msm_otg_pdata */
1775void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1776{
1777 pr_debug("%p\n", callback);
1778 notify_vbus_state_func_ptr = NULL;
1779}
1780EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1781
1782static void notify_usb_of_the_plugin_event(int plugin)
1783{
1784 plugin = !!plugin;
1785 if (notify_vbus_state_func_ptr) {
1786 pr_debug("notifying plugin\n");
1787 (*notify_vbus_state_func_ptr) (plugin);
1788 } else {
1789 pr_debug("unable to notify plugin\n");
1790 }
1791}
1792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793/* assumes vbus_lock is held */
1794static void __pm8921_charger_vbus_draw(unsigned int mA)
1795{
1796 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001797 if (!the_chip) {
1798 pr_err("called before init\n");
1799 return;
1800 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801
Willie Ruan0db41d42012-11-15 13:49:22 -08001802 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001804 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001806 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 }
1808 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1809 if (rc)
1810 pr_err("fail to set suspend bit rc=%d\n", rc);
1811 } else {
1812 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1813 if (rc)
1814 pr_err("fail to reset suspend bit rc=%d\n", rc);
1815 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1816 if (usb_ma_table[i].usb_ma <= mA)
1817 break;
1818 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001819
Willie Ruan69566002012-11-15 11:56:36 -08001820 if (i < 0) {
1821 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1822 mA);
1823 i = 0;
1824 }
1825
David Keitel38bdd4f2012-04-19 15:39:13 -07001826 /* Check if IUSB_FINE_RES is available */
David Keitel67ebde02012-10-01 11:12:59 -07001827 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001828 && !the_chip->iusb_fine_res)
1829 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 if (i < 0)
1831 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001832 rc = pm_chg_iusbmax_set(the_chip, i);
David Keitel1e3a82f2012-06-26 16:27:15 -07001833 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001834 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 }
1836}
1837
1838/* USB calls these to tell us how much max usb current the system can draw */
1839void pm8921_charger_vbus_draw(unsigned int mA)
1840{
1841 unsigned long flags;
1842
1843 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001844
David Keitel62c6a4b2012-05-17 12:54:59 -07001845 if (!the_chip) {
1846 pr_err("chip not yet initalized\n");
1847 return;
1848 }
1849
1850 /*
1851 * Reject VBUS requests if USB connection is the only available
1852 * power source. This makes sure that if booting without
1853 * battery the iusb_max value is not decreased avoiding potential
1854 * brown_outs.
1855 *
1856 * This would also apply when the battery has been
1857 * removed from the running system.
1858 */
1859 if (!get_prop_batt_present(the_chip)
1860 && !is_dc_chg_plugged_in(the_chip)) {
David Keitela3cf9432012-08-24 15:11:23 -07001861 if (!the_chip->has_dc_supply) {
David Keitelacb258c2012-07-13 17:12:04 -07001862 pr_err("rejected: no other power source connected\n");
1863 return;
1864 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001865 }
1866
David Keitelacf57c82012-03-07 18:48:50 -08001867 if (usb_max_current && mA > usb_max_current) {
1868 pr_warn("restricting usb current to %d instead of %d\n",
1869 usb_max_current, mA);
1870 mA = usb_max_current;
1871 }
1872 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1873 usb_target_ma = mA;
1874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 spin_lock_irqsave(&vbus_lock, flags);
1876 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001877 if (mA > USB_WALL_THRESHOLD_MA)
1878 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1879 else
1880 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001881 } else {
1882 /*
1883 * called before pmic initialized,
1884 * save this value and use it at probe
1885 */
David Keitelacf57c82012-03-07 18:48:50 -08001886 if (mA > USB_WALL_THRESHOLD_MA)
1887 usb_chg_current = USB_WALL_THRESHOLD_MA;
1888 else
1889 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890 }
1891 spin_unlock_irqrestore(&vbus_lock, flags);
1892}
1893EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1894
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001895int pm8921_is_usb_chg_plugged_in(void)
1896{
1897 if (!the_chip) {
1898 pr_err("called before init\n");
1899 return -EINVAL;
1900 }
1901 return is_usb_chg_plugged_in(the_chip);
1902}
1903EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1904
1905int pm8921_is_dc_chg_plugged_in(void)
1906{
1907 if (!the_chip) {
1908 pr_err("called before init\n");
1909 return -EINVAL;
1910 }
1911 return is_dc_chg_plugged_in(the_chip);
1912}
1913EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1914
1915int pm8921_is_battery_present(void)
1916{
1917 if (!the_chip) {
1918 pr_err("called before init\n");
1919 return -EINVAL;
1920 }
1921 return get_prop_batt_present(the_chip);
1922}
1923EXPORT_SYMBOL(pm8921_is_battery_present);
1924
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07001925int pm8921_is_batfet_closed(void)
1926{
1927 if (!the_chip) {
1928 pr_err("called before init\n");
1929 return -EINVAL;
1930 }
1931 return is_batfet_closed(the_chip);
1932}
1933EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08001934/*
1935 * Disabling the charge current limit causes current
1936 * current limits to have no monitoring. An adequate charger
1937 * capable of supplying high current while sustaining VIN_MIN
1938 * is required if the limiting is disabled.
1939 */
1940int pm8921_disable_input_current_limit(bool disable)
1941{
1942 if (!the_chip) {
1943 pr_err("called before init\n");
1944 return -EINVAL;
1945 }
1946 if (disable) {
1947 pr_warn("Disabling input current limit!\n");
1948
1949 return pm8xxx_writeb(the_chip->dev->parent,
1950 CHG_BUCK_CTRL_TEST3, 0xF2);
1951 }
1952 return 0;
1953}
1954EXPORT_SYMBOL(pm8921_disable_input_current_limit);
1955
David Keitel0789fc62012-06-07 17:43:27 -07001956int pm8917_set_under_voltage_detection_threshold(int mv)
1957{
1958 if (!the_chip) {
1959 pr_err("called before init\n");
1960 return -EINVAL;
1961 }
1962 return pm_chg_uvd_threshold_set(the_chip, mv);
1963}
1964EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
1965
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001966int pm8921_set_max_battery_charge_current(int ma)
1967{
1968 if (!the_chip) {
1969 pr_err("called before init\n");
1970 return -EINVAL;
1971 }
1972 return pm_chg_ibatmax_set(the_chip, ma);
1973}
1974EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
1975
1976int pm8921_disable_source_current(bool disable)
1977{
1978 if (!the_chip) {
1979 pr_err("called before init\n");
1980 return -EINVAL;
1981 }
1982 if (disable)
1983 pr_warn("current drawn from chg=0, battery provides current\n");
David Keiteld8878592012-09-04 09:33:28 -07001984
1985 pm_chg_usb_suspend_enable(the_chip, disable);
1986
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001987 return pm_chg_charge_dis(the_chip, disable);
1988}
1989EXPORT_SYMBOL(pm8921_disable_source_current);
1990
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001991int pm8921_regulate_input_voltage(int voltage)
1992{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001993 int rc;
1994
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07001995 if (!the_chip) {
1996 pr_err("called before init\n");
1997 return -EINVAL;
1998 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001999 rc = pm_chg_vinmin_set(the_chip, voltage);
2000
2001 if (rc == 0)
2002 the_chip->vin_min = voltage;
2003
2004 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002005}
2006
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002007#define USB_OV_THRESHOLD_MASK 0x60
2008#define USB_OV_THRESHOLD_SHIFT 5
2009int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2010{
2011 u8 temp;
2012
2013 if (!the_chip) {
2014 pr_err("called before init\n");
2015 return -EINVAL;
2016 }
2017
2018 if (ov > PM_USB_OV_7V) {
2019 pr_err("limiting to over voltage threshold to 7volts\n");
2020 ov = PM_USB_OV_7V;
2021 }
2022
2023 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2024
2025 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2026 USB_OV_THRESHOLD_MASK, temp);
2027}
2028EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2029
2030#define USB_DEBOUNCE_TIME_MASK 0x06
2031#define USB_DEBOUNCE_TIME_SHIFT 1
2032int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2033{
2034 u8 temp;
2035
2036 if (!the_chip) {
2037 pr_err("called before init\n");
2038 return -EINVAL;
2039 }
2040
2041 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2042 pr_err("limiting debounce to 80.5ms\n");
2043 ms = PM_USB_DEBOUNCE_80P5MS;
2044 }
2045
2046 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2047
2048 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2049 USB_DEBOUNCE_TIME_MASK, temp);
2050}
2051EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2052
2053#define USB_OVP_DISABLE_MASK 0x80
2054int pm8921_usb_ovp_disable(int disable)
2055{
2056 u8 temp = 0;
2057
2058 if (!the_chip) {
2059 pr_err("called before init\n");
2060 return -EINVAL;
2061 }
2062
2063 if (disable)
2064 temp = USB_OVP_DISABLE_MASK;
2065
2066 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2067 USB_OVP_DISABLE_MASK, temp);
2068}
2069
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002070bool pm8921_is_battery_charging(int *source)
2071{
2072 int fsm_state, is_charging, dc_present, usb_present;
2073
2074 if (!the_chip) {
2075 pr_err("called before init\n");
2076 return -EINVAL;
2077 }
2078 fsm_state = pm_chg_get_fsm_state(the_chip);
2079 is_charging = is_battery_charging(fsm_state);
2080 if (is_charging == 0) {
2081 *source = PM8921_CHG_SRC_NONE;
2082 return is_charging;
2083 }
2084
2085 if (source == NULL)
2086 return is_charging;
2087
2088 /* the battery is charging, the source is requested, find it */
2089 dc_present = is_dc_chg_plugged_in(the_chip);
2090 usb_present = is_usb_chg_plugged_in(the_chip);
2091
2092 if (dc_present && !usb_present)
2093 *source = PM8921_CHG_SRC_DC;
2094
2095 if (usb_present && !dc_present)
2096 *source = PM8921_CHG_SRC_USB;
2097
2098 if (usb_present && dc_present)
2099 /*
2100 * The system always chooses dc for charging since it has
2101 * higher priority.
2102 */
2103 *source = PM8921_CHG_SRC_DC;
2104
2105 return is_charging;
2106}
2107EXPORT_SYMBOL(pm8921_is_battery_charging);
2108
David Keitel86034022012-04-18 12:33:58 -07002109int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2110{
2111 if (!the_chip) {
2112 pr_err("called before init\n");
2113 return -EINVAL;
2114 }
2115
2116 if (type < POWER_SUPPLY_TYPE_USB)
2117 return -EINVAL;
2118
2119 the_chip->usb_psy.type = type;
2120 power_supply_changed(&the_chip->usb_psy);
2121 power_supply_changed(&the_chip->dc_psy);
2122 return 0;
2123}
2124EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2125
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002126int pm8921_batt_temperature(void)
2127{
2128 if (!the_chip) {
2129 pr_err("called before init\n");
2130 return -EINVAL;
2131 }
2132 return get_prop_batt_temp(the_chip);
2133}
2134
David Keitel8b079fb2012-06-28 19:14:30 -07002135static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
2136{
2137 int rc = 0;
2138
2139 rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2140 if (!rc)
2141 rc = pm8xxx_batt_alarm_enable(
2142 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2143 if (rc) {
2144 pr_err("unable to set batt alarm state rc=%d\n", rc);
2145 return rc;
2146 }
2147
2148 return rc;
2149}
2150static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
2151{
2152 int rc = 0;
2153
2154 rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2155 if (!rc)
2156 rc = pm8xxx_batt_alarm_disable(
2157 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2158 if (rc) {
2159 pr_err("unable to set batt alarm state rc=%d\n", rc);
2160 return rc;
2161 }
2162
2163 /*
2164 * The batt-alarm driver requires sane values for both min / max,
2165 * regardless of whether they're both activated.
2166 */
2167 rc = pm8xxx_batt_alarm_threshold_set(
2168 PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
2169 chip->alarm_low_mv);
2170 if (!rc)
2171 rc = pm8xxx_batt_alarm_threshold_set(
2172 PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
2173 chip->alarm_high_mv);
2174 if (rc) {
2175 pr_err("unable to set batt alarm threshold rc=%d\n", rc);
2176 return rc;
2177 }
2178
2179 rc = pm8xxx_batt_alarm_hold_time_set(
2180 PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
2181 if (rc) {
2182 pr_err("unable to set batt alarm hold time rc=%d\n", rc);
2183 return rc;
2184 }
2185
2186 /* PWM enabled at 2Hz */
2187 rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
2188 if (rc) {
2189 pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
2190 return rc;
2191 }
2192
2193 rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
2194 if (rc) {
2195 pr_err("unable to register alarm notifier rc=%d\n", rc);
2196 return rc;
2197 }
2198
2199 return rc;
2200}
2201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2203{
2204 int usb_present;
2205
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002206 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002207 usb_present = is_usb_chg_plugged_in(chip);
2208 if (chip->usb_present ^ usb_present) {
2209 notify_usb_of_the_plugin_event(usb_present);
2210 chip->usb_present = usb_present;
2211 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002212 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002213 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002214 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002215 if (usb_present) {
2216 schedule_delayed_work(&chip->unplug_check_work,
2217 round_jiffies_relative(msecs_to_jiffies
2218 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08002219 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2220 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002221 /* USB unplugged reset target current */
2222 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002223 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002224 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002225 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226}
2227
Amir Samuelovd31ef502011-10-26 14:41:36 +02002228static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2229{
David Keitel88e1b572012-01-11 11:57:14 -08002230 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002231 pr_debug("external charger not registered.\n");
2232 return;
2233 }
2234
2235 if (!chip->ext_charging) {
2236 pr_debug("already not charging.\n");
2237 return;
2238 }
2239
David Keitel88e1b572012-01-11 11:57:14 -08002240 power_supply_set_charge_type(chip->ext_psy,
2241 POWER_SUPPLY_CHARGE_TYPE_NONE);
2242 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002243 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002244 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002245 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002246 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002247 /* Update battery charging LEDs and user space battery info */
2248 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002249}
2250
2251static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2252{
2253 int dc_present;
2254 int batt_present;
2255 int batt_temp_ok;
2256 int vbat_ov;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002257 unsigned long delay =
2258 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2259
David Keitel88e1b572012-01-11 11:57:14 -08002260 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002261 pr_debug("external charger not registered.\n");
2262 return;
2263 }
2264
2265 if (chip->ext_charging) {
2266 pr_debug("already charging.\n");
2267 return;
2268 }
2269
David Keitel88e1b572012-01-11 11:57:14 -08002270 dc_present = is_dc_chg_plugged_in(the_chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002271 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2272 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002273
2274 if (!dc_present) {
2275 pr_warn("%s. dc not present.\n", __func__);
2276 return;
2277 }
2278 if (!batt_present) {
2279 pr_warn("%s. battery not present.\n", __func__);
2280 return;
2281 }
2282 if (!batt_temp_ok) {
2283 pr_warn("%s. battery temperature not ok.\n", __func__);
2284 return;
2285 }
Abhijeet Dharmapurikar70ef3822012-10-29 15:55:34 -07002286
2287 /* Force BATFET=ON */
2288 pm8921_disable_source_current(true);
2289
David Keitel88e1b572012-01-11 11:57:14 -08002290 vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002291 if (vbat_ov) {
2292 pr_warn("%s. battery over voltage.\n", __func__);
2293 return;
2294 }
Amir Samuelovd31ef502011-10-26 14:41:36 +02002295
David Keitel6ccbf132012-05-30 14:21:24 -07002296 schedule_delayed_work(&chip->unplug_check_work,
2297 round_jiffies_relative(msecs_to_jiffies
2298 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel6ccbf132012-05-30 14:21:24 -07002299
David Keitel63f71662012-02-08 20:30:00 -08002300 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002301 power_supply_set_charge_type(chip->ext_psy,
2302 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002303 chip->ext_charging = true;
2304 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002305 bms_notify_check(chip);
Abhijeet Dharmapurikar70ef3822012-10-29 15:55:34 -07002306 /*
2307 * since we wont get a fastchg irq from external charger
2308 * use eoc worker to detect end of charging
2309 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002310 schedule_delayed_work(&chip->eoc_work, delay);
2311 wake_lock(&chip->eoc_wake_lock);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002312 /* Update battery charging LEDs and user space battery info */
2313 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002314}
2315
David Keitel6ccbf132012-05-30 14:21:24 -07002316static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002317{
2318 u8 temp;
2319 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002320
David Keitel6ccbf132012-05-30 14:21:24 -07002321 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002322 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002323 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002324 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002325 }
David Keitel6ccbf132012-05-30 14:21:24 -07002326 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002327 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002328 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002329 return;
2330 }
2331 /* set ovp fet disable bit and the write bit */
2332 temp |= 0x81;
David Keitel6ccbf132012-05-30 14:21:24 -07002333 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002334 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002335 pr_err("Failed to write 0x%x OVP_TEST rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002336 return;
2337 }
2338}
2339
David Keitel8b079fb2012-06-28 19:14:30 -07002340static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
2341 unsigned long status, void *unused)
2342{
2343 int rc;
2344
2345 pr_info("status: %lu\n", status);
2346
2347 /* Check if called before init */
2348
2349 switch (status) {
2350 case 0:
2351 pr_err("spurious interrupt\n");
2352 break;
2353 /* expected case - trip of low threshold */
2354 case 1:
2355 if (!the_chip) {
2356 pr_err("not initialized\n");
2357 return -EINVAL;
2358 }
2359
2360 the_chip->disable_hw_clock_switching = 1;
2361
2362 rc = pm8xxx_batt_alarm_disable(
2363 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2364 if (!rc)
2365 rc = pm8xxx_batt_alarm_enable(
2366 PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2367 if (rc)
2368 pr_err("unable to set alarm state rc=%d\n", rc);
2369 break;
2370 case 2:
2371 if (!the_chip) {
2372 pr_err("not initialized\n");
2373 return -EINVAL;
2374 }
2375
2376 the_chip->disable_hw_clock_switching = 0;
2377
2378 rc = pm8xxx_batt_alarm_disable(
2379 PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
2380 if (!rc)
2381 rc = pm8xxx_batt_alarm_enable(
2382 PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
2383 if (rc)
2384 pr_err("unable to set alarm state rc=%d\n", rc);
2385
2386 pr_err("trip of high threshold\n");
2387 break;
2388 default:
2389 pr_err("error received\n");
2390 };
2391
2392 return 0;
2393}
2394
David Keitel6ccbf132012-05-30 14:21:24 -07002395static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002396{
2397 u8 temp;
2398 int rc;
2399
David Keitel6ccbf132012-05-30 14:21:24 -07002400 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002401 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002402 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002403 return;
2404 }
David Keitel6ccbf132012-05-30 14:21:24 -07002405 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002406 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002407 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002408 return;
2409 }
2410 /* unset ovp fet disable bit and set the write bit */
2411 temp &= 0xFE;
2412 temp |= 0x80;
David Keitel6ccbf132012-05-30 14:21:24 -07002413 rc = pm8xxx_writeb(chip->dev->parent, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002414 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002415 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002416 temp, rc);
2417 return;
2418 }
2419}
2420
2421static int param_open_ovp_counter = 10;
2422module_param(param_open_ovp_counter, int, 0644);
2423
David Keitel6ccbf132012-05-30 14:21:24 -07002424#define USB_ACTIVE_BIT BIT(5)
2425#define DC_ACTIVE_BIT BIT(6)
2426static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2427 u8 active_chg_mask)
2428{
2429 if (active_chg_mask & USB_ACTIVE_BIT)
2430 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2431 else if (active_chg_mask & DC_ACTIVE_BIT)
2432 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2433 else
2434 return 0;
2435}
2436
David Keitel8c5201a2012-02-24 16:08:54 -08002437#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002438#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002439static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002440{
David Keitel6ccbf132012-05-30 14:21:24 -07002441 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002442 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002443 u8 active_mask = 0;
2444 u16 ovpreg, ovptestreg;
2445
2446 if (is_usb_chg_plugged_in(chip) &&
2447 (chip->active_path & USB_ACTIVE_BIT)) {
2448 ovpreg = USB_OVP_CONTROL;
2449 ovptestreg = USB_OVP_TEST;
2450 active_mask = USB_ACTIVE_BIT;
2451 } else if (is_dc_chg_plugged_in(chip) &&
2452 (chip->active_path & DC_ACTIVE_BIT)) {
2453 ovpreg = DC_OVP_CONTROL;
2454 ovptestreg = DC_OVP_TEST;
2455 active_mask = DC_ACTIVE_BIT;
2456 } else {
2457 return;
2458 }
David Keitel8c5201a2012-02-24 16:08:54 -08002459
2460 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002461 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002462 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002463 active_chg_plugged_in
2464 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002465 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002466 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2467 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002468
2469 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002470 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002471 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002472 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002473
2474 msleep(20);
2475
David Keitel6ccbf132012-05-30 14:21:24 -07002476 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002477 } else {
David Keitel712782e2012-03-29 14:11:47 -07002478 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002479 }
2480 }
David Keitel6ccbf132012-05-30 14:21:24 -07002481 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2482 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2483 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002484 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002485}
David Keitelacf57c82012-03-07 18:48:50 -08002486
2487static int find_usb_ma_value(int value)
2488{
2489 int i;
2490
2491 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2492 if (value >= usb_ma_table[i].usb_ma)
2493 break;
2494 }
2495
2496 return i;
2497}
2498
2499static void decrease_usb_ma_value(int *value)
2500{
2501 int i;
2502
2503 if (value) {
2504 i = find_usb_ma_value(*value);
2505 if (i > 0)
2506 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002507 while (!the_chip->iusb_fine_res && i > 0
2508 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2509 i--;
Willie Ruan69566002012-11-15 11:56:36 -08002510
2511 if (i < 0) {
2512 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2513 *value);
2514 i = 0;
2515 }
2516
David Keitelacf57c82012-03-07 18:48:50 -08002517 *value = usb_ma_table[i].usb_ma;
2518 }
2519}
2520
2521static void increase_usb_ma_value(int *value)
2522{
2523 int i;
2524
2525 if (value) {
2526 i = find_usb_ma_value(*value);
2527
2528 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2529 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002530 /* Get next correct entry if IUSB_FINE_RES is not available */
2531 while (!the_chip->iusb_fine_res
2532 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2533 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2534 i++;
2535
David Keitelacf57c82012-03-07 18:48:50 -08002536 *value = usb_ma_table[i].usb_ma;
2537 }
2538}
2539
2540static void vin_collapse_check_worker(struct work_struct *work)
2541{
2542 struct delayed_work *dwork = to_delayed_work(work);
2543 struct pm8921_chg_chip *chip = container_of(dwork,
2544 struct pm8921_chg_chip, vin_collapse_check_work);
2545
Abhijeet Dharmapurikar6bf4d142012-10-31 19:07:16 -07002546 /*
2547 * AICL only for wall-chargers. If the charger appears to be plugged
2548 * back in now, the corresponding unplug must have been because of we
2549 * were trying to draw more current than the charger can support. In
2550 * such a case reset usb current to 500mA and decrease the target.
2551 * The AICL algorithm will step up the current from 500mA to target
2552 */
2553 if (is_usb_chg_plugged_in(chip)
2554 && usb_target_ma > USB_WALL_THRESHOLD_MA) {
David Keitelacf57c82012-03-07 18:48:50 -08002555 /* decrease usb_target_ma */
2556 decrease_usb_ma_value(&usb_target_ma);
2557 /* reset here, increase in unplug_check_worker */
2558 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2559 pr_debug("usb_now=%d, usb_target = %d\n",
2560 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar6bf4d142012-10-31 19:07:16 -07002561 if (!delayed_work_pending(&chip->unplug_check_work))
2562 schedule_delayed_work(&chip->unplug_check_work,
2563 round_jiffies_relative(msecs_to_jiffies
2564 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitelacf57c82012-03-07 18:48:50 -08002565 } else {
2566 handle_usb_insertion_removal(chip);
2567 }
2568}
2569
2570#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2572{
David Keitelacf57c82012-03-07 18:48:50 -08002573 if (usb_target_ma)
2574 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2575 round_jiffies_relative(msecs_to_jiffies
2576 (VIN_MIN_COLLAPSE_CHECK_MS)));
2577 else
2578 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 return IRQ_HANDLED;
2580}
2581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2583{
2584 struct pm8921_chg_chip *chip = data;
2585 int status;
2586
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002587 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2588 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002589 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 pr_debug("battery present=%d", status);
2591 power_supply_changed(&chip->batt_psy);
2592 return IRQ_HANDLED;
2593}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002594
2595/*
2596 * this interrupt used to restart charging a battery.
2597 *
2598 * Note: When DC-inserted the VBAT can't go low.
2599 * VPH_PWR is provided by the ext-charger.
2600 * After End-Of-Charging from DC, charging can be resumed only
2601 * if DC is removed and then inserted after the battery was in use.
2602 * Therefore the handle_start_ext_chg() is not called.
2603 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2605{
2606 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002607 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002609 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002610
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002611 if (high_transition) {
2612 /* enable auto charging */
2613 pm_chg_auto_enable(chip, !charging_disabled);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08002614 pr_info("batt fell below resume voltage %s\n",
2615 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002616 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 power_supply_changed(&chip->batt_psy);
2620 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002621 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 return IRQ_HANDLED;
2624}
2625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
2627{
2628 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2629 return IRQ_HANDLED;
2630}
2631
2632static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2633{
2634 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2635 return IRQ_HANDLED;
2636}
2637
2638static irqreturn_t vcp_irq_handler(int irq, void *data)
2639{
David Keitel8c5201a2012-02-24 16:08:54 -08002640 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641 return IRQ_HANDLED;
2642}
2643
2644static irqreturn_t atcdone_irq_handler(int irq, void *data)
2645{
2646 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2647 return IRQ_HANDLED;
2648}
2649
2650static irqreturn_t atcfail_irq_handler(int irq, void *data)
2651{
2652 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2653 return IRQ_HANDLED;
2654}
2655
2656static irqreturn_t chgdone_irq_handler(int irq, void *data)
2657{
2658 struct pm8921_chg_chip *chip = data;
2659
2660 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002661
2662 handle_stop_ext_chg(chip);
2663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664 power_supply_changed(&chip->batt_psy);
2665 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002666 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002667
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002668 bms_notify_check(chip);
2669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 return IRQ_HANDLED;
2671}
2672
2673static irqreturn_t chgfail_irq_handler(int irq, void *data)
2674{
2675 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002676 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677
David Keitel753ec8d2011-11-02 10:56:37 -07002678 ret = pm_chg_failed_clear(chip, 1);
2679 if (ret)
2680 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2681
2682 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2683 get_prop_batt_present(chip),
2684 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2685 pm_chg_get_fsm_state(data));
2686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 power_supply_changed(&chip->batt_psy);
2688 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002689 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 return IRQ_HANDLED;
2691}
2692
2693static irqreturn_t chgstate_irq_handler(int irq, void *data)
2694{
2695 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696
2697 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2698 power_supply_changed(&chip->batt_psy);
2699 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002700 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002702 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 return IRQ_HANDLED;
2705}
2706
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002707enum {
2708 PON_TIME_25NS = 0x04,
2709 PON_TIME_50NS = 0x08,
2710 PON_TIME_100NS = 0x0C,
2711};
David Keitel8c5201a2012-02-24 16:08:54 -08002712
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002713static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002714{
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002715 u8 temp;
2716 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002717
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002718 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x40);
2719 if (rc) {
2720 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2721 return;
2722 }
2723 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2724 if (rc) {
2725 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2726 return;
2727 }
2728 /* clear the min pon time select bit */
2729 temp &= 0xF3;
2730 /* set the pon time */
2731 temp |= (u8)pon_time_ns;
2732 /* write enable bank 4 */
2733 temp |= 0x80;
2734 rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
2735 if (rc) {
2736 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2737 return;
2738 }
2739}
David Keitel8c5201a2012-02-24 16:08:54 -08002740
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002741static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2742{
2743 pr_debug("Start\n");
2744 set_min_pon_time(chip, PON_TIME_100NS);
2745 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2746 msleep(250);
2747 pm_chg_vinmin_set(chip, chip->vin_min);
2748 set_min_pon_time(chip, PON_TIME_25NS);
2749 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002750}
2751
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002752#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002753#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2754#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002755static void unplug_check_worker(struct work_struct *work)
2756{
2757 struct delayed_work *dwork = to_delayed_work(work);
2758 struct pm8921_chg_chip *chip = container_of(dwork,
2759 struct pm8921_chg_chip, unplug_check_work);
David Keitel6ccbf132012-05-30 14:21:24 -07002760 u8 reg_loop, active_path;
2761 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002762 int chg_gone = 0;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002763
David Keitelacf57c82012-03-07 18:48:50 -08002764 reg_loop = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002765
2766 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2767 if (rc) {
2768 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2769 return;
2770 }
2771 chip->active_path = active_path;
2772
2773 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
2774 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2775 active_path, active_chg_plugged_in);
2776 if (active_path & USB_ACTIVE_BIT) {
2777 pr_debug("USB charger active\n");
2778
2779 pm_chg_iusbmax_get(chip, &usb_ma);
David Keitel6ccbf132012-05-30 14:21:24 -07002780
2781 if (usb_ma <= 100) {
2782 pr_debug(
2783 "Unenumerated or suspended usb_ma = %d skip\n",
2784 usb_ma);
2785 goto check_again_later;
2786 }
2787 } else if (active_path & DC_ACTIVE_BIT) {
2788 pr_debug("DC charger active\n");
2789 } else {
2790 /* No charger active */
2791 if (!(is_usb_chg_plugged_in(chip)
2792 && !(is_dc_chg_plugged_in(chip)))) {
2793 pr_debug(
2794 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2795 pm_chg_get_regulation_loop(chip),
2796 pm_chg_get_fsm_state(chip),
2797 get_prop_batt_current(chip)
2798 );
Abhijeet Dharmapurikar76d25482012-08-28 19:33:49 -07002799 return;
2800 } else {
2801 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002802 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002803 }
Abhijeet Dharmapurikarcda28f92012-10-29 11:55:48 -07002804 /* AICL only for usb wall charger */
2805 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
David Keitel6ccbf132012-05-30 14:21:24 -07002806 reg_loop = pm_chg_get_regulation_loop(chip);
2807 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2808 if ((reg_loop & VIN_ACTIVE_BIT) &&
David Keitel5c3ab6d2012-07-30 16:42:42 -07002809 (usb_ma > USB_WALL_THRESHOLD_MA)
2810 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002811 decrease_usb_ma_value(&usb_ma);
2812 usb_target_ma = usb_ma;
2813 /* end AICL here */
2814 __pm8921_charger_vbus_draw(usb_ma);
2815 pr_debug("usb_now=%d, usb_target = %d\n",
2816 usb_ma, usb_target_ma);
2817 }
David Keitelacf57c82012-03-07 18:48:50 -08002818 }
2819
2820 reg_loop = pm_chg_get_regulation_loop(chip);
2821 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2822
David Keitel6ccbf132012-05-30 14:21:24 -07002823 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002824 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002825 if (ibat > 0) {
Abhijeet Dharmapurikar5b675ff2012-10-24 13:12:57 -07002826 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2827 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2828 attempt_reverse_boost_fix(chip);
2829 /* after reverse boost fix check if the active
2830 * charger was detected as removed */
2831 active_chg_plugged_in
2832 = is_active_chg_plugged_in(chip,
2833 active_path);
2834 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2835 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002836 }
2837 }
2838
David Keitel6ccbf132012-05-30 14:21:24 -07002839 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
2840 pr_debug("active_path = 0x%x, active_chg = %d\n",
2841 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002842 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2843
David Keitel6ccbf132012-05-30 14:21:24 -07002844 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2845 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2846 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002847 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002848 }
2849
Abhijeet Dharmapurikarcda28f92012-10-29 11:55:48 -07002850 /* AICL only for usb wall charger */
David Keitel5c3ab6d2012-07-30 16:42:42 -07002851 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
Abhijeet Dharmapurikarcda28f92012-10-29 11:55:48 -07002852 && usb_target_ma > 0
David Keitel5c3ab6d2012-07-30 16:42:42 -07002853 && !charging_disabled) {
David Keitelacf57c82012-03-07 18:48:50 -08002854 /* only increase iusb_max if vin loop not active */
2855 if (usb_ma < usb_target_ma) {
2856 increase_usb_ma_value(&usb_ma);
2857 __pm8921_charger_vbus_draw(usb_ma);
2858 pr_debug("usb_now=%d, usb_target = %d\n",
2859 usb_ma, usb_target_ma);
2860 } else {
2861 usb_target_ma = usb_ma;
2862 }
2863 }
David Keitel8c5201a2012-02-24 16:08:54 -08002864check_again_later:
David Keitelacf57c82012-03-07 18:48:50 -08002865 /* schedule to check again later */
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002866 schedule_delayed_work(&chip->unplug_check_work,
2867 round_jiffies_relative(msecs_to_jiffies
2868 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
2869}
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871static irqreturn_t loop_change_irq_handler(int irq, void *data)
2872{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002873 struct pm8921_chg_chip *chip = data;
2874
2875 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2876 pm_chg_get_fsm_state(data),
2877 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002878 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 return IRQ_HANDLED;
2880}
2881
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -07002882struct ibatmax_max_adj_entry {
2883 int ibat_max_ma;
2884 int max_adj_ma;
2885};
2886
2887static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2888 {975, 300},
2889 {1475, 150},
2890 {1975, 200},
2891 {2475, 250},
2892};
2893
2894static int find_ibat_max_adj_ma(int ibat_target_ma)
2895{
2896 int i = 0;
2897
2898 for (i = ARRAY_SIZE(ibatmax_adj_table) - 1; i >= 0; i--) {
2899 if (ibat_target_ma <= ibatmax_adj_table[i].ibat_max_ma)
2900 break;
2901 }
2902
2903 return ibatmax_adj_table[i].max_adj_ma;
2904}
2905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002906static irqreturn_t fastchg_irq_handler(int irq, void *data)
2907{
2908 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002909 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002911 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2912 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2913 wake_lock(&chip->eoc_wake_lock);
2914 schedule_delayed_work(&chip->eoc_work,
2915 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002916 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002917 }
2918 power_supply_changed(&chip->batt_psy);
2919 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 return IRQ_HANDLED;
2921}
2922
2923static irqreturn_t trklchg_irq_handler(int irq, void *data)
2924{
2925 struct pm8921_chg_chip *chip = data;
2926
2927 power_supply_changed(&chip->batt_psy);
2928 return IRQ_HANDLED;
2929}
2930
2931static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2932{
2933 struct pm8921_chg_chip *chip = data;
2934 int status;
2935
2936 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2937 pr_debug("battery present=%d state=%d", !status,
2938 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002939 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 power_supply_changed(&chip->batt_psy);
2941 return IRQ_HANDLED;
2942}
2943
2944static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2945{
2946 struct pm8921_chg_chip *chip = data;
2947
Amir Samuelovd31ef502011-10-26 14:41:36 +02002948 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002949 power_supply_changed(&chip->batt_psy);
2950 return IRQ_HANDLED;
2951}
2952
2953static irqreturn_t chghot_irq_handler(int irq, void *data)
2954{
2955 struct pm8921_chg_chip *chip = data;
2956
2957 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2958 power_supply_changed(&chip->batt_psy);
2959 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002960 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 return IRQ_HANDLED;
2962}
2963
2964static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2965{
2966 struct pm8921_chg_chip *chip = data;
2967
2968 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002969 handle_stop_ext_chg(chip);
2970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 power_supply_changed(&chip->batt_psy);
2972 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 return IRQ_HANDLED;
2974}
2975
2976static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2977{
2978 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002979 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002980
2981 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2982 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2983
2984 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
David Keitel0873d0f2012-03-29 11:44:49 -07002985 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
2986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 power_supply_changed(&chip->batt_psy);
2988 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 return IRQ_HANDLED;
2990}
David Keitel52fda532011-11-10 10:43:44 -08002991/*
2992 *
2993 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2994 * fire for two cases:
2995 *
2996 * If the interrupt line switches to high temperature is okay
2997 * and thus charging begins.
2998 * If bat_temp_ok is low this means the temperature is now
2999 * too hot or cold, so charging is stopped.
3000 *
3001 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3003{
David Keitel52fda532011-11-10 10:43:44 -08003004 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 struct pm8921_chg_chip *chip = data;
3006
David Keitel52fda532011-11-10 10:43:44 -08003007 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3008
3009 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3010 bat_temp_ok, pm_chg_get_fsm_state(data));
3011
3012 if (bat_temp_ok)
3013 handle_start_ext_chg(chip);
3014 else
3015 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003016
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003017 power_supply_changed(&chip->batt_psy);
3018 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003019 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003020 return IRQ_HANDLED;
3021}
3022
3023static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3024{
3025 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3026 return IRQ_HANDLED;
3027}
3028
3029static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3030{
3031 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3032 return IRQ_HANDLED;
3033}
3034
3035static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3036{
3037 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3038 return IRQ_HANDLED;
3039}
3040
3041static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3042{
3043 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3044 return IRQ_HANDLED;
3045}
3046
3047static irqreturn_t batfet_irq_handler(int irq, void *data)
3048{
3049 struct pm8921_chg_chip *chip = data;
3050
3051 pr_debug("vreg ov\n");
3052 power_supply_changed(&chip->batt_psy);
3053 return IRQ_HANDLED;
3054}
3055
3056static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3057{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003058 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003059 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003060
Abhijeet Dharmapurikar70ef3822012-10-29 15:55:34 -07003061 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003062 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
David Keitele7a05ca2012-10-16 16:37:28 -07003063
Abhijeet Dharmapurikar70ef3822012-10-29 15:55:34 -07003064 if (chip->dc_present ^ dc_present)
3065 pm8921_bms_calibrate_hkadc();
3066
3067 if (dc_present)
3068 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
3069 else
3070 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3071
3072 chip->dc_present = dc_present;
3073
3074 if (chip->ext_psy) {
3075 if (dc_present)
3076 handle_start_ext_chg(chip);
3077 else
3078 handle_stop_ext_chg(chip);
3079 } else {
3080 if (dc_present)
3081 schedule_delayed_work(&chip->unplug_check_work,
3082 round_jiffies_relative(msecs_to_jiffies
3083 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitele7a05ca2012-10-16 16:37:28 -07003084 power_supply_changed(&chip->dc_psy);
David Keitele7a05ca2012-10-16 16:37:28 -07003085 }
3086
Abhijeet Dharmapurikar70ef3822012-10-29 15:55:34 -07003087 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 return IRQ_HANDLED;
3089}
3090
3091static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3092{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003093 struct pm8921_chg_chip *chip = data;
3094
Amir Samuelovd31ef502011-10-26 14:41:36 +02003095 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096 return IRQ_HANDLED;
3097}
3098
3099static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3100{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003101 struct pm8921_chg_chip *chip = data;
3102
Amir Samuelovd31ef502011-10-26 14:41:36 +02003103 handle_stop_ext_chg(chip);
3104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 return IRQ_HANDLED;
3106}
3107
David Keitel88e1b572012-01-11 11:57:14 -08003108static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3109{
3110 struct power_supply *psy = &the_chip->batt_psy;
3111 struct power_supply *epsy = dev_get_drvdata(dev);
3112 int i, dcin_irq;
3113
3114 /* Only search for external supply if none is registered */
3115 if (!the_chip->ext_psy) {
3116 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3117 for (i = 0; i < epsy->num_supplicants; i++) {
3118 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3119 if (!strncmp(epsy->name, "dc", 2)) {
3120 the_chip->ext_psy = epsy;
3121 dcin_valid_irq_handler(dcin_irq,
3122 the_chip);
3123 }
3124 }
3125 }
3126 }
3127 return 0;
3128}
3129
3130static void pm_batt_external_power_changed(struct power_supply *psy)
3131{
3132 /* Only look for an external supply if it hasn't been registered */
3133 if (!the_chip->ext_psy)
3134 class_for_each_device(power_supply_class, NULL, psy,
3135 __pm_batt_external_power_changed_work);
3136}
3137
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003138/**
3139 * update_heartbeat - internal function to update userspace
3140 * per update_time minutes
3141 *
3142 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003143#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003144static void update_heartbeat(struct work_struct *work)
3145{
3146 struct delayed_work *dwork = to_delayed_work(work);
3147 struct pm8921_chg_chip *chip = container_of(dwork,
3148 struct pm8921_chg_chip, update_heartbeat_work);
3149
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003150 pm_chg_failed_clear(chip, 1);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003151 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003152 if (chip->recent_reported_soc <= 20)
3153 schedule_delayed_work(&chip->update_heartbeat_work,
3154 round_jiffies_relative(msecs_to_jiffies
3155 (LOW_SOC_HEARTBEAT_MS)));
3156 else
3157 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003158 round_jiffies_relative(msecs_to_jiffies
3159 (chip->update_time)));
3160}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003161#define VDD_LOOP_ACTIVE_BIT BIT(3)
3162#define VDD_MAX_INCREASE_MV 400
3163static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3164module_param(vdd_max_increase_mv, int, 0644);
3165
3166static int ichg_threshold_ua = -400000;
3167module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003168
3169#define PM8921_CHG_VDDMAX_RES_MV 10
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003170static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3171 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003172{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003173 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003174 int vbat_batt_terminal_mv;
3175 int reg_loop;
3176 int delta_mv = 0;
3177
3178 if (chip->rconn_mohm == 0) {
3179 pr_debug("Exiting as rconn_mohm is 0\n");
3180 return;
3181 }
3182 /* adjust vdd_max only in normal temperature zone */
3183 if (chip->is_bat_cool || chip->is_bat_warm) {
3184 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3185 chip->is_bat_cool, chip->is_bat_warm);
3186 return;
3187 }
3188
3189 reg_loop = pm_chg_get_regulation_loop(chip);
3190 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3191 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3192 reg_loop);
3193 return;
3194 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003195 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3196 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3197
3198 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3199
3200 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3201 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3202 delta_mv,
3203 programmed_vdd_max,
3204 adj_vdd_max_mv);
3205
3206 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3207 pr_debug("adj vdd_max lower than default max voltage\n");
3208 return;
3209 }
3210
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003211 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3212 * PM8921_CHG_VDDMAX_RES_MV;
3213
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003214 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3215 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003216 pr_debug("adjusting vdd_max_mv to %d to make "
3217 "vbat_batt_termial_uv = %d to %d\n",
3218 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3219 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3220}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003221
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07003222static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3223{
3224 if (chip->is_bat_cool)
3225 pm_chg_vbatdet_set(the_chip,
3226 the_chip->cool_bat_voltage
3227 - the_chip->resume_voltage_delta);
3228 else if (chip->is_bat_warm)
3229 pm_chg_vbatdet_set(the_chip,
3230 the_chip->warm_bat_voltage
3231 - the_chip->resume_voltage_delta);
3232 else
3233 pm_chg_vbatdet_set(the_chip,
3234 the_chip->max_voltage_mv
3235 - the_chip->resume_voltage_delta);
3236}
3237
Abhijeet Dharmapurikar16adb082012-11-07 10:36:50 -08003238static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3239{
3240 unsigned int chg_current = chip->max_bat_chg_current;
3241
3242 if (chip->is_bat_cool)
3243 chg_current = min(chg_current, chip->cool_bat_chg_current);
3244
3245 if (chip->is_bat_warm)
3246 chg_current = min(chg_current, chip->warm_bat_chg_current);
3247
3248 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3249 chg_current = min(chg_current,
3250 chip->thermal_mitigation[thermal_mitigation]);
3251
3252 pm_chg_ibatmax_set(the_chip, chg_current);
3253}
3254
3255#define TEMP_HYSTERISIS_DECIDEGC 20
3256static void battery_cool(bool enter)
3257{
3258 pr_debug("enter = %d\n", enter);
3259 if (enter == the_chip->is_bat_cool)
3260 return;
3261 the_chip->is_bat_cool = enter;
3262 if (enter)
3263 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3264 else
3265 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3266 set_appropriate_battery_current(the_chip);
3267 set_appropriate_vbatdet(the_chip);
3268}
3269
3270static void battery_warm(bool enter)
3271{
3272 pr_debug("enter = %d\n", enter);
3273 if (enter == the_chip->is_bat_warm)
3274 return;
3275 the_chip->is_bat_warm = enter;
3276 if (enter)
3277 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3278 else
3279 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3280
3281 set_appropriate_battery_current(the_chip);
3282 set_appropriate_vbatdet(the_chip);
3283}
3284
3285static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3286{
3287 int temp = 0;
3288
3289 temp = get_prop_batt_temp(chip);
3290 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3291 temp, chip->warm_temp_dc,
3292 chip->cool_temp_dc);
3293
3294 if (chip->warm_temp_dc != INT_MIN) {
3295 if (chip->is_bat_warm
3296 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3297 battery_warm(false);
3298 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3299 battery_warm(true);
3300 }
3301
3302 if (chip->cool_temp_dc != INT_MIN) {
3303 if (chip->is_bat_cool
3304 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3305 battery_cool(false);
3306 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3307 battery_cool(true);
3308 }
3309}
3310
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003311enum {
3312 CHG_IN_PROGRESS,
3313 CHG_NOT_IN_PROGRESS,
3314 CHG_FINISHED,
3315};
3316
3317#define VBAT_TOLERANCE_MV 70
3318#define CHG_DISABLE_MSLEEP 100
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003319static int is_charging_finished(struct pm8921_chg_chip *chip,
3320 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003321{
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003322 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003323 int regulation_loop, fast_chg, vcp;
3324 int rc;
3325 static int last_vbat_programmed = -EINVAL;
3326
3327 if (!is_ext_charging(chip)) {
3328 /* return if the battery is not being fastcharged */
3329 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3330 pr_debug("fast_chg = %d\n", fast_chg);
3331 if (fast_chg == 0)
3332 return CHG_NOT_IN_PROGRESS;
3333
3334 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3335 pr_debug("vcp = %d\n", vcp);
3336 if (vcp == 1)
3337 return CHG_IN_PROGRESS;
3338
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003339 /* reset count if battery is hot/cold */
3340 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3341 pr_debug("batt_temp_ok = %d\n", rc);
3342 if (rc == 0)
3343 return CHG_IN_PROGRESS;
3344
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003345 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3346 if (rc) {
3347 pr_err("couldnt read vddmax rc = %d\n", rc);
3348 return CHG_IN_PROGRESS;
3349 }
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003350 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3351 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003352
3353 if (last_vbat_programmed == -EINVAL)
3354 last_vbat_programmed = vbat_programmed;
3355 if (last_vbat_programmed != vbat_programmed) {
3356 /* vddmax changed, reset and check again */
3357 pr_debug("vddmax = %d last_vdd_max=%d\n",
3358 vbat_programmed, last_vbat_programmed);
3359 last_vbat_programmed = vbat_programmed;
3360 return CHG_IN_PROGRESS;
3361 }
3362
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003363 if (chip->is_bat_cool)
3364 vbat_intended = chip->cool_bat_voltage;
3365 else if (chip->is_bat_warm)
3366 vbat_intended = chip->warm_bat_voltage;
3367 else
3368 vbat_intended = chip->max_voltage_mv;
3369
3370 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3371 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3372 vbat_batt_terminal_uv,
3373 vbat_intended);
3374 return CHG_IN_PROGRESS;
3375 }
3376
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003377 regulation_loop = pm_chg_get_regulation_loop(chip);
3378 if (regulation_loop < 0) {
3379 pr_err("couldnt read the regulation loop err=%d\n",
3380 regulation_loop);
3381 return CHG_IN_PROGRESS;
3382 }
3383 pr_debug("regulation_loop=%d\n", regulation_loop);
3384
3385 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3386 return CHG_IN_PROGRESS;
3387 } /* !is_ext_charging */
3388
3389 /* reset count if battery chg current is more than iterm */
3390 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3391 if (rc) {
3392 pr_err("couldnt read iterm rc = %d\n", rc);
3393 return CHG_IN_PROGRESS;
3394 }
3395
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003396 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3397 iterm_programmed, ichg_meas_ma);
3398 /*
3399 * ichg_meas_ma < 0 means battery is drawing current
3400 * ichg_meas_ma > 0 means battery is providing current
3401 */
3402 if (ichg_meas_ma > 0)
3403 return CHG_IN_PROGRESS;
3404
3405 if (ichg_meas_ma * -1 > iterm_programmed)
3406 return CHG_IN_PROGRESS;
3407
3408 return CHG_FINISHED;
3409}
3410
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003411/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003412 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003413 * has happened
3414 *
3415 * If all conditions favouring, if the charge current is
3416 * less than the term current for three consecutive times
3417 * an EOC has happened.
3418 * The wakelock is released if there is no need to reshedule
3419 * - this happens when the battery is removed or EOC has
3420 * happened
3421 */
3422#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003423static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003424{
3425 struct delayed_work *dwork = to_delayed_work(work);
3426 struct pm8921_chg_chip *chip = container_of(dwork,
3427 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003428 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003429 int end;
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003430 int vbat_meas_uv, vbat_meas_mv;
3431 int ichg_meas_ua, ichg_meas_ma;
3432 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003433
3434 pm_chg_failed_clear(chip, 1);
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003435
3436 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3437 &ichg_meas_ua, &vbat_meas_uv);
3438 vbat_meas_mv = vbat_meas_uv / 1000;
3439 /* rconn_mohm is in milliOhms */
3440 ichg_meas_ma = ichg_meas_ua / 1000;
3441 vbat_batt_terminal_uv = vbat_meas_uv
3442 + ichg_meas_ma
3443 * the_chip->rconn_mohm;
3444
3445 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003446
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003447 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003448 count = 0;
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07003449 goto eoc_worker_stop;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003450 }
3451
David Keitel8b079fb2012-06-28 19:14:30 -07003452 /* If the disable hw clock switching
3453 * flag was set it can now be unset. Also, re-enable
3454 * the battery alarm to set the flag again when needed
3455 */
3456 if (chip->disable_hw_clock_switching) {
3457 /* Unset the hw clock switching flag */
3458 chip->disable_hw_clock_switching = 0;
3459
3460 if (pm8921_charger_enable_batt_alarm(chip))
3461 pr_err("couldn't set up batt alarm!\n");
3462 }
3463
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003464 if (end == CHG_FINISHED) {
3465 count++;
3466 } else {
3467 count = 0;
3468 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003469
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003470 if (count == CONSECUTIVE_COUNT) {
3471 count = 0;
3472 pr_info("End of Charging\n");
3473
3474 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003475
Amir Samuelovd31ef502011-10-26 14:41:36 +02003476 if (is_ext_charging(chip))
3477 chip->ext_charge_done = true;
3478
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003479 if (chip->is_bat_warm || chip->is_bat_cool)
3480 chip->bms_notify.is_battery_full = 0;
3481 else
3482 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003483 /* declare end of charging by invoking chgdone interrupt */
3484 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003485 } else {
Abhijeet Dharmapurikar16adb082012-11-07 10:36:50 -08003486 check_temp_thresholds(chip);
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07003487 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003488 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003489 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003490 round_jiffies_relative(msecs_to_jiffies
3491 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07003492 return;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003493 }
Abhijeet Dharmapurikar035a0582012-10-26 16:54:12 -07003494
3495eoc_worker_stop:
3496 wake_unlock(&chip->eoc_wake_lock);
3497 /* set the vbatdet back, in case it was changed to trigger charging */
3498 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003499}
3500
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003501/**
3502 * set_disable_status_param -
3503 *
3504 * Internal function to disable battery charging and also disable drawing
3505 * any current from the source. The device is forced to run on a battery
3506 * after this.
3507 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003508static int set_disable_status_param(const char *val, struct kernel_param *kp)
3509{
3510 int ret;
3511 struct pm8921_chg_chip *chip = the_chip;
3512
3513 ret = param_set_int(val, kp);
3514 if (ret) {
3515 pr_err("error setting value %d\n", ret);
3516 return ret;
3517 }
3518 pr_info("factory set disable param to %d\n", charging_disabled);
3519 if (chip) {
3520 pm_chg_auto_enable(chip, !charging_disabled);
3521 pm_chg_charge_dis(chip, charging_disabled);
3522 }
3523 return 0;
3524}
3525module_param_call(disabled, set_disable_status_param, param_get_uint,
3526 &charging_disabled, 0644);
3527
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003528static int rconn_mohm;
3529static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3530{
3531 int ret;
3532 struct pm8921_chg_chip *chip = the_chip;
3533
3534 ret = param_set_int(val, kp);
3535 if (ret) {
3536 pr_err("error setting value %d\n", ret);
3537 return ret;
3538 }
3539 if (chip)
3540 chip->rconn_mohm = rconn_mohm;
3541 return 0;
3542}
3543module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3544 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003545/**
3546 * set_thermal_mitigation_level -
3547 *
3548 * Internal function to control battery charging current to reduce
3549 * temperature
3550 */
3551static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3552{
3553 int ret;
3554 struct pm8921_chg_chip *chip = the_chip;
3555
3556 ret = param_set_int(val, kp);
3557 if (ret) {
3558 pr_err("error setting value %d\n", ret);
3559 return ret;
3560 }
3561
3562 if (!chip) {
3563 pr_err("called before init\n");
3564 return -EINVAL;
3565 }
3566
3567 if (!chip->thermal_mitigation) {
3568 pr_err("no thermal mitigation\n");
3569 return -EINVAL;
3570 }
3571
3572 if (thermal_mitigation < 0
3573 || thermal_mitigation >= chip->thermal_levels) {
3574 pr_err("out of bound level selected\n");
3575 return -EINVAL;
3576 }
3577
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003578 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003579 return ret;
3580}
3581module_param_call(thermal_mitigation, set_therm_mitigation_level,
3582 param_get_uint,
3583 &thermal_mitigation, 0644);
3584
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003585static int set_usb_max_current(const char *val, struct kernel_param *kp)
3586{
3587 int ret, mA;
3588 struct pm8921_chg_chip *chip = the_chip;
3589
3590 ret = param_set_int(val, kp);
3591 if (ret) {
3592 pr_err("error setting value %d\n", ret);
3593 return ret;
3594 }
3595 if (chip) {
3596 pr_warn("setting current max to %d\n", usb_max_current);
3597 pm_chg_iusbmax_get(chip, &mA);
3598 if (mA > usb_max_current)
3599 pm8921_charger_vbus_draw(usb_max_current);
3600 return 0;
3601 }
3602 return -EINVAL;
3603}
David Keitelacf57c82012-03-07 18:48:50 -08003604module_param_call(usb_max_current, set_usb_max_current,
3605 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607static void free_irqs(struct pm8921_chg_chip *chip)
3608{
3609 int i;
3610
3611 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3612 if (chip->pmic_chg_irq[i]) {
3613 free_irq(chip->pmic_chg_irq[i], chip);
3614 chip->pmic_chg_irq[i] = 0;
3615 }
3616}
3617
David Keitel88e1b572012-01-11 11:57:14 -08003618/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003619static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3620{
3621 unsigned long flags;
3622 int fsm_state;
Abhijeet Dharmapurikar7f1d97f2012-09-17 16:59:36 -07003623 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003624
3625 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3626 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3627
3628 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar8c0c8442012-09-17 16:54:07 -07003629 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003630 schedule_delayed_work(&chip->unplug_check_work,
3631 round_jiffies_relative(msecs_to_jiffies
3632 (UNPLUG_CHECK_WAIT_PERIOD_MS)));
David Keitel8c5201a2012-02-24 16:08:54 -08003633 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003634 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635
3636 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3637 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3638 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003639 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003640 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3641 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003642 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003643 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3644 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
David Keitel52fda532011-11-10 10:43:44 -08003645 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003646
3647 spin_lock_irqsave(&vbus_lock, flags);
3648 if (usb_chg_current) {
3649 /* reissue a vbus draw call */
3650 __pm8921_charger_vbus_draw(usb_chg_current);
3651 }
3652 spin_unlock_irqrestore(&vbus_lock, flags);
Abhijeet Dharmapurikar7f1d97f2012-09-17 16:59:36 -07003653 /*
3654 * The bootloader could have started charging, a fastchg interrupt
3655 * might not happen. Check the real time status and if it is fast
3656 * charging invoke the handler so that the eoc worker could be
3657 * started
3658 */
3659 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3660 if (is_fast_chg)
3661 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662
3663 fsm_state = pm_chg_get_fsm_state(chip);
3664 if (is_battery_charging(fsm_state)) {
3665 chip->bms_notify.is_charging = 1;
3666 pm8921_bms_charging_began();
3667 }
3668
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003669 check_battery_valid(chip);
3670
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003671 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3672 chip->usb_present,
3673 chip->dc_present,
3674 get_prop_batt_present(chip),
3675 fsm_state);
David Keitel1e3a82f2012-06-26 16:27:15 -07003676
3677 /* Determine which USB trim column to use */
3678 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3679 chip->usb_trim_table = usb_trim_8917_table;
3680 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3681 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682}
3683
3684struct pm_chg_irq_init_data {
3685 unsigned int irq_id;
3686 char *name;
3687 unsigned long flags;
3688 irqreturn_t (*handler)(int, void *);
3689};
3690
3691#define CHG_IRQ(_id, _flags, _handler) \
3692{ \
3693 .irq_id = _id, \
3694 .name = #_id, \
3695 .flags = _flags, \
3696 .handler = _handler, \
3697}
3698struct pm_chg_irq_init_data chg_irq_data[] = {
3699 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3700 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3702 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003703 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3704 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003705 CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
3706 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3707 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3708 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3709 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3710 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3711 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3712 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3713 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003714 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3715 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003716 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3717 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3718 batt_removed_irq_handler),
3719 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3720 batttemp_hot_irq_handler),
3721 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3722 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3723 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003724 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3725 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003726 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3727 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3729 coarse_det_low_irq_handler),
3730 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3731 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3732 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3733 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3734 batfet_irq_handler),
3735 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3736 dcin_valid_irq_handler),
3737 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3738 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003739 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003740};
3741
3742static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3743 struct platform_device *pdev)
3744{
3745 struct resource *res;
3746 int ret, i;
3747
3748 ret = 0;
3749 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3750
3751 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3752 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3753 chg_irq_data[i].name);
3754 if (res == NULL) {
3755 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3756 goto err_out;
3757 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003758 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759 ret = request_irq(res->start, chg_irq_data[i].handler,
3760 chg_irq_data[i].flags,
3761 chg_irq_data[i].name, chip);
3762 if (ret < 0) {
3763 pr_err("couldn't request %d (%s) %d\n", res->start,
3764 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003765 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003766 goto err_out;
3767 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3769 }
3770 return 0;
3771
3772err_out:
3773 free_irqs(chip);
3774 return -EINVAL;
3775}
3776
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08003777static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3778{
3779 int err;
3780 u8 temp;
3781
3782 temp = 0xD1;
3783 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3784 if (err) {
3785 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3786 return;
3787 }
3788
3789 temp = 0xD3;
3790 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3791 if (err) {
3792 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3793 return;
3794 }
3795
3796 temp = 0xD1;
3797 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3798 if (err) {
3799 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3800 return;
3801 }
3802
3803 temp = 0xD5;
3804 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3805 if (err) {
3806 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3807 return;
3808 }
3809
3810 udelay(183);
3811
3812 temp = 0xD1;
3813 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3814 if (err) {
3815 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3816 return;
3817 }
3818
3819 temp = 0xD0;
3820 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3821 if (err) {
3822 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3823 return;
3824 }
3825 udelay(32);
3826
3827 temp = 0xD1;
3828 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3829 if (err) {
3830 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3831 return;
3832 }
3833
3834 temp = 0xD3;
3835 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3836 if (err) {
3837 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3838 return;
3839 }
3840}
3841
3842static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3843{
3844 int err;
3845 u8 temp;
3846
3847 temp = 0xD1;
3848 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3849 if (err) {
3850 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3851 return;
3852 }
3853
3854 temp = 0xD0;
3855 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
3856 if (err) {
3857 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3858 return;
3859 }
3860}
3861
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003862#define VREF_BATT_THERM_FORCE_ON BIT(7)
3863static void detect_battery_removal(struct pm8921_chg_chip *chip)
3864{
3865 u8 temp;
3866
3867 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3868 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3869
3870 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3871 /*
3872 * batt therm force on bit is battery backed and is default 0
3873 * The charger sets this bit at init time. If this bit is found
3874 * 0 that means the battery was removed. Tell the bms about it
3875 */
3876 pm8921_bms_invalidate_shutdown_soc();
3877}
3878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879#define ENUM_TIMER_STOP_BIT BIT(1)
3880#define BOOT_DONE_BIT BIT(6)
David Keitelb157ff72012-06-14 11:22:30 -07003881#define BOOT_TIMER_EN_BIT BIT(1)
3882#define BOOT_DONE_MASK (BOOT_DONE_BIT | BOOT_TIMER_EN_BIT)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883#define CHG_BATFET_ON_BIT BIT(3)
3884#define CHG_VCP_EN BIT(0)
3885#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3886#define SAFE_CURRENT_MA 1500
David Keitel913c55e2012-10-01 11:35:33 -07003887#define PM_SUB_REV 0x001
Abhijeet Dharmapurikar77b1f6b2012-10-26 11:01:27 -07003888#define MIN_CHARGE_CURRENT_MA 350
3889#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3891{
3892 int rc;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003893 int vdd_safe;
David Keitel913c55e2012-10-01 11:35:33 -07003894 u8 subrev;
Abhijeet Dharmapurikar77b1f6b2012-10-26 11:01:27 -07003895 int fcc_uah;
3896 int safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003897
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07003898 /* forcing 19p2mhz before accessing any charger registers */
3899 pm8921_chg_force_19p2mhz_clk(chip);
3900
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003901 detect_battery_removal(chip);
3902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
David Keitelb157ff72012-06-14 11:22:30 -07003904 BOOT_DONE_MASK, BOOT_DONE_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003905 if (rc) {
3906 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
3907 return rc;
3908 }
3909
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003910 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
3911
3912 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
3913 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
3914
3915 rc = pm_chg_vddsafe_set(chip, vdd_safe);
3916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 if (rc) {
3918 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003919 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003920 return rc;
3921 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07003922 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003923 chip->max_voltage_mv
3924 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003925 if (rc) {
3926 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003927 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003928 return rc;
3929 }
3930
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003931 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 if (rc) {
3933 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08003934 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 return rc;
3936 }
Abhijeet Dharmapurikara8f35422012-10-19 10:50:36 -07003937
3938 if (chip->safe_current_ma == 0)
3939 chip->safe_current_ma = SAFE_CURRENT_MA;
3940
3941 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003942 if (rc) {
3943 pr_err("Failed to set max voltage to %d rc=%d\n",
3944 SAFE_CURRENT_MA, rc);
3945 return rc;
3946 }
3947
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003948 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949 if (rc) {
3950 pr_err("Failed to set max current to 400 rc=%d\n", rc);
3951 return rc;
3952 }
3953
3954 rc = pm_chg_iterm_set(chip, chip->term_current);
3955 if (rc) {
3956 pr_err("Failed to set term current to %d rc=%d\n",
3957 chip->term_current, rc);
3958 return rc;
3959 }
3960
3961 /* Disable the ENUM TIMER */
3962 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
3963 ENUM_TIMER_STOP_BIT);
3964 if (rc) {
3965 pr_err("Failed to set enum timer stop rc=%d\n", rc);
3966 return rc;
3967 }
3968
Abhijeet Dharmapurikar77b1f6b2012-10-26 11:01:27 -07003969 fcc_uah = pm8921_bms_get_fcc();
3970 if (fcc_uah > 0) {
3971 safety_time = div_s64((s64)fcc_uah * 60,
3972 1000 * MIN_CHARGE_CURRENT_MA);
3973 /* add 20 minutes of buffer time */
3974 safety_time += 20;
3975 }
3976
3977 rc = pm_chg_tchg_max_set(chip, safety_time);
3978 if (rc) {
3979 pr_err("Failed to set max time to %d minutes rc=%d\n",
3980 safety_time, rc);
3981 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003982 }
3983
3984 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07003985 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003986 if (rc) {
3987 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar77b1f6b2012-10-26 11:01:27 -07003988 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003989 return rc;
3990 }
3991 }
3992
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07003993 if (chip->vin_min != 0) {
3994 rc = pm_chg_vinmin_set(chip, chip->vin_min);
3995 if (rc) {
3996 pr_err("Failed to set vin min to %d mV rc=%d\n",
3997 chip->vin_min, rc);
3998 return rc;
3999 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004000 } else {
4001 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004002 }
4003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 rc = pm_chg_disable_wd(chip);
4005 if (rc) {
4006 pr_err("Failed to disable wd rc=%d\n", rc);
4007 return rc;
4008 }
4009
4010 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4011 CHG_BAT_TEMP_DIS_BIT, 0);
4012 if (rc) {
4013 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4014 return rc;
4015 }
4016 /* switch to a 3.2Mhz for the buck */
David Keitel3567bec2012-06-26 16:35:53 -07004017 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4018 rc = pm8xxx_writeb(chip->dev->parent,
4019 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4020 else
4021 rc = pm8xxx_writeb(chip->dev->parent,
4022 CHG_BUCK_CLOCK_CTRL, 0x15);
4023
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004024 if (rc) {
4025 pr_err("Failed to switch buck clk rc=%d\n", rc);
4026 return rc;
4027 }
4028
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004029 if (chip->trkl_voltage != 0) {
4030 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4031 if (rc) {
4032 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4033 chip->trkl_voltage, rc);
4034 return rc;
4035 }
4036 }
4037
4038 if (chip->weak_voltage != 0) {
4039 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4040 if (rc) {
4041 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4042 chip->weak_voltage, rc);
4043 return rc;
4044 }
4045 }
4046
4047 if (chip->trkl_current != 0) {
4048 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4049 if (rc) {
4050 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4051 chip->trkl_voltage, rc);
4052 return rc;
4053 }
4054 }
4055
4056 if (chip->weak_current != 0) {
4057 rc = pm_chg_iweak_set(chip, chip->weak_current);
4058 if (rc) {
4059 pr_err("Failed to set weak current to %dmA rc=%d\n",
4060 chip->weak_current, rc);
4061 return rc;
4062 }
4063 }
4064
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004065 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4066 if (rc) {
4067 pr_err("Failed to set cold config %d rc=%d\n",
4068 chip->cold_thr, rc);
4069 }
4070
4071 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4072 if (rc) {
4073 pr_err("Failed to set hot config %d rc=%d\n",
4074 chip->hot_thr, rc);
4075 }
4076
Jay Chokshid674a512012-03-15 14:06:04 -07004077 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4078 if (rc) {
4079 pr_err("Failed to set charger LED src config %d rc=%d\n",
4080 chip->led_src_config, rc);
4081 }
4082
David Keitelb51995e2011-11-18 17:03:31 -08004083 /* Workarounds for die 3.0 */
David Keitel0a6ff482012-08-10 17:14:50 -07004084 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
David Keitel913c55e2012-10-01 11:35:33 -07004085 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4086 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4087 if (rc) {
4088 pr_err("read failed: addr=%03X, rc=%d\n",
4089 PM_SUB_REV, rc);
4090 return rc;
4091 }
4092 /* Check if die 3.0.1 is present */
4093 if (subrev == 0x1)
4094 pm8xxx_writeb(chip->dev->parent,
4095 CHG_BUCK_CTRL_TEST3, 0xA4);
4096 else
4097 pm8xxx_writeb(chip->dev->parent,
4098 CHG_BUCK_CTRL_TEST3, 0xAC);
4099 }
David Keitelb51995e2011-11-18 17:03:31 -08004100
David Keitel38bdd4f2012-04-19 15:39:13 -07004101 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel0789fc62012-06-07 17:43:27 -07004102 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
David Keitel38bdd4f2012-04-19 15:39:13 -07004103 chip->iusb_fine_res = true;
David Keitel0789fc62012-06-07 17:43:27 -07004104 if (chip->uvd_voltage_mv)
4105 rc = pm_chg_uvd_threshold_set(chip,
4106 chip->uvd_voltage_mv);
4107 if (rc) {
4108 pr_err("Failed to set UVD threshold %drc=%d\n",
4109 chip->uvd_voltage_mv, rc);
4110 return rc;
4111 }
4112 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004113
David Keitelb51995e2011-11-18 17:03:31 -08004114 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD9);
4115
David Keitela3c0d822011-11-03 14:18:52 -07004116 /* Disable EOC FSM processing */
4117 pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
4118
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004119 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4120 VREF_BATT_THERM_FORCE_ON);
4121 if (rc)
4122 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4123
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004124 rc = pm_chg_charge_dis(chip, charging_disabled);
4125 if (rc) {
4126 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4127 return rc;
4128 }
4129
4130 rc = pm_chg_auto_enable(chip, !charging_disabled);
4131 if (rc) {
4132 pr_err("Failed to enable charging rc=%d\n", rc);
4133 return rc;
4134 }
4135
4136 return 0;
4137}
4138
4139static int get_rt_status(void *data, u64 * val)
4140{
4141 int i = (int)data;
4142 int ret;
4143
4144 /* global irq number is passed in via data */
4145 ret = pm_chg_get_rt_status(the_chip, i);
4146 *val = ret;
4147 return 0;
4148}
4149DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4150
4151static int get_fsm_status(void *data, u64 * val)
4152{
4153 u8 temp;
4154
4155 temp = pm_chg_get_fsm_state(the_chip);
4156 *val = temp;
4157 return 0;
4158}
4159DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4160
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004161static int get_reg_loop(void *data, u64 * val)
4162{
4163 u8 temp;
4164
4165 if (!the_chip) {
4166 pr_err("%s called before init\n", __func__);
4167 return -EINVAL;
4168 }
4169 temp = pm_chg_get_regulation_loop(the_chip);
4170 *val = temp;
4171 return 0;
4172}
4173DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175static int get_reg(void *data, u64 * val)
4176{
4177 int addr = (int)data;
4178 int ret;
4179 u8 temp;
4180
4181 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4182 if (ret) {
4183 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4184 addr, temp, ret);
4185 return -EAGAIN;
4186 }
4187 *val = temp;
4188 return 0;
4189}
4190
4191static int set_reg(void *data, u64 val)
4192{
4193 int addr = (int)data;
4194 int ret;
4195 u8 temp;
4196
4197 temp = (u8) val;
4198 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
4199 if (ret) {
4200 pr_err("pm8xxx_writeb to %x value =%d errored = %d\n",
4201 addr, temp, ret);
4202 return -EAGAIN;
4203 }
4204 return 0;
4205}
4206DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4207
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -07004208static int reg_loop;
4209#define MAX_REG_LOOP_CHAR 10
4210static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4211{
4212 u8 temp;
4213
4214 if (!the_chip) {
4215 pr_err("called before init\n");
4216 return -EINVAL;
4217 }
4218 temp = pm_chg_get_regulation_loop(the_chip);
4219 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4220}
4221module_param_call(reg_loop, NULL, get_reg_loop_param,
4222 &reg_loop, 0644);
4223
4224static int max_chg_ma;
4225#define MAX_MA_CHAR 10
4226static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4227{
4228 if (!the_chip) {
4229 pr_err("called before init\n");
4230 return -EINVAL;
4231 }
4232 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4233}
4234module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4235 &max_chg_ma, 0644);
4236static int ibatmax_ma;
4237static int set_ibat_max(const char *val, struct kernel_param *kp)
4238{
4239 int rc;
4240
4241 if (!the_chip) {
4242 pr_err("called before init\n");
4243 return -EINVAL;
4244 }
4245
4246 rc = param_set_int(val, kp);
4247 if (rc) {
4248 pr_err("error setting value %d\n", rc);
4249 return rc;
4250 }
4251
4252 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4253 <= the_chip->ibatmax_max_adj_ma) {
4254 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4255 if (rc) {
4256 pr_err("Failed to set ibatmax rc = %d\n", rc);
4257 return rc;
4258 }
4259 }
4260
4261 return 0;
4262}
4263static int get_ibat_max(char *buf, struct kernel_param *kp)
4264{
4265 int ibat_ma;
4266 int rc;
4267
4268 if (!the_chip) {
4269 pr_err("called before init\n");
4270 return -EINVAL;
4271 }
4272
4273 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4274 if (rc) {
4275 pr_err("ibatmax_get error = %d\n", rc);
4276 return rc;
4277 }
4278
4279 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4280}
4281module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4282 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004283enum {
4284 BAT_WARM_ZONE,
4285 BAT_COOL_ZONE,
4286};
4287static int get_warm_cool(void *data, u64 * val)
4288{
4289 if (!the_chip) {
4290 pr_err("%s called before init\n", __func__);
4291 return -EINVAL;
4292 }
4293 if ((int)data == BAT_WARM_ZONE)
4294 *val = the_chip->is_bat_warm;
4295 if ((int)data == BAT_COOL_ZONE)
4296 *val = the_chip->is_bat_cool;
4297 return 0;
4298}
4299DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4302{
4303 int i;
4304
4305 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4306
4307 if (IS_ERR(chip->dent)) {
4308 pr_err("pmic charger couldnt create debugfs dir\n");
4309 return;
4310 }
4311
4312 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4313 (void *)CHG_CNTRL, &reg_fops);
4314 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4315 (void *)CHG_CNTRL_2, &reg_fops);
4316 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4317 (void *)CHG_CNTRL_3, &reg_fops);
4318 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4319 (void *)PBL_ACCESS1, &reg_fops);
4320 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4321 (void *)PBL_ACCESS2, &reg_fops);
4322 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4323 (void *)SYS_CONFIG_1, &reg_fops);
4324 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4325 (void *)SYS_CONFIG_2, &reg_fops);
4326 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4327 (void *)CHG_VDD_MAX, &reg_fops);
4328 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4329 (void *)CHG_VDD_SAFE, &reg_fops);
4330 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4331 (void *)CHG_VBAT_DET, &reg_fops);
4332 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4333 (void *)CHG_IBAT_MAX, &reg_fops);
4334 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4335 (void *)CHG_IBAT_SAFE, &reg_fops);
4336 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4337 (void *)CHG_VIN_MIN, &reg_fops);
4338 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4339 (void *)CHG_VTRICKLE, &reg_fops);
4340 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4341 (void *)CHG_ITRICKLE, &reg_fops);
4342 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4343 (void *)CHG_ITERM, &reg_fops);
4344 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4345 (void *)CHG_TCHG_MAX, &reg_fops);
4346 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4347 (void *)CHG_TWDOG, &reg_fops);
4348 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4349 (void *)CHG_TEMP_THRESH, &reg_fops);
4350 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4351 (void *)CHG_COMP_OVR, &reg_fops);
4352 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4353 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4354 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4355 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4356 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4357 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4358 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4359 (void *)CHG_TEST, &reg_fops);
4360
4361 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4362 &fsm_fops);
4363
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004364 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4365 &reg_loop_fops);
4366
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004367 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4368 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4369 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4370 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4373 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4374 debugfs_create_file(chg_irq_data[i].name, 0444,
4375 chip->dent,
4376 (void *)chg_irq_data[i].irq_id,
4377 &rt_fops);
4378 }
4379}
4380
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004381static int pm8921_charger_suspend_noirq(struct device *dev)
4382{
4383 int rc;
4384 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4385
4386 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4387 if (rc)
4388 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
David Keitel8b079fb2012-06-28 19:14:30 -07004389 if (!(chip->disable_hw_clock_switching))
4390 pm8921_chg_set_hw_clk_switching(chip);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004391 return 0;
4392}
4393
4394static int pm8921_charger_resume_noirq(struct device *dev)
4395{
4396 int rc;
4397 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4398
4399 pm8921_chg_force_19p2mhz_clk(chip);
4400
4401 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4402 VREF_BATT_THERM_FORCE_ON);
4403 if (rc)
4404 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4405 return 0;
4406}
4407
David Keitelf2226022011-12-13 15:55:50 -08004408static int pm8921_charger_resume(struct device *dev)
4409{
David Keitelf2226022011-12-13 15:55:50 -08004410 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4411
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004412 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4413 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4414 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4415 }
David Keitelf2226022011-12-13 15:55:50 -08004416 return 0;
4417}
4418
4419static int pm8921_charger_suspend(struct device *dev)
4420{
4421 int rc;
4422 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4423
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004424 if (is_usb_chg_plugged_in(chip)) {
4425 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4426 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4427 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004428
Abhijeet Dharmapurikar79da3d42012-10-26 15:56:17 -07004429 rc = pm8xxx_batt_alarm_enable(PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
4430 if (rc < 0)
4431 pr_err("Failed to enable lower comparator\n");
David Keitelf2226022011-12-13 15:55:50 -08004432 return 0;
4433}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004434static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4435{
4436 int rc = 0;
4437 struct pm8921_chg_chip *chip;
4438 const struct pm8921_charger_platform_data *pdata
4439 = pdev->dev.platform_data;
4440
4441 if (!pdata) {
4442 pr_err("missing platform data\n");
4443 return -EINVAL;
4444 }
4445
4446 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4447 GFP_KERNEL);
4448 if (!chip) {
4449 pr_err("Cannot allocate pm_chg_chip\n");
4450 return -ENOMEM;
4451 }
4452
4453 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004454 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004455 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004456 chip->max_voltage_mv = pdata->max_voltage;
David Keitel8b079fb2012-06-28 19:14:30 -07004457 chip->alarm_low_mv = pdata->alarm_low_mv;
4458 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004459 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikara8f35422012-10-19 10:50:36 -07004460 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004461 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004462 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Xiaozhe Shi14e8fa12012-10-11 15:49:58 -07004463 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004464 chip->term_current = pdata->term_current;
4465 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004466 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004467 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4468 chip->batt_id_min = pdata->batt_id_min;
4469 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004470 if (pdata->cool_temp != INT_MIN)
4471 chip->cool_temp_dc = pdata->cool_temp * 10;
4472 else
4473 chip->cool_temp_dc = INT_MIN;
4474
4475 if (pdata->warm_temp != INT_MIN)
4476 chip->warm_temp_dc = pdata->warm_temp * 10;
4477 else
4478 chip->warm_temp_dc = INT_MIN;
4479
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004480 chip->temp_check_period = pdata->temp_check_period;
4481 chip->max_bat_chg_current = pdata->max_bat_chg_current;
4482 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4483 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4484 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4485 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004486 chip->trkl_voltage = pdata->trkl_voltage;
4487 chip->weak_voltage = pdata->weak_voltage;
4488 chip->trkl_current = pdata->trkl_current;
4489 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004490 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004491 chip->thermal_mitigation = pdata->thermal_mitigation;
4492 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004493
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004494 chip->cold_thr = pdata->cold_thr;
4495 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004496 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004497 chip->led_src_config = pdata->led_src_config;
David Keitela3cf9432012-08-24 15:11:23 -07004498 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikarbbaef592012-10-10 10:07:51 -07004499 chip->battery_less_hardware = pdata->battery_less_hardware;
4500
4501 if (chip->battery_less_hardware)
4502 charging_disabled = 1;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004503
Abhijeet Dharmapurikar3ee5b072012-10-15 17:47:29 -07004504 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4505 chip->max_bat_chg_current);
4506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507 rc = pm8921_chg_hw_init(chip);
4508 if (rc) {
4509 pr_err("couldn't init hardware rc=%d\n", rc);
4510 goto free_chip;
4511 }
4512
4513 chip->usb_psy.name = "usb",
4514 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4515 chip->usb_psy.supplied_to = pm_power_supplied_to,
4516 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004517 chip->usb_psy.properties = pm_power_props_usb,
4518 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4519 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004520 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004521
David Keitel6ed71a52012-01-30 12:42:18 -08004522 chip->dc_psy.name = "pm8921-dc",
4523 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4524 chip->dc_psy.supplied_to = pm_power_supplied_to,
4525 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004526 chip->dc_psy.properties = pm_power_props_mains,
4527 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4528 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004530 chip->batt_psy.name = "battery",
4531 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4532 chip->batt_psy.properties = msm_batt_power_props,
4533 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4534 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004535 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004536 rc = power_supply_register(chip->dev, &chip->usb_psy);
4537 if (rc < 0) {
4538 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004539 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 }
4541
David Keitel6ed71a52012-01-30 12:42:18 -08004542 rc = power_supply_register(chip->dev, &chip->dc_psy);
4543 if (rc < 0) {
4544 pr_err("power_supply_register usb failed rc = %d\n", rc);
4545 goto unregister_usb;
4546 }
4547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548 rc = power_supply_register(chip->dev, &chip->batt_psy);
4549 if (rc < 0) {
4550 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004551 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004552 }
4553
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004554 platform_set_drvdata(pdev, chip);
4555 the_chip = chip;
4556
4557 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004558 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004559 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4560 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004561 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004562
Abhijeet Dharmapurikarcf5bb9f2012-10-15 13:57:59 -07004563 INIT_WORK(&chip->bms_notify.work, bms_notify);
4564 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4565
4566 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4567
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 rc = request_irqs(chip, pdev);
4569 if (rc) {
4570 pr_err("couldn't register interrupts rc=%d\n", rc);
4571 goto unregister_batt;
4572 }
4573
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004574 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
David Keitel847ec162012-09-04 09:50:36 -07004575 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004576 enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
4577 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004578 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004579
David Keitel8b079fb2012-06-28 19:14:30 -07004580 rc = pm8921_charger_configure_batt_alarm(chip);
4581 if (rc) {
4582 pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
4583 goto free_irq;
4584 }
4585
4586 rc = pm8921_charger_enable_batt_alarm(chip);
4587 if (rc) {
4588 pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
4589 goto free_irq;
4590 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004591 create_debugfs_entries(chip);
4592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593 /* determine what state the charger is in */
4594 determine_initial_state(chip);
4595
Abhijeet Dharmapurikarcf5bb9f2012-10-15 13:57:59 -07004596 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004597 schedule_delayed_work(&chip->update_heartbeat_work,
4598 round_jiffies_relative(msecs_to_jiffies
4599 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004600 return 0;
4601
4602free_irq:
4603 free_irqs(chip);
4604unregister_batt:
4605 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004606unregister_dc:
4607 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004608unregister_usb:
4609 power_supply_unregister(&chip->usb_psy);
4610free_chip:
4611 kfree(chip);
4612 return rc;
4613}
4614
4615static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4616{
4617 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4618
4619 free_irqs(chip);
4620 platform_set_drvdata(pdev, NULL);
4621 the_chip = NULL;
4622 kfree(chip);
4623 return 0;
4624}
David Keitelf2226022011-12-13 15:55:50 -08004625static const struct dev_pm_ops pm8921_pm_ops = {
4626 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004627 .suspend_noirq = pm8921_charger_suspend_noirq,
4628 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004629 .resume = pm8921_charger_resume,
4630};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004631static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004632 .probe = pm8921_charger_probe,
4633 .remove = __devexit_p(pm8921_charger_remove),
4634 .driver = {
4635 .name = PM8921_CHARGER_DEV_NAME,
4636 .owner = THIS_MODULE,
4637 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004638 },
4639};
4640
4641static int __init pm8921_charger_init(void)
4642{
4643 return platform_driver_register(&pm8921_charger_driver);
4644}
4645
4646static void __exit pm8921_charger_exit(void)
4647{
4648 platform_driver_unregister(&pm8921_charger_driver);
4649}
4650
4651late_initcall(pm8921_charger_init);
4652module_exit(pm8921_charger_exit);
4653
4654MODULE_LICENSE("GPL v2");
4655MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4656MODULE_VERSION("1.0");
4657MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);