blob: e4ae96fa122af0d9d3cfbebc1f428134d031028c [file] [log] [blame]
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001/* Copyright (c) 2011-2013, 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>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070024#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/delay.h>
27#include <linux/bitops.h>
28#include <linux/workqueue.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
Ajay Dudani11aeb7b2012-06-28 19:14:30 -070031#include <linux/mfd/pm8xxx/batt-alarm.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070032#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033
34#include <mach/msm_xo.h>
35#include <mach/msm_hsusb.h>
36
37#define CHG_BUCK_CLOCK_CTRL 0x14
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070038#define CHG_BUCK_CLOCK_CTRL_8038 0xD
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#define PBL_ACCESS1 0x04
41#define PBL_ACCESS2 0x05
42#define SYS_CONFIG_1 0x06
43#define SYS_CONFIG_2 0x07
44#define CHG_CNTRL 0x204
45#define CHG_IBAT_MAX 0x205
46#define CHG_TEST 0x206
47#define CHG_BUCK_CTRL_TEST1 0x207
48#define CHG_BUCK_CTRL_TEST2 0x208
49#define CHG_BUCK_CTRL_TEST3 0x209
50#define COMPARATOR_OVERRIDE 0x20A
51#define PSI_TXRX_SAMPLE_DATA_0 0x20B
52#define PSI_TXRX_SAMPLE_DATA_1 0x20C
53#define PSI_TXRX_SAMPLE_DATA_2 0x20D
54#define PSI_TXRX_SAMPLE_DATA_3 0x20E
55#define PSI_CONFIG_STATUS 0x20F
56#define CHG_IBAT_SAFE 0x210
57#define CHG_ITRICKLE 0x211
58#define CHG_CNTRL_2 0x212
59#define CHG_VBAT_DET 0x213
60#define CHG_VTRICKLE 0x214
61#define CHG_ITERM 0x215
62#define CHG_CNTRL_3 0x216
63#define CHG_VIN_MIN 0x217
64#define CHG_TWDOG 0x218
65#define CHG_TTRKL_MAX 0x219
66#define CHG_TEMP_THRESH 0x21A
67#define CHG_TCHG_MAX 0x21B
68#define USB_OVP_CONTROL 0x21C
69#define DC_OVP_CONTROL 0x21D
70#define USB_OVP_TEST 0x21E
71#define DC_OVP_TEST 0x21F
72#define CHG_VDD_MAX 0x220
73#define CHG_VDD_SAFE 0x221
74#define CHG_VBAT_BOOT_THRESH 0x222
75#define USB_OVP_TRIM 0x355
76#define BUCK_CONTROL_TRIM1 0x356
77#define BUCK_CONTROL_TRIM2 0x357
78#define BUCK_CONTROL_TRIM3 0x358
79#define BUCK_CONTROL_TRIM4 0x359
80#define CHG_DEFAULTS_TRIM 0x35A
81#define CHG_ITRIM 0x35B
82#define CHG_TTRIM 0x35C
83#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070084#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070085#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070087/* check EOC every 10 seconds */
88#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080089/* check for USB unplug every 200 msecs */
90#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070091#define UNPLUG_CHECK_RAMP_MS 25
92#define USB_TRIM_ENTRIES 16
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094enum chg_fsm_state {
95 FSM_STATE_OFF_0 = 0,
96 FSM_STATE_BATFETDET_START_12 = 12,
97 FSM_STATE_BATFETDET_END_16 = 16,
98 FSM_STATE_ON_CHG_HIGHI_1 = 1,
99 FSM_STATE_ATC_2A = 2,
100 FSM_STATE_ATC_2B = 18,
101 FSM_STATE_ON_BAT_3 = 3,
102 FSM_STATE_ATC_FAIL_4 = 4 ,
103 FSM_STATE_DELAY_5 = 5,
104 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
105 FSM_STATE_FAST_CHG_7 = 7,
106 FSM_STATE_TRKL_CHG_8 = 8,
107 FSM_STATE_CHG_FAIL_9 = 9,
108 FSM_STATE_EOC_10 = 10,
109 FSM_STATE_ON_CHG_VREGOK_11 = 11,
110 FSM_STATE_ATC_PAUSE_13 = 13,
111 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
112 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
113 FSM_STATE_START_BOOT = 20,
114 FSM_STATE_FLCB_VREGOK = 21,
115 FSM_STATE_FLCB = 22,
116};
117
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700118struct fsm_state_to_batt_status {
119 enum chg_fsm_state fsm_state;
120 int batt_state;
121};
122
123static struct fsm_state_to_batt_status map[] = {
124 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
125 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
126 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
127 /*
128 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
129 * too hot/cold, charger too hot
130 */
131 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
132 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
134 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
135 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
136 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
137 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
138 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
139 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
140 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
141 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
142 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
143 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
144 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
146 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
147 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
149};
150
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700151enum chg_regulation_loop {
152 VDD_LOOP = BIT(3),
153 BAT_CURRENT_LOOP = BIT(2),
154 INPUT_CURRENT_LOOP = BIT(1),
155 INPUT_VOLTAGE_LOOP = BIT(0),
156 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
157 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160enum pmic_chg_interrupts {
161 USBIN_VALID_IRQ = 0,
162 USBIN_OV_IRQ,
163 BATT_INSERTED_IRQ,
164 VBATDET_LOW_IRQ,
165 USBIN_UV_IRQ,
166 VBAT_OV_IRQ,
167 CHGWDOG_IRQ,
168 VCP_IRQ,
169 ATCDONE_IRQ,
170 ATCFAIL_IRQ,
171 CHGDONE_IRQ,
172 CHGFAIL_IRQ,
173 CHGSTATE_IRQ,
174 LOOP_CHANGE_IRQ,
175 FASTCHG_IRQ,
176 TRKLCHG_IRQ,
177 BATT_REMOVED_IRQ,
178 BATTTEMP_HOT_IRQ,
179 CHGHOT_IRQ,
180 BATTTEMP_COLD_IRQ,
181 CHG_GONE_IRQ,
182 BAT_TEMP_OK_IRQ,
183 COARSE_DET_LOW_IRQ,
184 VDD_LOOP_IRQ,
185 VREG_OV_IRQ,
186 VBATDET_IRQ,
187 BATFET_IRQ,
188 PSI_IRQ,
189 DCIN_VALID_IRQ,
190 DCIN_OV_IRQ,
191 DCIN_UV_IRQ,
192 PM_CHG_MAX_INTS,
193};
194
195struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700196 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 int is_charging;
198 struct work_struct work;
199};
200
201/**
202 * struct pm8921_chg_chip -device information
203 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 * @usb_present: present status of usb
205 * @dc_present: present status of dc
206 * @usb_charger_current: usb current to charge the battery with used when
207 * the usb path is enabled or charging is resumed
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800209 * @max_voltage_mv: the max volts the batt should be charged up to
210 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700211 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700212 * @alarm_low_mv: the battery alarm voltage low
213 * @alarm_high_mv: the battery alarm voltage high
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800214 * @cool_temp_dc: the cool temp threshold in deciCelcius
215 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700216 * @resume_voltage_delta: the voltage delta from vdd max at which the
217 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 * @term_current: The charging based term current
219 *
220 */
221struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700222 struct device *dev;
223 unsigned int usb_present;
224 unsigned int dc_present;
225 unsigned int usb_charger_current;
226 unsigned int max_bat_chg_current;
227 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700228 unsigned int ttrkl_time;
229 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800230 unsigned int max_voltage_mv;
231 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700232 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700233 unsigned int safe_current_ma;
234 unsigned int alarm_low_mv;
235 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800236 int cool_temp_dc;
237 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700238 unsigned int temp_check_period;
239 unsigned int cool_bat_chg_current;
240 unsigned int warm_bat_chg_current;
241 unsigned int cool_bat_voltage;
242 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700243 unsigned int is_bat_cool;
244 unsigned int is_bat_warm;
245 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700246 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 unsigned int term_current;
248 unsigned int vbat_channel;
249 unsigned int batt_temp_channel;
250 unsigned int batt_id_channel;
251 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800252 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800253 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700254 struct power_supply batt_psy;
255 struct dentry *dent;
256 struct bms_notify bms_notify;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700257 int *usb_trim_table;
258 struct regulator *vreg_xoadc;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200259 bool ext_charging;
260 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700261 bool iusb_fine_res;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700262 bool final_kickstart;
263 bool lockup_lpm_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700265 struct work_struct battery_id_valid_work;
266 int64_t batt_id_min;
267 int64_t batt_id_max;
268 int trkl_voltage;
269 int weak_voltage;
270 int trkl_current;
271 int weak_current;
272 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800273 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700274 int thermal_levels;
275 struct delayed_work update_heartbeat_work;
276 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800277 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800278 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700279 struct delayed_work btc_override_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700280 struct wake_lock eoc_wake_lock;
281 enum pm8921_chg_cold_thr cold_thr;
282 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800283 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700284 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700285 bool host_mode;
David Keitelff4f9ce2012-08-24 15:11:23 -0700286 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700287 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700288 int recent_reported_soc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700289 int battery_less_hardware;
290 int ibatmax_max_adj_ma;
291 int btc_override;
292 int btc_override_cold_decidegc;
293 int btc_override_hot_decidegc;
294 int btc_delay_ms;
295 bool btc_panic_if_cant_stop_chg;
296 int stop_chg_upon_expiry;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -0800297 bool disable_aicl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298};
299
David Keitelacf57c82012-03-07 18:48:50 -0800300/* user space parameter to limit usb current */
301static unsigned int usb_max_current;
302/*
303 * usb_target_ma is used for wall charger
304 * adaptive input current limiting only. Use
305 * pm_iusbmax_get() to get current maximum usb current setting.
306 */
307static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700309static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310
311static struct pm8921_chg_chip *the_chip;
312
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700313static DEFINE_SPINLOCK(lpm_lock);
314#define LPM_ENABLE_BIT BIT(2)
315static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
316{
317 int rc;
318 u8 reg;
319
320 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
321 if (rc) {
322 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
323 CHG_CNTRL, rc);
324 return rc;
325 }
326 reg &= ~LPM_ENABLE_BIT;
327 reg |= (enable ? LPM_ENABLE_BIT : 0);
328
329 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
330 if (rc) {
331 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
332 CHG_CNTRL, rc);
333 return rc;
334 }
335
336 return rc;
337}
338
339static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
340{
341 int rc;
342 unsigned long flags = 0;
343
344 /* Disable LPM */
345 if (chip->lockup_lpm_wrkarnd) {
346 spin_lock_irqsave(&lpm_lock, flags);
347
348 /*
349 * This write could have initiated right after a previous write.
350 * Allow time to settle to go in to lpm from the previous write
351 */
352 udelay(200);
353 rc = pm8921_chg_set_lpm(chip, 0);
354 if (rc)
355 goto lpm_err;
356
357 /* Wait to come out of LPM */
358 udelay(200);
359 }
360
361 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
362 if (rc) {
363 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
364 goto lpm_err;
365 }
366
367 /* Enable LPM */
368 if (chip->lockup_lpm_wrkarnd)
369 rc = pm8921_chg_set_lpm(chip, 1);
370
371lpm_err:
372 if (chip->lockup_lpm_wrkarnd)
373 spin_unlock_irqrestore(&lpm_lock, flags);
374
375 return rc;
376}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
379 u8 mask, u8 val)
380{
381 int rc;
382 u8 reg;
383
384 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
385 if (rc) {
386 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
387 return rc;
388 }
389 reg &= ~mask;
390 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700391 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700393 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 return rc;
395 }
396 return 0;
397}
398
David Keitelcf867232012-01-27 18:40:12 -0800399static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
400{
401 return pm8xxx_read_irq_stat(chip->dev->parent,
402 chip->pmic_chg_irq[irq_id]);
403}
404
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700405static int is_chg_on_bat(struct pm8921_chg_chip *chip)
406{
407 return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
408 || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
409}
410
411static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
412 int bypass)
413{
414 int rc;
415
416 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
417 if (rc) {
418 pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
419 }
420}
421
David Keitelcf867232012-01-27 18:40:12 -0800422/* Treat OverVoltage/UnderVoltage as source missing */
423static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
424{
425 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
426}
427
428/* Treat OverVoltage/UnderVoltage as source missing */
429static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
430{
431 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
432}
433
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700434static int is_batfet_closed(struct pm8921_chg_chip *chip)
435{
436 return pm_chg_get_rt_status(chip, BATFET_IRQ);
437}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438#define CAPTURE_FSM_STATE_CMD 0xC2
439#define READ_BANK_7 0x70
440#define READ_BANK_4 0x40
441static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
442{
443 u8 temp;
444 int err, ret = 0;
445
446 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700447 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 if (err) {
449 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
450 return err;
451 }
452
453 temp = READ_BANK_7;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700454 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 if (err) {
456 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
457 return err;
458 }
459
460 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
461 if (err) {
462 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
463 return err;
464 }
465 /* get the lower 4 bits */
466 ret = temp & 0xF;
467
468 temp = READ_BANK_4;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700469 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470 if (err) {
471 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
472 return err;
473 }
474
475 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
476 if (err) {
477 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
478 return err;
479 }
480 /* get the upper 1 bit */
481 ret |= (temp & 0x1) << 4;
482 return ret;
483}
484
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700485#define READ_BANK_6 0x60
486static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
487{
488 u8 temp;
489 int err;
490
491 temp = READ_BANK_6;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700492 err = pm_chg_write(chip, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700493 if (err) {
494 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
495 return err;
496 }
497
498 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
499 if (err) {
500 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
501 return err;
502 }
503
504 /* return the lower 4 bits */
505 return temp & CHG_ALL_LOOPS;
506}
507
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508#define CHG_USB_SUSPEND_BIT BIT(2)
509static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
510{
511 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
512 enable ? CHG_USB_SUSPEND_BIT : 0);
513}
514
515#define CHG_EN_BIT BIT(7)
516static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
517{
518 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
519 enable ? CHG_EN_BIT : 0);
520}
521
David Keitel753ec8d2011-11-02 10:56:37 -0700522#define CHG_FAILED_CLEAR BIT(0)
523#define ATC_FAILED_CLEAR BIT(1)
524static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
525{
526 int rc;
527
528 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
529 clear ? ATC_FAILED_CLEAR : 0);
530 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
531 clear ? CHG_FAILED_CLEAR : 0);
532 return rc;
533}
534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535#define CHG_CHARGE_DIS_BIT BIT(1)
536static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
537{
538 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
539 disable ? CHG_CHARGE_DIS_BIT : 0);
540}
541
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800542static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
543{
544 u8 temp;
545
546 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
547 return temp & CHG_CHARGE_DIS_BIT;
548}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549#define PM8921_CHG_V_MIN_MV 3240
550#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800551#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552#define PM8921_CHG_VDDMAX_MAX 4500
553#define PM8921_CHG_VDDMAX_MIN 3400
554#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800555static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800557 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800558 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800560 if (voltage < PM8921_CHG_VDDMAX_MIN
561 || voltage > PM8921_CHG_VDDMAX_MAX) {
562 pr_err("bad mV=%d asked to set\n", voltage);
563 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564 }
David Keitelcf867232012-01-27 18:40:12 -0800565
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800566 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
567
568 remainder = voltage % 20;
569 if (remainder >= 10) {
570 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
571 }
572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700574 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575}
576
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700577static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
578{
579 u8 temp;
580 int rc;
581
582 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
583 if (rc) {
584 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700585 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700586 return rc;
587 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800588 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
589 + PM8921_CHG_V_MIN_MV;
590 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
591 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700592 return 0;
593}
594
David Keitelcf867232012-01-27 18:40:12 -0800595static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
596{
597 int current_mv, ret, steps, i;
598 bool increase;
599
600 ret = 0;
601
602 if (voltage < PM8921_CHG_VDDMAX_MIN
603 || voltage > PM8921_CHG_VDDMAX_MAX) {
604 pr_err("bad mV=%d asked to set\n", voltage);
605 return -EINVAL;
606 }
607
608 ret = pm_chg_vddmax_get(chip, &current_mv);
609 if (ret) {
610 pr_err("Failed to read vddmax rc=%d\n", ret);
611 return -EINVAL;
612 }
613 if (current_mv == voltage)
614 return 0;
615
616 /* Only change in increments when USB is present */
617 if (is_usb_chg_plugged_in(chip)) {
618 if (current_mv < voltage) {
619 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
620 increase = true;
621 } else {
622 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
623 increase = false;
624 }
625 for (i = 0; i < steps; i++) {
626 if (increase)
627 current_mv += PM8921_CHG_V_STEP_MV;
628 else
629 current_mv -= PM8921_CHG_V_STEP_MV;
630 ret |= __pm_chg_vddmax_set(chip, current_mv);
631 }
632 }
633 ret |= __pm_chg_vddmax_set(chip, voltage);
634 return ret;
635}
636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637#define PM8921_CHG_VDDSAFE_MIN 3400
638#define PM8921_CHG_VDDSAFE_MAX 4500
639static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
640{
641 u8 temp;
642
643 if (voltage < PM8921_CHG_VDDSAFE_MIN
644 || voltage > PM8921_CHG_VDDSAFE_MAX) {
645 pr_err("bad mV=%d asked to set\n", voltage);
646 return -EINVAL;
647 }
648 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
649 pr_debug("voltage=%d setting %02x\n", voltage, temp);
650 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
651}
652
653#define PM8921_CHG_VBATDET_MIN 3240
654#define PM8921_CHG_VBATDET_MAX 5780
655static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
656{
657 u8 temp;
658
659 if (voltage < PM8921_CHG_VBATDET_MIN
660 || voltage > PM8921_CHG_VBATDET_MAX) {
661 pr_err("bad mV=%d asked to set\n", voltage);
662 return -EINVAL;
663 }
664 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
665 pr_debug("voltage=%d setting %02x\n", voltage, temp);
666 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
667}
668
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700669#define PM8921_CHG_VINMIN_MIN_MV 3800
670#define PM8921_CHG_VINMIN_STEP_MV 100
671#define PM8921_CHG_VINMIN_USABLE_MAX 6500
672#define PM8921_CHG_VINMIN_USABLE_MIN 4300
673#define PM8921_CHG_VINMIN_MASK 0x1F
674static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
675{
676 u8 temp;
677
678 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
679 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
680 pr_err("bad mV=%d asked to set\n", voltage);
681 return -EINVAL;
682 }
683 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
684 pr_debug("voltage=%d setting %02x\n", voltage, temp);
685 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
686 temp);
687}
688
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800689static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
690{
691 u8 temp;
692 int rc, voltage_mv;
693
694 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
695 temp &= PM8921_CHG_VINMIN_MASK;
696
697 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
698 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
699
700 return voltage_mv;
701}
702
David Keitel0789fc62012-06-07 17:43:27 -0700703#define PM8917_USB_UVD_MIN_MV 3850
704#define PM8917_USB_UVD_MAX_MV 4350
705#define PM8917_USB_UVD_STEP_MV 100
706#define PM8917_USB_UVD_MASK 0x7
707static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
708{
709 u8 temp;
710
711 if (thresh_mv < PM8917_USB_UVD_MIN_MV
712 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
713 pr_err("bad mV=%d asked to set\n", thresh_mv);
714 return -EINVAL;
715 }
716 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
717 return pm_chg_masked_write(chip, OVP_USB_UVD,
718 PM8917_USB_UVD_MASK, temp);
719}
720
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700722#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723#define PM8921_CHG_I_MIN_MA 225
724#define PM8921_CHG_I_STEP_MA 50
725#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700726static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
727{
728 u8 temp;
729 int rc;
730
731 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
732 if (rc) {
733 pr_err("rc = %d while reading ibat max\n", rc);
734 *ibat_ma = 0;
735 return rc;
736 }
737 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
738 + PM8921_CHG_I_MIN_MA;
739 return 0;
740}
741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
743{
744 u8 temp;
745
746 if (chg_current < PM8921_CHG_IBATMAX_MIN
747 || chg_current > PM8921_CHG_IBATMAX_MAX) {
748 pr_err("bad mA=%d asked to set\n", chg_current);
749 return -EINVAL;
750 }
751 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
752 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
753}
754
755#define PM8921_CHG_IBATSAFE_MIN 225
756#define PM8921_CHG_IBATSAFE_MAX 3375
757static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
758{
759 u8 temp;
760
761 if (chg_current < PM8921_CHG_IBATSAFE_MIN
762 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
763 pr_err("bad mA=%d asked to set\n", chg_current);
764 return -EINVAL;
765 }
766 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
767 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
768 PM8921_CHG_I_MASK, temp);
769}
770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700772#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773#define PM8921_CHG_ITERM_STEP_MA 10
774#define PM8921_CHG_ITERM_MASK 0xF
775static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
776{
777 u8 temp;
778
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700779 if (chg_current < PM8921_CHG_ITERM_MIN_MA
780 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 pr_err("bad mA=%d asked to set\n", chg_current);
782 return -EINVAL;
783 }
784
785 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
786 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700787 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 temp);
789}
790
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700791static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
792{
793 u8 temp;
794 int rc;
795
796 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
797 if (rc) {
798 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700799 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700800 return rc;
801 }
802 temp &= PM8921_CHG_ITERM_MASK;
803 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
804 + PM8921_CHG_ITERM_MIN_MA;
805 return 0;
806}
807
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800808struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700809 int usb_ma;
810 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800811};
812
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700813/* USB Trim tables */
814static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
815 0x0,
816 0x0,
817 -0x9,
818 0x0,
819 -0xD,
820 0x0,
821 -0x10,
822 -0x11,
823 0x0,
824 0x0,
825 -0x25,
826 0x0,
827 -0x28,
828 0x0,
829 -0x32,
830 0x0
831};
832
833static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
834 0x0,
835 0x0,
836 0xA,
837 0xC,
838 0x10,
839 0x10,
840 0x13,
841 0x14,
842 0x13,
843 0x3,
844 0x1A,
845 0x1D,
846 0x1D,
847 0x21,
848 0x24,
849 0x26
850};
851
852/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800853static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700854 {100, 0x0},
855 {200, 0x1},
856 {500, 0x2},
857 {600, 0x3},
858 {700, 0x4},
859 {800, 0x5},
860 {850, 0x6},
861 {900, 0x8},
862 {950, 0x7},
863 {1000, 0x9},
864 {1100, 0xA},
865 {1200, 0xB},
866 {1300, 0xC},
867 {1400, 0xD},
868 {1500, 0xE},
869 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800870};
871
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700872#define REG_SBI_CONFIG 0x04F
873#define PAGE3_ENABLE_MASK 0x6
874#define USB_OVP_TRIM_MASK 0x3F
875#define USB_OVP_TRIM_PM8917_MASK 0x7F
876#define USB_OVP_TRIM_MIN 0x00
877#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
878#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
879#define REG_USB_OVP_TRIM_PM8917 0x2B5
880#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
881static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
882{
883 u8 temp, sbi_config, msb, lsb, mask;
884 s8 trim;
885 int rc = 0;
886 static u8 usb_trim_reg_orig = 0xFF;
887
888 /* No trim data for PM8921 */
889 if (!chip->usb_trim_table)
890 return 0;
891
892 if (usb_trim_reg_orig == 0xFF) {
893 rc = pm8xxx_readb(chip->dev->parent,
894 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
895 if (rc) {
896 pr_err("error = %d reading sbi config reg\n", rc);
897 return rc;
898 }
899
900 rc = pm8xxx_readb(chip->dev->parent,
901 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
902 if (rc) {
903 pr_err("error = %d reading sbi config reg\n", rc);
904 return rc;
905 }
906
907 msb = msb >> 5;
908 lsb = lsb >> 5;
909 usb_trim_reg_orig = msb << 3 | lsb;
910
911 if (pm8xxx_get_version(chip->dev->parent)
912 == PM8XXX_VERSION_8917) {
913 rc = pm8xxx_readb(chip->dev->parent,
914 REG_USB_OVP_TRIM_PM8917, &msb);
915 if (rc) {
916 pr_err("error = %d reading config reg\n", rc);
917 return rc;
918 }
919
920 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
921 usb_trim_reg_orig |= msb << 6;
922 }
923 }
924
925 /* use the original trim value */
926 trim = usb_trim_reg_orig;
927
928 trim += chip->usb_trim_table[index];
929 if (trim < 0)
930 trim = 0;
931
932 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
933 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
934
935 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
936 if (rc) {
937 pr_err("error = %d reading sbi config reg\n", rc);
938 return rc;
939 }
940
941 temp = sbi_config | PAGE3_ENABLE_MASK;
942 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
943 if (rc) {
944 pr_err("error = %d writing sbi config reg\n", rc);
945 return rc;
946 }
947
948 mask = USB_OVP_TRIM_MASK;
949
950 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
951 mask = USB_OVP_TRIM_PM8917_MASK;
952
953 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
954 if (rc) {
955 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
956 return rc;
957 }
958
959 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
960 if (rc) {
961 pr_err("error = %d writing sbi config reg\n", rc);
962 return rc;
963 }
964 return rc;
965}
966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700968#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969#define PM8921_CHG_IUSB_MAX 7
970#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700971#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700972static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700974 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700975 int rc;
976
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700977 reg_val = usb_ma_table[index].value >> 1;
978 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700980 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
981 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 return -EINVAL;
983 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700984 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
985
986 /* IUSB_FINE_RES */
987 if (chip->iusb_fine_res) {
988 /* Clear IUSB_FINE_RES bit to avoid overshoot */
989 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
990 PM8917_IUSB_FINE_RES, 0);
991
992 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
993 PM8921_CHG_IUSB_MASK, temp);
994
995 if (rc) {
996 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
997 return rc;
998 }
999
1000 if (fineres) {
1001 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1002 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001003 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001004 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
1005 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001006 return rc;
1007 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001008 }
1009 } else {
1010 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
1011 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001012 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001013 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001014 return rc;
1015 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001016 }
1017
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001018 rc = pm_chg_usb_trim(chip, index);
1019 if (rc)
1020 pr_err("unable to set usb trim rc = %d\n", rc);
1021
David Keitel38bdd4f2012-04-19 15:39:13 -07001022 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023}
1024
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001025static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
1026{
David Keitel38bdd4f2012-04-19 15:39:13 -07001027 u8 temp, fineres;
1028 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001029
David Keitel38bdd4f2012-04-19 15:39:13 -07001030 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001031 *mA = 0;
1032 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
1033 if (rc) {
1034 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1035 return rc;
1036 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001037
1038 if (chip->iusb_fine_res) {
1039 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1040 if (rc) {
1041 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1042 return rc;
1043 }
1044 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001045 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001046 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1047
1048 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1049 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1050 if (usb_ma_table[i].value == temp)
1051 break;
1052 }
1053
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001054 if (i < 0) {
1055 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1056 i = 0;
1057 }
1058
David Keitel38bdd4f2012-04-19 15:39:13 -07001059 *mA = usb_ma_table[i].usb_ma;
1060
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001061 return rc;
1062}
1063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064#define PM8921_CHG_WD_MASK 0x1F
1065static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1066{
1067 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001068 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1069}
1070
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001071#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001072#define PM8921_CHG_TCHG_MIN 4
1073#define PM8921_CHG_TCHG_MAX 512
1074#define PM8921_CHG_TCHG_STEP 4
1075static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1076{
1077 u8 temp;
1078
1079 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1080 pr_err("bad max minutes =%d asked to set\n", minutes);
1081 return -EINVAL;
1082 }
1083
1084 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1085 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1086 temp);
1087}
1088
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001089#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001090#define PM8921_CHG_TTRKL_MIN 1
1091#define PM8921_CHG_TTRKL_MAX 64
1092static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1093{
1094 u8 temp;
1095
1096 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1097 pr_err("bad max minutes =%d asked to set\n", minutes);
1098 return -EINVAL;
1099 }
1100
1101 temp = minutes - 1;
1102 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1103 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104}
1105
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001106#define PM8921_CHG_VTRKL_MIN_MV 2050
1107#define PM8921_CHG_VTRKL_MAX_MV 2800
1108#define PM8921_CHG_VTRKL_STEP_MV 50
1109#define PM8921_CHG_VTRKL_SHIFT 4
1110#define PM8921_CHG_VTRKL_MASK 0xF0
1111static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1112{
1113 u8 temp;
1114
1115 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1116 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1117 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1118 return -EINVAL;
1119 }
1120
1121 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1122 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1123 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1124 temp);
1125}
1126
1127#define PM8921_CHG_VWEAK_MIN_MV 2100
1128#define PM8921_CHG_VWEAK_MAX_MV 3600
1129#define PM8921_CHG_VWEAK_STEP_MV 100
1130#define PM8921_CHG_VWEAK_MASK 0x0F
1131static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1132{
1133 u8 temp;
1134
1135 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1136 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1137 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1138 return -EINVAL;
1139 }
1140
1141 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1142 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1143 temp);
1144}
1145
1146#define PM8921_CHG_ITRKL_MIN_MA 50
1147#define PM8921_CHG_ITRKL_MAX_MA 200
1148#define PM8921_CHG_ITRKL_MASK 0x0F
1149#define PM8921_CHG_ITRKL_STEP_MA 10
1150static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1151{
1152 u8 temp;
1153
1154 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1155 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1156 pr_err("bad current = %dmA asked to set\n", milliamps);
1157 return -EINVAL;
1158 }
1159
1160 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1161
1162 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1163 temp);
1164}
1165
1166#define PM8921_CHG_IWEAK_MIN_MA 325
1167#define PM8921_CHG_IWEAK_MAX_MA 525
1168#define PM8921_CHG_IWEAK_SHIFT 7
1169#define PM8921_CHG_IWEAK_MASK 0x80
1170static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1171{
1172 u8 temp;
1173
1174 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1175 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1176 pr_err("bad current = %dmA asked to set\n", milliamps);
1177 return -EINVAL;
1178 }
1179
1180 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1181 temp = 0;
1182 else
1183 temp = 1;
1184
1185 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1186 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1187 temp);
1188}
1189
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001190#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1191#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1192static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1193 enum pm8921_chg_cold_thr cold_thr)
1194{
1195 u8 temp;
1196
1197 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1198 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1199 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1200 PM8921_CHG_BATT_TEMP_THR_COLD,
1201 temp);
1202}
1203
1204#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1205#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1206static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1207 enum pm8921_chg_hot_thr hot_thr)
1208{
1209 u8 temp;
1210
1211 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1212 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1213 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1214 PM8921_CHG_BATT_TEMP_THR_HOT,
1215 temp);
1216}
1217
Jay Chokshid674a512012-03-15 14:06:04 -07001218#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1219#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1220static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1221 enum pm8921_chg_led_src_config led_src_config)
1222{
1223 u8 temp;
1224
1225 if (led_src_config < LED_SRC_GND ||
1226 led_src_config > LED_SRC_BYPASS)
1227 return -EINVAL;
1228
1229 if (led_src_config == LED_SRC_BYPASS)
1230 return 0;
1231
1232 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1233
1234 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1235 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1236}
1237
David Keitel8c5201a2012-02-24 16:08:54 -08001238
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001239static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1240{
1241 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001242 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001243
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001244 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001245 if (rc) {
1246 pr_err("error reading batt id channel = %d, rc = %d\n",
1247 chip->vbat_channel, rc);
1248 return rc;
1249 }
1250 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1251 result.measurement);
1252 return result.physical;
1253}
1254
1255static int is_battery_valid(struct pm8921_chg_chip *chip)
1256{
1257 int64_t rc;
1258
1259 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1260 return 1;
1261
1262 rc = read_battery_id(chip);
1263 if (rc < 0) {
1264 pr_err("error reading batt id channel = %d, rc = %lld\n",
1265 chip->vbat_channel, rc);
1266 /* assume battery id is valid when adc error happens */
1267 return 1;
1268 }
1269
1270 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1271 pr_err("batt_id phy =%lld is not valid\n", rc);
1272 return 0;
1273 }
1274 return 1;
1275}
1276
1277static void check_battery_valid(struct pm8921_chg_chip *chip)
1278{
1279 if (is_battery_valid(chip) == 0) {
1280 pr_err("batt_id not valid, disbling charging\n");
1281 pm_chg_auto_enable(chip, 0);
1282 } else {
1283 pm_chg_auto_enable(chip, !charging_disabled);
1284 }
1285}
1286
1287static void battery_id_valid(struct work_struct *work)
1288{
1289 struct pm8921_chg_chip *chip = container_of(work,
1290 struct pm8921_chg_chip, battery_id_valid_work);
1291
1292 check_battery_valid(chip);
1293}
1294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1296{
1297 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1298 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1299 enable_irq(chip->pmic_chg_irq[interrupt]);
1300 }
1301}
1302
1303static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1304{
1305 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1306 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1307 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1308 }
1309}
1310
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001311static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1312{
1313 return test_bit(interrupt, chip->enabled_irqs);
1314}
1315
Amir Samuelovd31ef502011-10-26 14:41:36 +02001316static bool is_ext_charging(struct pm8921_chg_chip *chip)
1317{
David Keitel88e1b572012-01-11 11:57:14 -08001318 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001319
David Keitel88e1b572012-01-11 11:57:14 -08001320 if (!chip->ext_psy)
1321 return false;
1322 if (chip->ext_psy->get_property(chip->ext_psy,
1323 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1324 return false;
1325 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1326 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001327
1328 return false;
1329}
1330
1331static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1332{
David Keitel88e1b572012-01-11 11:57:14 -08001333 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001334
David Keitel88e1b572012-01-11 11:57:14 -08001335 if (!chip->ext_psy)
1336 return false;
1337 if (chip->ext_psy->get_property(chip->ext_psy,
1338 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1339 return false;
1340 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001341 return true;
1342
1343 return false;
1344}
1345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346static int is_battery_charging(int fsm_state)
1347{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001348 if (is_ext_charging(the_chip))
1349 return 1;
1350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 switch (fsm_state) {
1352 case FSM_STATE_ATC_2A:
1353 case FSM_STATE_ATC_2B:
1354 case FSM_STATE_ON_CHG_AND_BAT_6:
1355 case FSM_STATE_FAST_CHG_7:
1356 case FSM_STATE_TRKL_CHG_8:
1357 return 1;
1358 }
1359 return 0;
1360}
1361
1362static void bms_notify(struct work_struct *work)
1363{
1364 struct bms_notify *n = container_of(work, struct bms_notify, work);
1365
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001366 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001368 } else {
1369 pm8921_bms_charging_end(n->is_battery_full);
1370 n->is_battery_full = 0;
1371 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372}
1373
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001374static void bms_notify_check(struct pm8921_chg_chip *chip)
1375{
1376 int fsm_state, new_is_charging;
1377
1378 fsm_state = pm_chg_get_fsm_state(chip);
1379 new_is_charging = is_battery_charging(fsm_state);
1380
1381 if (chip->bms_notify.is_charging ^ new_is_charging) {
1382 chip->bms_notify.is_charging = new_is_charging;
1383 schedule_work(&(chip->bms_notify.work));
1384 }
1385}
1386
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001387static enum power_supply_property pm_power_props_usb[] = {
1388 POWER_SUPPLY_PROP_PRESENT,
1389 POWER_SUPPLY_PROP_ONLINE,
1390 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001391 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001392 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001393};
1394
1395static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001397 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398};
1399
1400static char *pm_power_supplied_to[] = {
1401 "battery",
1402};
1403
David Keitel6ed71a52012-01-30 12:42:18 -08001404#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001405static int pm_power_get_property_mains(struct power_supply *psy,
1406 enum power_supply_property psp,
1407 union power_supply_propval *val)
1408{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001409 int type;
1410
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001411 /* Check if called before init */
1412 if (!the_chip)
1413 return -EINVAL;
1414
1415 switch (psp) {
1416 case POWER_SUPPLY_PROP_PRESENT:
1417 case POWER_SUPPLY_PROP_ONLINE:
1418 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001419
1420 if (the_chip->has_dc_supply) {
1421 val->intval = 1;
1422 return 0;
1423 }
1424
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001425 if (the_chip->dc_present) {
1426 val->intval = 1;
1427 return 0;
1428 }
1429
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001430 type = the_chip->usb_psy.type;
1431 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1432 type == POWER_SUPPLY_TYPE_USB_ACA ||
1433 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001434 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001435
1436 break;
1437 default:
1438 return -EINVAL;
1439 }
1440 return 0;
1441}
1442
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001443static int disable_aicl(int disable)
1444{
1445 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1446 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1447 pr_err("called with invalid param :%d\n", disable);
1448 return -EINVAL;
1449 }
1450
1451 if (!the_chip) {
1452 pr_err("%s called before init\n", __func__);
1453 return -EINVAL;
1454 }
1455
1456 pr_debug("Disable AICL = %d\n", disable);
1457 the_chip->disable_aicl = disable;
1458 return 0;
1459}
1460
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001461static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1462{
1463 int rc;
1464
1465 if (!chip->host_mode)
1466 return 0;
1467
1468 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001469 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001470 if (rc < 0) {
1471 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1472 return rc;
1473 }
1474
1475 chip->host_mode = 0;
1476
1477 return 0;
1478}
1479
1480static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1481{
1482 int rc;
1483
1484 if (chip->host_mode)
1485 return 0;
1486
1487 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001488 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001489 if (rc < 0) {
1490 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1491 return rc;
1492 }
1493
1494 chip->host_mode = 1;
1495
1496 return 0;
1497}
1498
1499static int pm_power_set_property_usb(struct power_supply *psy,
1500 enum power_supply_property psp,
1501 const union power_supply_propval *val)
1502{
1503 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001504 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001505 return -EINVAL;
1506
1507 switch (psp) {
1508 case POWER_SUPPLY_PROP_SCOPE:
1509 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001510 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001511 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001512 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001513 else
1514 return -EINVAL;
1515 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001516 case POWER_SUPPLY_PROP_TYPE:
1517 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001518 case POWER_SUPPLY_PROP_HEALTH:
1519 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1520 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001521 default:
1522 return -EINVAL;
1523 }
1524 return 0;
1525}
1526
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001527static int usb_property_is_writeable(struct power_supply *psy,
1528 enum power_supply_property psp)
1529{
1530 switch (psp) {
1531 case POWER_SUPPLY_PROP_HEALTH:
1532 return 1;
1533 default:
1534 break;
1535 }
1536
1537 return 0;
1538}
1539
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001540static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 enum power_supply_property psp,
1542 union power_supply_propval *val)
1543{
David Keitel6ed71a52012-01-30 12:42:18 -08001544 int current_max;
1545
1546 /* Check if called before init */
1547 if (!the_chip)
1548 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549
1550 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001551 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001552 if (pm_is_chg_charge_dis(the_chip)) {
1553 val->intval = 0;
1554 } else {
1555 pm_chg_iusbmax_get(the_chip, &current_max);
1556 val->intval = current_max;
1557 }
David Keitel6ed71a52012-01-30 12:42:18 -08001558 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001560 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001561 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001562
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001563 if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001564 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001567
1568 case POWER_SUPPLY_PROP_SCOPE:
1569 if (the_chip->host_mode)
1570 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1571 else
1572 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1573 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001574 case POWER_SUPPLY_PROP_HEALTH:
1575 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1576 val->intval = the_chip->disable_aicl;
1577 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578 default:
1579 return -EINVAL;
1580 }
1581 return 0;
1582}
1583
1584static enum power_supply_property msm_batt_power_props[] = {
1585 POWER_SUPPLY_PROP_STATUS,
1586 POWER_SUPPLY_PROP_CHARGE_TYPE,
1587 POWER_SUPPLY_PROP_HEALTH,
1588 POWER_SUPPLY_PROP_PRESENT,
1589 POWER_SUPPLY_PROP_TECHNOLOGY,
1590 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1591 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1592 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1593 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001594 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001595 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001596 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001597 POWER_SUPPLY_PROP_CHARGE_FULL,
1598 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599};
1600
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001601static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001602{
1603 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001604 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001606 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 if (rc) {
1608 pr_err("error reading adc channel = %d, rc = %d\n",
1609 chip->vbat_channel, rc);
1610 return rc;
1611 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001612 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 result.measurement);
1614 return (int)result.physical;
1615}
1616
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001617static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1618{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001619 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1620 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1621 unsigned int low_voltage = chip->min_voltage_mv;
1622 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001623
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001624 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001625 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001626 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001627 return 100;
1628 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001629 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001630 / (high_voltage - low_voltage);
1631}
1632
David Keitel4f9397b2012-04-16 11:46:16 -07001633static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1634{
1635 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1636}
1637
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001638static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1639{
1640 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1641 int fsm_state = pm_chg_get_fsm_state(chip);
1642 int i;
1643
1644 if (chip->ext_psy) {
1645 if (chip->ext_charge_done)
1646 return POWER_SUPPLY_STATUS_FULL;
1647 if (chip->ext_charging)
1648 return POWER_SUPPLY_STATUS_CHARGING;
1649 }
1650
1651 for (i = 0; i < ARRAY_SIZE(map); i++)
1652 if (map[i].fsm_state == fsm_state)
1653 batt_state = map[i].batt_state;
1654
1655 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1656 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1657 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1658 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1659 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1660
1661 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1662 }
1663 return batt_state;
1664}
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1667{
David Keitel4f9397b2012-04-16 11:46:16 -07001668 int percent_soc;
1669
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001670 if (chip->battery_less_hardware)
1671 return 100;
1672
David Keitel4f9397b2012-04-16 11:46:16 -07001673 if (!get_prop_batt_present(chip))
1674 percent_soc = voltage_based_capacity(chip);
1675 else
1676 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001677
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001678 if (percent_soc == -ENXIO)
1679 percent_soc = voltage_based_capacity(chip);
1680
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001681 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001682 pr_warn_ratelimited("low battery charge = %d%%\n",
1683 percent_soc);
1684
1685 if (percent_soc <= chip->resume_charge_percent
1686 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1687 pr_debug("soc fell below %d. charging enabled.\n",
1688 chip->resume_charge_percent);
1689 if (chip->is_bat_warm)
1690 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1691 chip->is_bat_warm,
1692 chip->resume_charge_percent);
1693 else if (chip->is_bat_cool)
1694 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1695 chip->is_bat_cool,
1696 chip->resume_charge_percent);
1697 else
1698 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1699 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001700
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001701 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001702 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703}
1704
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001705static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1706{
1707 return pm8921_bms_get_current_max();
1708}
1709
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001710static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1711{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001712 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001713
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001714 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001715 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001716 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001717 }
1718
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001719 if (rc) {
1720 pr_err("unable to get batt current rc = %d\n", rc);
1721 return rc;
1722 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001723 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001724 }
1725}
1726
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001727static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1728{
1729 int rc;
1730
1731 rc = pm8921_bms_get_fcc();
1732 if (rc < 0)
1733 pr_err("unable to get batt fcc rc = %d\n", rc);
1734 return rc;
1735}
1736
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001737static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1738{
1739 int rc;
1740 int cc_uah;
1741
1742 rc = pm8921_bms_cc_uah(&cc_uah);
1743
1744 if (rc == 0)
1745 return cc_uah;
1746
1747 pr_err("unable to get batt fcc rc = %d\n", rc);
1748 return rc;
1749}
1750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1752{
1753 int temp;
1754
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001755 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1756 if (temp)
1757 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001759 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1760 if (temp)
1761 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001763 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764}
1765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1767{
1768 int temp;
1769
Amir Samuelovd31ef502011-10-26 14:41:36 +02001770 if (!get_prop_batt_present(chip))
1771 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1772
1773 if (is_ext_trickle_charging(chip))
1774 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1775
1776 if (is_ext_charging(chip))
1777 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1778
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1780 if (temp)
1781 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1782
1783 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1784 if (temp)
1785 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1786
1787 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1788}
1789
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001790#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001791static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1792{
1793 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001794 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001795
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001796 if (chip->battery_less_hardware)
1797 return 300;
1798
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001799 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001800 if (rc) {
1801 pr_err("error reading adc channel = %d, rc = %d\n",
1802 chip->vbat_channel, rc);
1803 return rc;
1804 }
1805 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1806 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001807 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1808 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1809 (int) result.physical);
1810
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001811 return (int)result.physical;
1812}
1813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814static int pm_batt_power_get_property(struct power_supply *psy,
1815 enum power_supply_property psp,
1816 union power_supply_propval *val)
1817{
1818 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1819 batt_psy);
1820
1821 switch (psp) {
1822 case POWER_SUPPLY_PROP_STATUS:
1823 val->intval = get_prop_batt_status(chip);
1824 break;
1825 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1826 val->intval = get_prop_charge_type(chip);
1827 break;
1828 case POWER_SUPPLY_PROP_HEALTH:
1829 val->intval = get_prop_batt_health(chip);
1830 break;
1831 case POWER_SUPPLY_PROP_PRESENT:
1832 val->intval = get_prop_batt_present(chip);
1833 break;
1834 case POWER_SUPPLY_PROP_TECHNOLOGY:
1835 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1836 break;
1837 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001838 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 break;
1840 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001841 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 break;
1843 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001844 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 break;
1846 case POWER_SUPPLY_PROP_CAPACITY:
1847 val->intval = get_prop_batt_capacity(chip);
1848 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001849 case POWER_SUPPLY_PROP_CURRENT_NOW:
1850 val->intval = get_prop_batt_current(chip);
1851 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001852 case POWER_SUPPLY_PROP_CURRENT_MAX:
1853 val->intval = get_prop_batt_current_max(chip);
1854 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001855 case POWER_SUPPLY_PROP_TEMP:
1856 val->intval = get_prop_batt_temp(chip);
1857 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001858 case POWER_SUPPLY_PROP_CHARGE_FULL:
1859 val->intval = get_prop_batt_fcc(chip);
1860 break;
1861 case POWER_SUPPLY_PROP_CHARGE_NOW:
1862 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001863 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 default:
1865 return -EINVAL;
1866 }
1867
1868 return 0;
1869}
1870
1871static void (*notify_vbus_state_func_ptr)(int);
1872static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873
1874int pm8921_charger_register_vbus_sn(void (*callback)(int))
1875{
1876 pr_debug("%p\n", callback);
1877 notify_vbus_state_func_ptr = callback;
1878 return 0;
1879}
1880EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1881
1882/* this is passed to the hsusb via platform_data msm_otg_pdata */
1883void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1884{
1885 pr_debug("%p\n", callback);
1886 notify_vbus_state_func_ptr = NULL;
1887}
1888EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1889
1890static void notify_usb_of_the_plugin_event(int plugin)
1891{
1892 plugin = !!plugin;
1893 if (notify_vbus_state_func_ptr) {
1894 pr_debug("notifying plugin\n");
1895 (*notify_vbus_state_func_ptr) (plugin);
1896 } else {
1897 pr_debug("unable to notify plugin\n");
1898 }
1899}
1900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901static void __pm8921_charger_vbus_draw(unsigned int mA)
1902{
1903 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001904 if (!the_chip) {
1905 pr_err("called before init\n");
1906 return;
1907 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001909 if (usb_max_current && mA > usb_max_current) {
1910 pr_debug("restricting usb current to %d instead of %d\n",
1911 usb_max_current, mA);
1912 mA = usb_max_current;
1913 }
1914
1915 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001917 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001919 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 }
1921 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1922 if (rc)
1923 pr_err("fail to set suspend bit rc=%d\n", rc);
1924 } else {
1925 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1926 if (rc)
1927 pr_err("fail to reset suspend bit rc=%d\n", rc);
1928 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1929 if (usb_ma_table[i].usb_ma <= mA)
1930 break;
1931 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001932
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001933 if (i < 0) {
1934 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1935 mA);
1936 i = 0;
1937 }
1938
David Keitel38bdd4f2012-04-19 15:39:13 -07001939 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001940 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001941 && !the_chip->iusb_fine_res)
1942 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943 if (i < 0)
1944 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001945 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001946 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001947 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 }
1949}
1950
1951/* USB calls these to tell us how much max usb current the system can draw */
1952void pm8921_charger_vbus_draw(unsigned int mA)
1953{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001954 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955
1956 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001957
David Keitel62c6a4b2012-05-17 12:54:59 -07001958 /*
1959 * Reject VBUS requests if USB connection is the only available
1960 * power source. This makes sure that if booting without
1961 * battery the iusb_max value is not decreased avoiding potential
1962 * brown_outs.
1963 *
1964 * This would also apply when the battery has been
1965 * removed from the running system.
1966 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001967 if (the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07001968 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001969 if (!the_chip->has_dc_supply) {
1970 pr_err("rejected: no other power source connected\n");
1971 return;
1972 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001973 }
1974
David Keitelacf57c82012-03-07 18:48:50 -08001975 if (usb_max_current && mA > usb_max_current) {
1976 pr_warn("restricting usb current to %d instead of %d\n",
1977 usb_max_current, mA);
1978 mA = usb_max_current;
1979 }
Devin Kim2073afb2012-09-05 13:01:51 -07001980 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1981 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001982
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301983 if (usb_target_ma)
1984 usb_target_ma = mA;
1985
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001986
1987 if (mA > USB_WALL_THRESHOLD_MA)
1988 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
1989 else
1990 set_usb_now_ma = mA;
1991
1992 if (the_chip && the_chip->disable_aicl)
1993 set_usb_now_ma = mA;
1994
1995 if (the_chip)
1996 __pm8921_charger_vbus_draw(set_usb_now_ma);
1997 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998 /*
1999 * called before pmic initialized,
2000 * save this value and use it at probe
2001 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002002 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003}
2004EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
2005
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002006int pm8921_is_usb_chg_plugged_in(void)
2007{
2008 if (!the_chip) {
2009 pr_err("called before init\n");
2010 return -EINVAL;
2011 }
2012 return is_usb_chg_plugged_in(the_chip);
2013}
2014EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
2015
2016int pm8921_is_dc_chg_plugged_in(void)
2017{
2018 if (!the_chip) {
2019 pr_err("called before init\n");
2020 return -EINVAL;
2021 }
2022 return is_dc_chg_plugged_in(the_chip);
2023}
2024EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
2025
2026int pm8921_is_battery_present(void)
2027{
2028 if (!the_chip) {
2029 pr_err("called before init\n");
2030 return -EINVAL;
2031 }
2032 return get_prop_batt_present(the_chip);
2033}
2034EXPORT_SYMBOL(pm8921_is_battery_present);
2035
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002036int pm8921_is_batfet_closed(void)
2037{
2038 if (!the_chip) {
2039 pr_err("called before init\n");
2040 return -EINVAL;
2041 }
2042 return is_batfet_closed(the_chip);
2043}
2044EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002045/*
2046 * Disabling the charge current limit causes current
2047 * current limits to have no monitoring. An adequate charger
2048 * capable of supplying high current while sustaining VIN_MIN
2049 * is required if the limiting is disabled.
2050 */
2051int pm8921_disable_input_current_limit(bool disable)
2052{
2053 if (!the_chip) {
2054 pr_err("called before init\n");
2055 return -EINVAL;
2056 }
2057 if (disable) {
2058 pr_warn("Disabling input current limit!\n");
2059
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002060 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002061 }
2062 return 0;
2063}
2064EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2065
David Keitel0789fc62012-06-07 17:43:27 -07002066int pm8917_set_under_voltage_detection_threshold(int mv)
2067{
2068 if (!the_chip) {
2069 pr_err("called before init\n");
2070 return -EINVAL;
2071 }
2072 return pm_chg_uvd_threshold_set(the_chip, mv);
2073}
2074EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2075
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002076int pm8921_set_max_battery_charge_current(int ma)
2077{
2078 if (!the_chip) {
2079 pr_err("called before init\n");
2080 return -EINVAL;
2081 }
2082 return pm_chg_ibatmax_set(the_chip, ma);
2083}
2084EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2085
2086int pm8921_disable_source_current(bool disable)
2087{
2088 if (!the_chip) {
2089 pr_err("called before init\n");
2090 return -EINVAL;
2091 }
2092 if (disable)
2093 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002094
2095 pm_chg_usb_suspend_enable(the_chip, disable);
2096
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002097 return pm_chg_charge_dis(the_chip, disable);
2098}
2099EXPORT_SYMBOL(pm8921_disable_source_current);
2100
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002101int pm8921_regulate_input_voltage(int voltage)
2102{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002103 int rc;
2104
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002105 if (!the_chip) {
2106 pr_err("called before init\n");
2107 return -EINVAL;
2108 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002109 rc = pm_chg_vinmin_set(the_chip, voltage);
2110
2111 if (rc == 0)
2112 the_chip->vin_min = voltage;
2113
2114 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002115}
2116
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002117#define USB_OV_THRESHOLD_MASK 0x60
2118#define USB_OV_THRESHOLD_SHIFT 5
2119int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2120{
2121 u8 temp;
2122
2123 if (!the_chip) {
2124 pr_err("called before init\n");
2125 return -EINVAL;
2126 }
2127
2128 if (ov > PM_USB_OV_7V) {
2129 pr_err("limiting to over voltage threshold to 7volts\n");
2130 ov = PM_USB_OV_7V;
2131 }
2132
2133 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2134
2135 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2136 USB_OV_THRESHOLD_MASK, temp);
2137}
2138EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2139
2140#define USB_DEBOUNCE_TIME_MASK 0x06
2141#define USB_DEBOUNCE_TIME_SHIFT 1
2142int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2143{
2144 u8 temp;
2145
2146 if (!the_chip) {
2147 pr_err("called before init\n");
2148 return -EINVAL;
2149 }
2150
2151 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2152 pr_err("limiting debounce to 80.5ms\n");
2153 ms = PM_USB_DEBOUNCE_80P5MS;
2154 }
2155
2156 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2157
2158 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2159 USB_DEBOUNCE_TIME_MASK, temp);
2160}
2161EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2162
2163#define USB_OVP_DISABLE_MASK 0x80
2164int pm8921_usb_ovp_disable(int disable)
2165{
2166 u8 temp = 0;
2167
2168 if (!the_chip) {
2169 pr_err("called before init\n");
2170 return -EINVAL;
2171 }
2172
2173 if (disable)
2174 temp = USB_OVP_DISABLE_MASK;
2175
2176 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2177 USB_OVP_DISABLE_MASK, temp);
2178}
2179
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002180bool pm8921_is_battery_charging(int *source)
2181{
2182 int fsm_state, is_charging, dc_present, usb_present;
2183
2184 if (!the_chip) {
2185 pr_err("called before init\n");
2186 return -EINVAL;
2187 }
2188 fsm_state = pm_chg_get_fsm_state(the_chip);
2189 is_charging = is_battery_charging(fsm_state);
2190 if (is_charging == 0) {
2191 *source = PM8921_CHG_SRC_NONE;
2192 return is_charging;
2193 }
2194
2195 if (source == NULL)
2196 return is_charging;
2197
2198 /* the battery is charging, the source is requested, find it */
2199 dc_present = is_dc_chg_plugged_in(the_chip);
2200 usb_present = is_usb_chg_plugged_in(the_chip);
2201
2202 if (dc_present && !usb_present)
2203 *source = PM8921_CHG_SRC_DC;
2204
2205 if (usb_present && !dc_present)
2206 *source = PM8921_CHG_SRC_USB;
2207
2208 if (usb_present && dc_present)
2209 /*
2210 * The system always chooses dc for charging since it has
2211 * higher priority.
2212 */
2213 *source = PM8921_CHG_SRC_DC;
2214
2215 return is_charging;
2216}
2217EXPORT_SYMBOL(pm8921_is_battery_charging);
2218
David Keitel86034022012-04-18 12:33:58 -07002219int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2220{
2221 if (!the_chip) {
2222 pr_err("called before init\n");
2223 return -EINVAL;
2224 }
2225
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002226 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002227 return -EINVAL;
2228
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002229 the_chip->usb_psy.type = type;
David Keitel86034022012-04-18 12:33:58 -07002230 power_supply_changed(&the_chip->usb_psy);
2231 power_supply_changed(&the_chip->dc_psy);
2232 return 0;
2233}
2234EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2235
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002236int pm8921_batt_temperature(void)
2237{
2238 if (!the_chip) {
2239 pr_err("called before init\n");
2240 return -EINVAL;
2241 }
2242 return get_prop_batt_temp(the_chip);
2243}
2244
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002245static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002246{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002247 int err;
2248 u8 temp;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002249
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002250
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002251 temp = 0xD1;
2252 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2253 if (err) {
2254 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002255 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002256 }
2257
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002258 temp = 0xD3;
2259 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2260 if (err) {
2261 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002262 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002263 }
2264
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002265 temp = 0xD1;
2266 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2267 if (err) {
2268 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002269 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002270 }
2271
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002272 temp = 0xD5;
2273 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2274 if (err) {
2275 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002276 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002277 }
2278
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002279 /* Wait a few clock cycles before re-enabling hw clock switching */
2280 udelay(183);
2281
2282 temp = 0xD1;
2283 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2284 if (err) {
2285 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002286 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002287 }
2288
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002289 temp = 0xD0;
2290 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2291 if (err) {
2292 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002293 return err;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002294 }
2295
2296 /* Wait for few clock cycles before re-enabling LPM */
2297 udelay(32);
2298
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002299 return 0;
2300}
2301
2302static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
2303{
2304 int err;
2305 unsigned long flags = 0;
2306
2307 spin_lock_irqsave(&lpm_lock, flags);
2308 err = pm8921_chg_set_lpm(chip, 0);
2309 if (err) {
2310 pr_err("Error settig LPM rc=%d\n", err);
2311 goto kick_err;
2312 }
2313
2314 __pm8921_apply_19p2mhz_kickstart(chip);
2315
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002316kick_err:
2317 err = pm8921_chg_set_lpm(chip, 1);
2318 if (err)
2319 pr_err("Error settig LPM rc=%d\n", err);
2320
2321 spin_unlock_irqrestore(&lpm_lock, flags);
2322
2323 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002324}
2325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2327{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002328 int usb_present, rc = 0;
2329
2330 if (chip->lockup_lpm_wrkarnd) {
2331 rc = pm8921_apply_19p2mhz_kickstart(chip);
2332 if (rc)
2333 pr_err("Failed to apply kickstart rc=%d\n", rc);
2334 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002336 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 usb_present = is_usb_chg_plugged_in(chip);
2338 if (chip->usb_present ^ usb_present) {
2339 notify_usb_of_the_plugin_event(usb_present);
2340 chip->usb_present = usb_present;
2341 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002342 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002343 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002344
2345 /* Enable/disable bypass if charger is on battery */
2346 if (chip->lockup_lpm_wrkarnd)
2347 pm8921_chg_bypass_bat_gone_debounce(chip,
2348 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002349 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002350 if (usb_present) {
2351 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002352 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002353 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2354 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002355 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002356 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002357 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002358 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002359 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002360}
2361
Amir Samuelovd31ef502011-10-26 14:41:36 +02002362static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2363{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002364 if (chip->lockup_lpm_wrkarnd)
2365 /* Enable bypass if charger is on battery */
2366 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2367
David Keitel88e1b572012-01-11 11:57:14 -08002368 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002369 pr_debug("external charger not registered.\n");
2370 return;
2371 }
2372
2373 if (!chip->ext_charging) {
2374 pr_debug("already not charging.\n");
2375 return;
2376 }
2377
David Keitel88e1b572012-01-11 11:57:14 -08002378 power_supply_set_charge_type(chip->ext_psy,
2379 POWER_SUPPLY_CHARGE_TYPE_NONE);
2380 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002381 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002382 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002383 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002384 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002385 /* Update battery charging LEDs and user space battery info */
2386 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002387}
2388
2389static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2390{
2391 int dc_present;
2392 int batt_present;
2393 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002394 unsigned long delay =
2395 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2396
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002397 /* Disable bypass if charger connected and not running on bat */
2398 if (chip->lockup_lpm_wrkarnd)
2399 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2400
David Keitel88e1b572012-01-11 11:57:14 -08002401 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002402 pr_debug("external charger not registered.\n");
2403 return;
2404 }
2405
2406 if (chip->ext_charging) {
2407 pr_debug("already charging.\n");
2408 return;
2409 }
2410
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002411 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002412 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2413 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002414
2415 if (!dc_present) {
2416 pr_warn("%s. dc not present.\n", __func__);
2417 return;
2418 }
2419 if (!batt_present) {
2420 pr_warn("%s. battery not present.\n", __func__);
2421 return;
2422 }
2423 if (!batt_temp_ok) {
2424 pr_warn("%s. battery temperature not ok.\n", __func__);
2425 return;
2426 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002427
2428 /* Force BATFET=ON */
2429 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002430
David Keitel6ccbf132012-05-30 14:21:24 -07002431 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002432 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002433
David Keitel63f71662012-02-08 20:30:00 -08002434 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002435 power_supply_set_charge_type(chip->ext_psy,
2436 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002437 chip->ext_charging = true;
2438 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002439 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002440 /*
2441 * since we wont get a fastchg irq from external charger
2442 * use eoc worker to detect end of charging
2443 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002444 schedule_delayed_work(&chip->eoc_work, delay);
2445 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002446 if (chip->btc_override)
2447 schedule_delayed_work(&chip->btc_override_work,
2448 round_jiffies_relative(msecs_to_jiffies
2449 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002450 /* Update battery charging LEDs and user space battery info */
2451 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002452}
2453
David Keitel6ccbf132012-05-30 14:21:24 -07002454static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002455{
2456 u8 temp;
2457 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002458
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002459 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002460 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002461 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002462 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002463 }
David Keitel6ccbf132012-05-30 14:21:24 -07002464 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002465 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002466 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002467 return;
2468 }
2469 /* set ovp fet disable bit and the write bit */
2470 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002471 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002472 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002473 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002474 return;
2475 }
2476}
2477
David Keitel6ccbf132012-05-30 14:21:24 -07002478static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002479{
2480 u8 temp;
2481 int rc;
2482
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002483 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002484 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002485 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002486 return;
2487 }
David Keitel6ccbf132012-05-30 14:21:24 -07002488 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002489 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002490 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002491 return;
2492 }
2493 /* unset ovp fet disable bit and set the write bit */
2494 temp &= 0xFE;
2495 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002496 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002497 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002498 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002499 temp, rc);
2500 return;
2501 }
2502}
2503
2504static int param_open_ovp_counter = 10;
2505module_param(param_open_ovp_counter, int, 0644);
2506
David Keitel6ccbf132012-05-30 14:21:24 -07002507#define USB_ACTIVE_BIT BIT(5)
2508#define DC_ACTIVE_BIT BIT(6)
2509static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2510 u8 active_chg_mask)
2511{
2512 if (active_chg_mask & USB_ACTIVE_BIT)
2513 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2514 else if (active_chg_mask & DC_ACTIVE_BIT)
2515 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2516 else
2517 return 0;
2518}
2519
David Keitel8c5201a2012-02-24 16:08:54 -08002520#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002521#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002522static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002523{
David Keitel6ccbf132012-05-30 14:21:24 -07002524 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002525 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002526 u8 active_mask = 0;
2527 u16 ovpreg, ovptestreg;
2528
2529 if (is_usb_chg_plugged_in(chip) &&
2530 (chip->active_path & USB_ACTIVE_BIT)) {
2531 ovpreg = USB_OVP_CONTROL;
2532 ovptestreg = USB_OVP_TEST;
2533 active_mask = USB_ACTIVE_BIT;
2534 } else if (is_dc_chg_plugged_in(chip) &&
2535 (chip->active_path & DC_ACTIVE_BIT)) {
2536 ovpreg = DC_OVP_CONTROL;
2537 ovptestreg = DC_OVP_TEST;
2538 active_mask = DC_ACTIVE_BIT;
2539 } else {
2540 return;
2541 }
David Keitel8c5201a2012-02-24 16:08:54 -08002542
2543 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002544 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002545 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002546 active_chg_plugged_in
2547 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002548 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002549 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2550 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002551
2552 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002553 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002554 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002555 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002556
2557 msleep(20);
2558
David Keitel6ccbf132012-05-30 14:21:24 -07002559 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002560 } else {
David Keitel712782e2012-03-29 14:11:47 -07002561 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002562 }
2563 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002564 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2565 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2566 else
2567 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2568
David Keitel6ccbf132012-05-30 14:21:24 -07002569 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2570 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002571 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002572}
David Keitelacf57c82012-03-07 18:48:50 -08002573
2574static int find_usb_ma_value(int value)
2575{
2576 int i;
2577
2578 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2579 if (value >= usb_ma_table[i].usb_ma)
2580 break;
2581 }
2582
2583 return i;
2584}
2585
2586static void decrease_usb_ma_value(int *value)
2587{
2588 int i;
2589
2590 if (value) {
2591 i = find_usb_ma_value(*value);
2592 if (i > 0)
2593 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002594 while (!the_chip->iusb_fine_res && i > 0
2595 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2596 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002597
2598 if (i < 0) {
2599 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2600 *value);
2601 i = 0;
2602 }
2603
David Keitelacf57c82012-03-07 18:48:50 -08002604 *value = usb_ma_table[i].usb_ma;
2605 }
2606}
2607
2608static void increase_usb_ma_value(int *value)
2609{
2610 int i;
2611
2612 if (value) {
2613 i = find_usb_ma_value(*value);
2614
2615 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2616 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002617 /* Get next correct entry if IUSB_FINE_RES is not available */
2618 while (!the_chip->iusb_fine_res
2619 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2620 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2621 i++;
2622
David Keitelacf57c82012-03-07 18:48:50 -08002623 *value = usb_ma_table[i].usb_ma;
2624 }
2625}
2626
2627static void vin_collapse_check_worker(struct work_struct *work)
2628{
2629 struct delayed_work *dwork = to_delayed_work(work);
2630 struct pm8921_chg_chip *chip = container_of(dwork,
2631 struct pm8921_chg_chip, vin_collapse_check_work);
2632
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002633 /*
2634 * AICL only for wall-chargers. If the charger appears to be plugged
2635 * back in now, the corresponding unplug must have been because of we
2636 * were trying to draw more current than the charger can support. In
2637 * such a case reset usb current to 500mA and decrease the target.
2638 * The AICL algorithm will step up the current from 500mA to target
2639 */
2640 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002641 && usb_target_ma > USB_WALL_THRESHOLD_MA
2642 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002643 /* decrease usb_target_ma */
2644 decrease_usb_ma_value(&usb_target_ma);
2645 /* reset here, increase in unplug_check_worker */
2646 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2647 pr_debug("usb_now=%d, usb_target = %d\n",
2648 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002649 if (!delayed_work_pending(&chip->unplug_check_work))
2650 schedule_delayed_work(&chip->unplug_check_work,
2651 msecs_to_jiffies
2652 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002653 } else {
2654 handle_usb_insertion_removal(chip);
2655 }
2656}
2657
2658#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2660{
David Keitelacf57c82012-03-07 18:48:50 -08002661 if (usb_target_ma)
2662 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2663 round_jiffies_relative(msecs_to_jiffies
2664 (VIN_MIN_COLLAPSE_CHECK_MS)));
2665 else
2666 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 return IRQ_HANDLED;
2668}
2669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2671{
2672 struct pm8921_chg_chip *chip = data;
2673 int status;
2674
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002675 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2676 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002677 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 pr_debug("battery present=%d", status);
2679 power_supply_changed(&chip->batt_psy);
2680 return IRQ_HANDLED;
2681}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002682
2683/*
2684 * this interrupt used to restart charging a battery.
2685 *
2686 * Note: When DC-inserted the VBAT can't go low.
2687 * VPH_PWR is provided by the ext-charger.
2688 * After End-Of-Charging from DC, charging can be resumed only
2689 * if DC is removed and then inserted after the battery was in use.
2690 * Therefore the handle_start_ext_chg() is not called.
2691 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2693{
2694 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002695 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002697 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002698
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002699 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002700 /* enable auto charging */
2701 pm_chg_auto_enable(chip, !charging_disabled);
2702 pr_info("batt fell below resume voltage %s\n",
2703 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002707 power_supply_changed(&chip->batt_psy);
2708 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002709 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002711 return IRQ_HANDLED;
2712}
2713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002714static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2715{
2716 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2717 return IRQ_HANDLED;
2718}
2719
2720static irqreturn_t vcp_irq_handler(int irq, void *data)
2721{
David Keitel8c5201a2012-02-24 16:08:54 -08002722 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002723 return IRQ_HANDLED;
2724}
2725
2726static irqreturn_t atcdone_irq_handler(int irq, void *data)
2727{
2728 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2729 return IRQ_HANDLED;
2730}
2731
2732static irqreturn_t atcfail_irq_handler(int irq, void *data)
2733{
2734 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2735 return IRQ_HANDLED;
2736}
2737
2738static irqreturn_t chgdone_irq_handler(int irq, void *data)
2739{
2740 struct pm8921_chg_chip *chip = data;
2741
2742 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002743
2744 handle_stop_ext_chg(chip);
2745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002746 power_supply_changed(&chip->batt_psy);
2747 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002748 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002749
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002750 bms_notify_check(chip);
2751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002752 return IRQ_HANDLED;
2753}
2754
2755static irqreturn_t chgfail_irq_handler(int irq, void *data)
2756{
2757 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002758 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002760 if (!chip->stop_chg_upon_expiry) {
2761 ret = pm_chg_failed_clear(chip, 1);
2762 if (ret)
2763 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2764 }
David Keitel753ec8d2011-11-02 10:56:37 -07002765
2766 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2767 get_prop_batt_present(chip),
2768 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2769 pm_chg_get_fsm_state(data));
2770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 power_supply_changed(&chip->batt_psy);
2772 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002773 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 return IRQ_HANDLED;
2775}
2776
2777static irqreturn_t chgstate_irq_handler(int irq, void *data)
2778{
2779 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780
2781 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2782 power_supply_changed(&chip->batt_psy);
2783 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002784 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002786 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002788 return IRQ_HANDLED;
2789}
2790
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002791enum {
2792 PON_TIME_25NS = 0x04,
2793 PON_TIME_50NS = 0x08,
2794 PON_TIME_100NS = 0x0C,
2795};
David Keitel8c5201a2012-02-24 16:08:54 -08002796
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002797static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002798{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002799 u8 temp;
2800 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002801
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002802 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2803 if (rc) {
2804 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2805 return;
2806 }
2807 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2808 if (rc) {
2809 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2810 return;
2811 }
2812 /* clear the min pon time select bit */
2813 temp &= 0xF3;
2814 /* set the pon time */
2815 temp |= (u8)pon_time_ns;
2816 /* write enable bank 4 */
2817 temp |= 0x80;
2818 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2819 if (rc) {
2820 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2821 return;
2822 }
2823}
David Keitel8c5201a2012-02-24 16:08:54 -08002824
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002825static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2826{
2827 pr_debug("Start\n");
2828 set_min_pon_time(chip, PON_TIME_100NS);
2829 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2830 msleep(250);
2831 pm_chg_vinmin_set(chip, chip->vin_min);
2832 set_min_pon_time(chip, PON_TIME_25NS);
2833 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002834}
2835
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002836#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002837#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2838#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002839static void unplug_check_worker(struct work_struct *work)
2840{
2841 struct delayed_work *dwork = to_delayed_work(work);
2842 struct pm8921_chg_chip *chip = container_of(dwork,
2843 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002844 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002845 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002846 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002847 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002848
2849 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2850 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002851 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2852 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002853 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002854
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002855 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002856 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002857 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2858 active_path, active_chg_plugged_in);
2859 if (active_path & USB_ACTIVE_BIT) {
2860 pr_debug("USB charger active\n");
2861
2862 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002863
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002864 if (usb_ma <= 100) {
2865 pr_debug(
2866 "Unenumerated or suspended usb_ma = %d skip\n",
2867 usb_ma);
2868 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002869 }
2870 } else if (active_path & DC_ACTIVE_BIT) {
2871 pr_debug("DC charger active\n");
2872 } else {
2873 /* No charger active */
2874 if (!(is_usb_chg_plugged_in(chip)
2875 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002876 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002877 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2878 pm_chg_get_regulation_loop(chip),
2879 pm_chg_get_fsm_state(chip),
2880 get_prop_batt_current(chip)
2881 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002882 if (chip->lockup_lpm_wrkarnd) {
2883 rc = pm8921_apply_19p2mhz_kickstart(chip);
2884 if (rc)
2885 pr_err("Failed kickstart rc=%d\n", rc);
2886
2887 /*
2888 * Make sure kickstart happens at least 200 ms
2889 * after charger has been removed.
2890 */
2891 if (chip->final_kickstart) {
2892 chip->final_kickstart = false;
2893 goto check_again_later;
2894 }
2895 }
2896 return;
2897 } else {
2898 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002899 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002900 }
David Keitel8c5201a2012-02-24 16:08:54 -08002901
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002902 chip->final_kickstart = true;
2903
2904 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002905 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
2906 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07002907 reg_loop = pm_chg_get_regulation_loop(chip);
2908 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2909 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002910 (usb_ma > USB_WALL_THRESHOLD_MA)
2911 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002912 decrease_usb_ma_value(&usb_ma);
2913 usb_target_ma = usb_ma;
2914 /* end AICL here */
2915 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002916 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002917 usb_ma, usb_target_ma);
2918 }
David Keitelacf57c82012-03-07 18:48:50 -08002919 }
2920
2921 reg_loop = pm_chg_get_regulation_loop(chip);
2922 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2923
David Keitel6ccbf132012-05-30 14:21:24 -07002924 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002925 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002926 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002927 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2928 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2929 attempt_reverse_boost_fix(chip);
2930 /* after reverse boost fix check if the active
2931 * charger was detected as removed */
2932 active_chg_plugged_in
2933 = is_active_chg_plugged_in(chip,
2934 active_path);
2935 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2936 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002937 }
2938 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002939
2940 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002941 pr_debug("active_path = 0x%x, active_chg = %d\n",
2942 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002943 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2944
David Keitel6ccbf132012-05-30 14:21:24 -07002945 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2946 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2947 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002948 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002949 }
2950
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002951 /* AICL only for usb wall charger */
2952 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2953 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002954 && !charging_disabled
2955 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002956 /* only increase iusb_max if vin loop not active */
2957 if (usb_ma < usb_target_ma) {
2958 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302959 if (usb_ma > usb_target_ma)
2960 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002961 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002962 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002963 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002964 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002965 } else {
2966 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002967 }
2968 }
Devin Kim2073afb2012-09-05 13:01:51 -07002969check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002970 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002971 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002972 if (ramp)
2973 schedule_delayed_work(&chip->unplug_check_work,
2974 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2975 else
2976 schedule_delayed_work(&chip->unplug_check_work,
2977 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002978}
2979
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980static irqreturn_t loop_change_irq_handler(int irq, void *data)
2981{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002982 struct pm8921_chg_chip *chip = data;
2983
2984 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2985 pm_chg_get_fsm_state(data),
2986 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002987 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988 return IRQ_HANDLED;
2989}
2990
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002991struct ibatmax_max_adj_entry {
2992 int ibat_max_ma;
2993 int max_adj_ma;
2994};
2995
2996static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2997 {975, 300},
2998 {1475, 150},
2999 {1975, 200},
3000 {2475, 250},
3001};
3002
3003static int find_ibat_max_adj_ma(int ibat_target_ma)
3004{
3005 int i = 0;
3006
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08003007 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
3008 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003009 break;
3010 }
3011
3012 return ibatmax_adj_table[i].max_adj_ma;
3013}
3014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003015static irqreturn_t fastchg_irq_handler(int irq, void *data)
3016{
3017 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003018 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003020 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3021 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
3022 wake_lock(&chip->eoc_wake_lock);
3023 schedule_delayed_work(&chip->eoc_work,
3024 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003025 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003026 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003027 if (high_transition
3028 && chip->btc_override
3029 && !delayed_work_pending(&chip->btc_override_work)) {
3030 schedule_delayed_work(&chip->btc_override_work,
3031 round_jiffies_relative(msecs_to_jiffies
3032 (chip->btc_delay_ms)));
3033 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003034 power_supply_changed(&chip->batt_psy);
3035 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 return IRQ_HANDLED;
3037}
3038
3039static irqreturn_t trklchg_irq_handler(int irq, void *data)
3040{
3041 struct pm8921_chg_chip *chip = data;
3042
3043 power_supply_changed(&chip->batt_psy);
3044 return IRQ_HANDLED;
3045}
3046
3047static irqreturn_t batt_removed_irq_handler(int irq, void *data)
3048{
3049 struct pm8921_chg_chip *chip = data;
3050 int status;
3051
3052 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3053 pr_debug("battery present=%d state=%d", !status,
3054 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003055 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003056 power_supply_changed(&chip->batt_psy);
3057 return IRQ_HANDLED;
3058}
3059
3060static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3061{
3062 struct pm8921_chg_chip *chip = data;
3063
Amir Samuelovd31ef502011-10-26 14:41:36 +02003064 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065 power_supply_changed(&chip->batt_psy);
3066 return IRQ_HANDLED;
3067}
3068
3069static irqreturn_t chghot_irq_handler(int irq, void *data)
3070{
3071 struct pm8921_chg_chip *chip = data;
3072
3073 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3074 power_supply_changed(&chip->batt_psy);
3075 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003076 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003077 return IRQ_HANDLED;
3078}
3079
3080static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3081{
3082 struct pm8921_chg_chip *chip = data;
3083
3084 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003085 handle_stop_ext_chg(chip);
3086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003087 power_supply_changed(&chip->batt_psy);
3088 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 return IRQ_HANDLED;
3090}
3091
3092static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3093{
3094 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003095 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003096
3097 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3098 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3099
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003100 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3101 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003103 power_supply_changed(&chip->batt_psy);
3104 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 return IRQ_HANDLED;
3106}
David Keitel52fda532011-11-10 10:43:44 -08003107/*
3108 *
3109 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3110 * fire for two cases:
3111 *
3112 * If the interrupt line switches to high temperature is okay
3113 * and thus charging begins.
3114 * If bat_temp_ok is low this means the temperature is now
3115 * too hot or cold, so charging is stopped.
3116 *
3117 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3119{
David Keitel52fda532011-11-10 10:43:44 -08003120 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003121 struct pm8921_chg_chip *chip = data;
3122
David Keitel52fda532011-11-10 10:43:44 -08003123 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3124
3125 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3126 bat_temp_ok, pm_chg_get_fsm_state(data));
3127
3128 if (bat_temp_ok)
3129 handle_start_ext_chg(chip);
3130 else
3131 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003132
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133 power_supply_changed(&chip->batt_psy);
3134 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003135 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003136 return IRQ_HANDLED;
3137}
3138
3139static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3140{
3141 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3142 return IRQ_HANDLED;
3143}
3144
3145static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3146{
3147 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3148 return IRQ_HANDLED;
3149}
3150
3151static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3152{
3153 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3154 return IRQ_HANDLED;
3155}
3156
3157static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3158{
3159 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3160 return IRQ_HANDLED;
3161}
3162
3163static irqreturn_t batfet_irq_handler(int irq, void *data)
3164{
3165 struct pm8921_chg_chip *chip = data;
3166
3167 pr_debug("vreg ov\n");
3168 power_supply_changed(&chip->batt_psy);
3169 return IRQ_HANDLED;
3170}
3171
3172static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3173{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003174 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003175 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003176
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003177 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003178 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003179
3180 if (chip->dc_present ^ dc_present)
3181 pm8921_bms_calibrate_hkadc();
3182
David Keitel88e1b572012-01-11 11:57:14 -08003183 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003184 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003185 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003186 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3187
3188 chip->dc_present = dc_present;
3189
3190 if (chip->ext_psy) {
3191 if (dc_present)
3192 handle_start_ext_chg(chip);
3193 else
3194 handle_stop_ext_chg(chip);
3195 } else {
3196 if (chip->lockup_lpm_wrkarnd)
3197 /* if no external supply call bypass debounce here */
3198 pm8921_chg_bypass_bat_gone_debounce(chip,
3199 is_chg_on_bat(chip));
3200
3201 if (dc_present)
3202 schedule_delayed_work(&chip->unplug_check_work,
3203 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3204 power_supply_changed(&chip->dc_psy);
3205 }
3206
3207 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003208 return IRQ_HANDLED;
3209}
3210
3211static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3212{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003213 struct pm8921_chg_chip *chip = data;
3214
Amir Samuelovd31ef502011-10-26 14:41:36 +02003215 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003216 return IRQ_HANDLED;
3217}
3218
3219static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3220{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003221 struct pm8921_chg_chip *chip = data;
3222
Amir Samuelovd31ef502011-10-26 14:41:36 +02003223 handle_stop_ext_chg(chip);
3224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003225 return IRQ_HANDLED;
3226}
3227
David Keitel88e1b572012-01-11 11:57:14 -08003228static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3229{
3230 struct power_supply *psy = &the_chip->batt_psy;
3231 struct power_supply *epsy = dev_get_drvdata(dev);
3232 int i, dcin_irq;
3233
3234 /* Only search for external supply if none is registered */
3235 if (!the_chip->ext_psy) {
3236 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3237 for (i = 0; i < epsy->num_supplicants; i++) {
3238 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3239 if (!strncmp(epsy->name, "dc", 2)) {
3240 the_chip->ext_psy = epsy;
3241 dcin_valid_irq_handler(dcin_irq,
3242 the_chip);
3243 }
3244 }
3245 }
3246 }
3247 return 0;
3248}
3249
3250static void pm_batt_external_power_changed(struct power_supply *psy)
3251{
3252 /* Only look for an external supply if it hasn't been registered */
3253 if (!the_chip->ext_psy)
3254 class_for_each_device(power_supply_class, NULL, psy,
3255 __pm_batt_external_power_changed_work);
3256}
3257
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003258/**
3259 * update_heartbeat - internal function to update userspace
3260 * per update_time minutes
3261 *
3262 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003263#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003264static void update_heartbeat(struct work_struct *work)
3265{
3266 struct delayed_work *dwork = to_delayed_work(work);
3267 struct pm8921_chg_chip *chip = container_of(dwork,
3268 struct pm8921_chg_chip, update_heartbeat_work);
3269
3270 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003271 if (chip->recent_reported_soc <= 20)
3272 schedule_delayed_work(&chip->update_heartbeat_work,
3273 round_jiffies_relative(msecs_to_jiffies
3274 (LOW_SOC_HEARTBEAT_MS)));
3275 else
3276 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003277 round_jiffies_relative(msecs_to_jiffies
3278 (chip->update_time)));
3279}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003280#define VDD_LOOP_ACTIVE_BIT BIT(3)
3281#define VDD_MAX_INCREASE_MV 400
3282static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3283module_param(vdd_max_increase_mv, int, 0644);
3284
3285static int ichg_threshold_ua = -400000;
3286module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003287
3288#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003289static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3290 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003291{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003292 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003293 int vbat_batt_terminal_mv;
3294 int reg_loop;
3295 int delta_mv = 0;
3296
3297 if (chip->rconn_mohm == 0) {
3298 pr_debug("Exiting as rconn_mohm is 0\n");
3299 return;
3300 }
3301 /* adjust vdd_max only in normal temperature zone */
3302 if (chip->is_bat_cool || chip->is_bat_warm) {
3303 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3304 chip->is_bat_cool, chip->is_bat_warm);
3305 return;
3306 }
3307
3308 reg_loop = pm_chg_get_regulation_loop(chip);
3309 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3310 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3311 reg_loop);
3312 return;
3313 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003314 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3315 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3316
3317 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3318
3319 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3320 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3321 delta_mv,
3322 programmed_vdd_max,
3323 adj_vdd_max_mv);
3324
3325 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3326 pr_debug("adj vdd_max lower than default max voltage\n");
3327 return;
3328 }
3329
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003330 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3331 * PM8921_CHG_VDDMAX_RES_MV;
3332
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003333 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3334 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003335 pr_debug("adjusting vdd_max_mv to %d to make "
3336 "vbat_batt_termial_uv = %d to %d\n",
3337 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3338 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3339}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003340
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003341static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3342{
3343 if (chip->is_bat_cool)
3344 pm_chg_vbatdet_set(the_chip,
3345 the_chip->cool_bat_voltage
3346 - the_chip->resume_voltage_delta);
3347 else if (chip->is_bat_warm)
3348 pm_chg_vbatdet_set(the_chip,
3349 the_chip->warm_bat_voltage
3350 - the_chip->resume_voltage_delta);
3351 else
3352 pm_chg_vbatdet_set(the_chip,
3353 the_chip->max_voltage_mv
3354 - the_chip->resume_voltage_delta);
3355}
3356
3357static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3358{
3359 unsigned int chg_current = chip->max_bat_chg_current;
3360
3361 if (chip->is_bat_cool)
3362 chg_current = min(chg_current, chip->cool_bat_chg_current);
3363
3364 if (chip->is_bat_warm)
3365 chg_current = min(chg_current, chip->warm_bat_chg_current);
3366
3367 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3368 chg_current = min(chg_current,
3369 chip->thermal_mitigation[thermal_mitigation]);
3370
3371 pm_chg_ibatmax_set(the_chip, chg_current);
3372}
3373
3374#define TEMP_HYSTERISIS_DECIDEGC 20
3375static void battery_cool(bool enter)
3376{
3377 pr_debug("enter = %d\n", enter);
3378 if (enter == the_chip->is_bat_cool)
3379 return;
3380 the_chip->is_bat_cool = enter;
3381 if (enter)
3382 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3383 else
3384 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3385 set_appropriate_battery_current(the_chip);
3386 set_appropriate_vbatdet(the_chip);
3387}
3388
3389static void battery_warm(bool enter)
3390{
3391 pr_debug("enter = %d\n", enter);
3392 if (enter == the_chip->is_bat_warm)
3393 return;
3394 the_chip->is_bat_warm = enter;
3395 if (enter)
3396 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3397 else
3398 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3399
3400 set_appropriate_battery_current(the_chip);
3401 set_appropriate_vbatdet(the_chip);
3402}
3403
3404static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3405{
3406 int temp = 0;
3407
3408 temp = get_prop_batt_temp(chip);
3409 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3410 temp, chip->warm_temp_dc,
3411 chip->cool_temp_dc);
3412
3413 if (chip->warm_temp_dc != INT_MIN) {
3414 if (chip->is_bat_warm
3415 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3416 battery_warm(false);
3417 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3418 battery_warm(true);
3419 }
3420
3421 if (chip->cool_temp_dc != INT_MIN) {
3422 if (chip->is_bat_cool
3423 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3424 battery_cool(false);
3425 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3426 battery_cool(true);
3427 }
3428}
3429
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003430enum {
3431 CHG_IN_PROGRESS,
3432 CHG_NOT_IN_PROGRESS,
3433 CHG_FINISHED,
3434};
3435
3436#define VBAT_TOLERANCE_MV 70
3437#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003438static int is_charging_finished(struct pm8921_chg_chip *chip,
3439 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003440{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003441 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003442 int regulation_loop, fast_chg, vcp;
3443 int rc;
3444 static int last_vbat_programmed = -EINVAL;
3445
3446 if (!is_ext_charging(chip)) {
3447 /* return if the battery is not being fastcharged */
3448 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3449 pr_debug("fast_chg = %d\n", fast_chg);
3450 if (fast_chg == 0)
3451 return CHG_NOT_IN_PROGRESS;
3452
3453 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3454 pr_debug("vcp = %d\n", vcp);
3455 if (vcp == 1)
3456 return CHG_IN_PROGRESS;
3457
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003458 /* reset count if battery is hot/cold */
3459 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3460 pr_debug("batt_temp_ok = %d\n", rc);
3461 if (rc == 0)
3462 return CHG_IN_PROGRESS;
3463
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003464 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3465 if (rc) {
3466 pr_err("couldnt read vddmax rc = %d\n", rc);
3467 return CHG_IN_PROGRESS;
3468 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003469 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3470 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003471
3472 if (last_vbat_programmed == -EINVAL)
3473 last_vbat_programmed = vbat_programmed;
3474 if (last_vbat_programmed != vbat_programmed) {
3475 /* vddmax changed, reset and check again */
3476 pr_debug("vddmax = %d last_vdd_max=%d\n",
3477 vbat_programmed, last_vbat_programmed);
3478 last_vbat_programmed = vbat_programmed;
3479 return CHG_IN_PROGRESS;
3480 }
3481
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003482 if (chip->is_bat_cool)
3483 vbat_intended = chip->cool_bat_voltage;
3484 else if (chip->is_bat_warm)
3485 vbat_intended = chip->warm_bat_voltage;
3486 else
3487 vbat_intended = chip->max_voltage_mv;
3488
3489 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3490 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3491 vbat_batt_terminal_uv,
3492 vbat_intended);
3493 return CHG_IN_PROGRESS;
3494 }
3495
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003496 regulation_loop = pm_chg_get_regulation_loop(chip);
3497 if (regulation_loop < 0) {
3498 pr_err("couldnt read the regulation loop err=%d\n",
3499 regulation_loop);
3500 return CHG_IN_PROGRESS;
3501 }
3502 pr_debug("regulation_loop=%d\n", regulation_loop);
3503
3504 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3505 return CHG_IN_PROGRESS;
3506 } /* !is_ext_charging */
3507
3508 /* reset count if battery chg current is more than iterm */
3509 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3510 if (rc) {
3511 pr_err("couldnt read iterm rc = %d\n", rc);
3512 return CHG_IN_PROGRESS;
3513 }
3514
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003515 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3516 iterm_programmed, ichg_meas_ma);
3517 /*
3518 * ichg_meas_ma < 0 means battery is drawing current
3519 * ichg_meas_ma > 0 means battery is providing current
3520 */
3521 if (ichg_meas_ma > 0)
3522 return CHG_IN_PROGRESS;
3523
3524 if (ichg_meas_ma * -1 > iterm_programmed)
3525 return CHG_IN_PROGRESS;
3526
3527 return CHG_FINISHED;
3528}
3529
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003530#define COMP_OVERRIDE_HOT_BANK 6
3531#define COMP_OVERRIDE_COLD_BANK 7
3532#define COMP_OVERRIDE_BIT BIT(1)
3533static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3534{
3535 u8 val;
3536 int rc = 0;
3537
3538 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3539
3540 if (flag)
3541 val |= 0x01;
3542
3543 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3544 if (rc < 0)
3545 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3546
3547 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3548 return rc;
3549}
3550
3551static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3552{
3553 u8 val;
3554 int rc = 0;
3555
3556 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3557
3558 if (flag)
3559 val |= 0x01;
3560
3561 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3562 if (rc < 0)
3563 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3564
3565 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3566 return rc;
3567}
3568
3569static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3570{
3571 int rc = 0;
3572 u8 reg;
3573 u8 val;
3574
3575 val = COMP_OVERRIDE_HOT_BANK << 2;
3576 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3577 if (rc < 0) {
3578 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3579 goto cold_init;
3580 }
3581 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3582 if (rc < 0) {
3583 pr_err("Could not read bank %d of override rc = %d\n",
3584 COMP_OVERRIDE_HOT_BANK, rc);
3585 goto cold_init;
3586 }
3587 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3588 /* for now override it as not hot */
3589 rc = pm_chg_override_hot(chip, 0);
3590 if (rc < 0)
3591 pr_err("Could not override hot rc = %d\n", rc);
3592 }
3593
3594cold_init:
3595 val = COMP_OVERRIDE_COLD_BANK << 2;
3596 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3597 if (rc < 0) {
3598 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3599 return;
3600 }
3601 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3602 if (rc < 0) {
3603 pr_err("Could not read bank %d of override rc = %d\n",
3604 COMP_OVERRIDE_COLD_BANK, rc);
3605 return;
3606 }
3607 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3608 /* for now override it as not cold */
3609 rc = pm_chg_override_cold(chip, 0);
3610 if (rc < 0)
3611 pr_err("Could not override cold rc = %d\n", rc);
3612 }
3613}
3614
3615static void btc_override_worker(struct work_struct *work)
3616{
3617 int decidegc;
3618 int temp;
3619 int rc = 0;
3620 struct delayed_work *dwork = to_delayed_work(work);
3621 struct pm8921_chg_chip *chip = container_of(dwork,
3622 struct pm8921_chg_chip, btc_override_work);
3623
3624 if (!chip->btc_override) {
3625 pr_err("called when not enabled\n");
3626 return;
3627 }
3628
3629 decidegc = get_prop_batt_temp(chip);
3630
3631 pr_debug("temp=%d\n", decidegc);
3632
3633 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3634 if (temp) {
3635 if (decidegc < chip->btc_override_hot_decidegc)
3636 /* stop forcing batt hot */
3637 rc = pm_chg_override_hot(chip, 0);
3638 if (rc)
3639 pr_err("Couldnt write 0 to hot comp\n");
3640 } else {
3641 if (decidegc >= chip->btc_override_hot_decidegc)
3642 /* start forcing batt hot */
3643 rc = pm_chg_override_hot(chip, 1);
3644 if (rc && chip->btc_panic_if_cant_stop_chg)
3645 panic("Couldnt override comps to stop chg\n");
3646 }
3647
3648 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3649 if (temp) {
3650 if (decidegc > chip->btc_override_cold_decidegc)
3651 /* stop forcing batt cold */
3652 rc = pm_chg_override_cold(chip, 0);
3653 if (rc)
3654 pr_err("Couldnt write 0 to cold comp\n");
3655 } else {
3656 if (decidegc <= chip->btc_override_cold_decidegc)
3657 /* start forcing batt cold */
3658 rc = pm_chg_override_cold(chip, 1);
3659 if (rc && chip->btc_panic_if_cant_stop_chg)
3660 panic("Couldnt override comps to stop chg\n");
3661 }
3662
3663 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3664 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3665 schedule_delayed_work(&chip->btc_override_work,
3666 round_jiffies_relative(msecs_to_jiffies
3667 (chip->btc_delay_ms)));
3668 return;
3669 }
3670
3671 rc = pm_chg_override_hot(chip, 0);
3672 if (rc)
3673 pr_err("Couldnt write 0 to hot comp\n");
3674 rc = pm_chg_override_cold(chip, 0);
3675 if (rc)
3676 pr_err("Couldnt write 0 to cold comp\n");
3677}
3678
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003679/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003680 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003681 * has happened
3682 *
3683 * If all conditions favouring, if the charge current is
3684 * less than the term current for three consecutive times
3685 * an EOC has happened.
3686 * The wakelock is released if there is no need to reshedule
3687 * - this happens when the battery is removed or EOC has
3688 * happened
3689 */
3690#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003691static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003692{
3693 struct delayed_work *dwork = to_delayed_work(work);
3694 struct pm8921_chg_chip *chip = container_of(dwork,
3695 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003696 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003697 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003698 int vbat_meas_uv, vbat_meas_mv;
3699 int ichg_meas_ua, ichg_meas_ma;
3700 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003701
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003702 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3703 &ichg_meas_ua, &vbat_meas_uv);
3704 vbat_meas_mv = vbat_meas_uv / 1000;
3705 /* rconn_mohm is in milliOhms */
3706 ichg_meas_ma = ichg_meas_ua / 1000;
3707 vbat_batt_terminal_uv = vbat_meas_uv
3708 + ichg_meas_ma
3709 * the_chip->rconn_mohm;
3710
3711 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003712
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003713 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003714 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003715 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003716 }
3717
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003718 if (end == CHG_FINISHED) {
3719 count++;
3720 } else {
3721 count = 0;
3722 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003723
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003724 if (count == CONSECUTIVE_COUNT) {
3725 count = 0;
3726 pr_info("End of Charging\n");
3727
3728 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003729
Amir Samuelovd31ef502011-10-26 14:41:36 +02003730 if (is_ext_charging(chip))
3731 chip->ext_charge_done = true;
3732
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003733 if (chip->is_bat_warm || chip->is_bat_cool)
3734 chip->bms_notify.is_battery_full = 0;
3735 else
3736 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003737 /* declare end of charging by invoking chgdone interrupt */
3738 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003739 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003740 check_temp_thresholds(chip);
3741 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003742 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003743 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003744 round_jiffies_relative(msecs_to_jiffies
3745 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003746 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003747 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003748
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003749eoc_worker_stop:
3750 wake_unlock(&chip->eoc_wake_lock);
3751 /* set the vbatdet back, in case it was changed to trigger charging */
3752 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003753}
3754
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003755/**
3756 * set_disable_status_param -
3757 *
3758 * Internal function to disable battery charging and also disable drawing
3759 * any current from the source. The device is forced to run on a battery
3760 * after this.
3761 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762static int set_disable_status_param(const char *val, struct kernel_param *kp)
3763{
3764 int ret;
3765 struct pm8921_chg_chip *chip = the_chip;
3766
3767 ret = param_set_int(val, kp);
3768 if (ret) {
3769 pr_err("error setting value %d\n", ret);
3770 return ret;
3771 }
3772 pr_info("factory set disable param to %d\n", charging_disabled);
3773 if (chip) {
3774 pm_chg_auto_enable(chip, !charging_disabled);
3775 pm_chg_charge_dis(chip, charging_disabled);
3776 }
3777 return 0;
3778}
3779module_param_call(disabled, set_disable_status_param, param_get_uint,
3780 &charging_disabled, 0644);
3781
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003782static int rconn_mohm;
3783static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3784{
3785 int ret;
3786 struct pm8921_chg_chip *chip = the_chip;
3787
3788 ret = param_set_int(val, kp);
3789 if (ret) {
3790 pr_err("error setting value %d\n", ret);
3791 return ret;
3792 }
3793 if (chip)
3794 chip->rconn_mohm = rconn_mohm;
3795 return 0;
3796}
3797module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3798 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003799/**
3800 * set_thermal_mitigation_level -
3801 *
3802 * Internal function to control battery charging current to reduce
3803 * temperature
3804 */
3805static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3806{
3807 int ret;
3808 struct pm8921_chg_chip *chip = the_chip;
3809
3810 ret = param_set_int(val, kp);
3811 if (ret) {
3812 pr_err("error setting value %d\n", ret);
3813 return ret;
3814 }
3815
3816 if (!chip) {
3817 pr_err("called before init\n");
3818 return -EINVAL;
3819 }
3820
3821 if (!chip->thermal_mitigation) {
3822 pr_err("no thermal mitigation\n");
3823 return -EINVAL;
3824 }
3825
3826 if (thermal_mitigation < 0
3827 || thermal_mitigation >= chip->thermal_levels) {
3828 pr_err("out of bound level selected\n");
3829 return -EINVAL;
3830 }
3831
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003832 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003833 return ret;
3834}
3835module_param_call(thermal_mitigation, set_therm_mitigation_level,
3836 param_get_uint,
3837 &thermal_mitigation, 0644);
3838
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003839static int set_usb_max_current(const char *val, struct kernel_param *kp)
3840{
3841 int ret, mA;
3842 struct pm8921_chg_chip *chip = the_chip;
3843
3844 ret = param_set_int(val, kp);
3845 if (ret) {
3846 pr_err("error setting value %d\n", ret);
3847 return ret;
3848 }
3849 if (chip) {
3850 pr_warn("setting current max to %d\n", usb_max_current);
3851 pm_chg_iusbmax_get(chip, &mA);
3852 if (mA > usb_max_current)
3853 pm8921_charger_vbus_draw(usb_max_current);
3854 return 0;
3855 }
3856 return -EINVAL;
3857}
David Keitelacf57c82012-03-07 18:48:50 -08003858module_param_call(usb_max_current, set_usb_max_current,
3859 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003861static void free_irqs(struct pm8921_chg_chip *chip)
3862{
3863 int i;
3864
3865 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3866 if (chip->pmic_chg_irq[i]) {
3867 free_irq(chip->pmic_chg_irq[i], chip);
3868 chip->pmic_chg_irq[i] = 0;
3869 }
3870}
3871
David Keitel88e1b572012-01-11 11:57:14 -08003872/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003873static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3874{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003876 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003877
3878 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3879 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3880
3881 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003882 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003883 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003884 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003885 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003886 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003887
3888 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3889 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3890 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003891 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003892 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3893 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003894 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003895 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3896 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003897 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003899 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3900 if (usb_chg_current)
3901 /*
3902 * Reissue a vbus draw call only if a battery
3903 * or DC is present. We don't want to brown out the
3904 * device if usb is its only source
3905 */
3906 __pm8921_charger_vbus_draw(usb_chg_current);
3907 usb_chg_current = 0;
3908
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003909 /*
3910 * The bootloader could have started charging, a fastchg interrupt
3911 * might not happen. Check the real time status and if it is fast
3912 * charging invoke the handler so that the eoc worker could be
3913 * started
3914 */
3915 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3916 if (is_fast_chg)
3917 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918
3919 fsm_state = pm_chg_get_fsm_state(chip);
3920 if (is_battery_charging(fsm_state)) {
3921 chip->bms_notify.is_charging = 1;
3922 pm8921_bms_charging_began();
3923 }
3924
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003925 check_battery_valid(chip);
3926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3928 chip->usb_present,
3929 chip->dc_present,
3930 get_prop_batt_present(chip),
3931 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003932
3933 /* Determine which USB trim column to use */
3934 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3935 chip->usb_trim_table = usb_trim_8917_table;
3936 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3937 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003938}
3939
3940struct pm_chg_irq_init_data {
3941 unsigned int irq_id;
3942 char *name;
3943 unsigned long flags;
3944 irqreturn_t (*handler)(int, void *);
3945};
3946
3947#define CHG_IRQ(_id, _flags, _handler) \
3948{ \
3949 .irq_id = _id, \
3950 .name = #_id, \
3951 .flags = _flags, \
3952 .handler = _handler, \
3953}
3954struct pm_chg_irq_init_data chg_irq_data[] = {
3955 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3956 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003957 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3958 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003959 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3960 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003961 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3962 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3963 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3964 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3965 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3966 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3967 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3968 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003969 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3970 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003971 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3972 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3973 batt_removed_irq_handler),
3974 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3975 batttemp_hot_irq_handler),
3976 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3977 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3978 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003979 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3980 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003981 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3982 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003983 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3984 coarse_det_low_irq_handler),
3985 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3986 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3987 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3988 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3989 batfet_irq_handler),
3990 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3991 dcin_valid_irq_handler),
3992 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3993 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003994 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003995};
3996
3997static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3998 struct platform_device *pdev)
3999{
4000 struct resource *res;
4001 int ret, i;
4002
4003 ret = 0;
4004 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
4005
4006 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4007 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
4008 chg_irq_data[i].name);
4009 if (res == NULL) {
4010 pr_err("couldn't find %s\n", chg_irq_data[i].name);
4011 goto err_out;
4012 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004013 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014 ret = request_irq(res->start, chg_irq_data[i].handler,
4015 chg_irq_data[i].flags,
4016 chg_irq_data[i].name, chip);
4017 if (ret < 0) {
4018 pr_err("couldn't request %d (%s) %d\n", res->start,
4019 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004020 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 goto err_out;
4022 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
4024 }
4025 return 0;
4026
4027err_out:
4028 free_irqs(chip);
4029 return -EINVAL;
4030}
4031
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004032#define VREF_BATT_THERM_FORCE_ON BIT(7)
4033static void detect_battery_removal(struct pm8921_chg_chip *chip)
4034{
4035 u8 temp;
4036
4037 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4038 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4039
4040 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4041 /*
4042 * batt therm force on bit is battery backed and is default 0
4043 * The charger sets this bit at init time. If this bit is found
4044 * 0 that means the battery was removed. Tell the bms about it
4045 */
4046 pm8921_bms_invalidate_shutdown_soc();
4047}
4048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004049#define ENUM_TIMER_STOP_BIT BIT(1)
4050#define BOOT_DONE_BIT BIT(6)
4051#define CHG_BATFET_ON_BIT BIT(3)
4052#define CHG_VCP_EN BIT(0)
4053#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4054#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004055#define PM_SUB_REV 0x001
4056#define MIN_CHARGE_CURRENT_MA 350
4057#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4059{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004060 u8 subrev;
4061 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004062
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004063 spin_lock_init(&lpm_lock);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08004064
4065 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4066 rc = __pm8921_apply_19p2mhz_kickstart(chip);
4067 if (rc) {
4068 pr_err("Failed to apply kickstart rc=%d\n", rc);
4069 return rc;
4070 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004071 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004072
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004073 detect_battery_removal(chip);
4074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004075 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004076 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 if (rc) {
4078 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4079 return rc;
4080 }
4081
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004082 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4083
4084 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4085 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4086
4087 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004089 if (rc) {
4090 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004091 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004092 return rc;
4093 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004094 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004095 chip->max_voltage_mv
4096 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 if (rc) {
4098 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004099 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 return rc;
4101 }
4102
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004103 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 if (rc) {
4105 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004106 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 return rc;
4108 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004109
4110 if (chip->safe_current_ma == 0)
4111 chip->safe_current_ma = SAFE_CURRENT_MA;
4112
4113 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 if (rc) {
4115 pr_err("Failed to set max voltage to %d rc=%d\n",
4116 SAFE_CURRENT_MA, rc);
4117 return rc;
4118 }
4119
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004120 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004121 if (rc) {
4122 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4123 return rc;
4124 }
4125
4126 rc = pm_chg_iterm_set(chip, chip->term_current);
4127 if (rc) {
4128 pr_err("Failed to set term current to %d rc=%d\n",
4129 chip->term_current, rc);
4130 return rc;
4131 }
4132
4133 /* Disable the ENUM TIMER */
4134 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4135 ENUM_TIMER_STOP_BIT);
4136 if (rc) {
4137 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4138 return rc;
4139 }
4140
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004141 fcc_uah = pm8921_bms_get_fcc();
4142 if (fcc_uah > 0) {
4143 safety_time = div_s64((s64)fcc_uah * 60,
4144 1000 * MIN_CHARGE_CURRENT_MA);
4145 /* add 20 minutes of buffer time */
4146 safety_time += 20;
4147
4148 /* make sure we do not exceed the maximum programmable time */
4149 if (safety_time > PM8921_CHG_TCHG_MAX)
4150 safety_time = PM8921_CHG_TCHG_MAX;
4151 }
4152
4153 rc = pm_chg_tchg_max_set(chip, safety_time);
4154 if (rc) {
4155 pr_err("Failed to set max time to %d minutes rc=%d\n",
4156 safety_time, rc);
4157 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004158 }
4159
4160 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004161 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004162 if (rc) {
4163 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004164 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004165 return rc;
4166 }
4167 }
4168
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004169 if (chip->vin_min != 0) {
4170 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4171 if (rc) {
4172 pr_err("Failed to set vin min to %d mV rc=%d\n",
4173 chip->vin_min, rc);
4174 return rc;
4175 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004176 } else {
4177 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004178 }
4179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180 rc = pm_chg_disable_wd(chip);
4181 if (rc) {
4182 pr_err("Failed to disable wd rc=%d\n", rc);
4183 return rc;
4184 }
4185
4186 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4187 CHG_BAT_TEMP_DIS_BIT, 0);
4188 if (rc) {
4189 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4190 return rc;
4191 }
4192 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004193 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4194 rc = pm_chg_write(chip,
4195 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4196 else
4197 rc = pm_chg_write(chip,
4198 CHG_BUCK_CLOCK_CTRL, 0x15);
4199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004200 if (rc) {
4201 pr_err("Failed to switch buck clk rc=%d\n", rc);
4202 return rc;
4203 }
4204
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004205 if (chip->trkl_voltage != 0) {
4206 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4207 if (rc) {
4208 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4209 chip->trkl_voltage, rc);
4210 return rc;
4211 }
4212 }
4213
4214 if (chip->weak_voltage != 0) {
4215 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4216 if (rc) {
4217 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4218 chip->weak_voltage, rc);
4219 return rc;
4220 }
4221 }
4222
4223 if (chip->trkl_current != 0) {
4224 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4225 if (rc) {
4226 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4227 chip->trkl_voltage, rc);
4228 return rc;
4229 }
4230 }
4231
4232 if (chip->weak_current != 0) {
4233 rc = pm_chg_iweak_set(chip, chip->weak_current);
4234 if (rc) {
4235 pr_err("Failed to set weak current to %dmA rc=%d\n",
4236 chip->weak_current, rc);
4237 return rc;
4238 }
4239 }
4240
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004241 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4242 if (rc) {
4243 pr_err("Failed to set cold config %d rc=%d\n",
4244 chip->cold_thr, rc);
4245 }
4246
4247 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4248 if (rc) {
4249 pr_err("Failed to set hot config %d rc=%d\n",
4250 chip->hot_thr, rc);
4251 }
4252
Jay Chokshid674a512012-03-15 14:06:04 -07004253 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4254 if (rc) {
4255 pr_err("Failed to set charger LED src config %d rc=%d\n",
4256 chip->led_src_config, rc);
4257 }
4258
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004259 /* Workarounds for die 3.0 */
4260 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4261 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4262 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4263 if (rc) {
4264 pr_err("read failed: addr=%03X, rc=%d\n",
4265 PM_SUB_REV, rc);
4266 return rc;
4267 }
4268 /* Check if die 3.0.1 is present */
4269 if (subrev & 0x1)
4270 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4271 else
4272 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004273 }
4274
David Keitel0789fc62012-06-07 17:43:27 -07004275 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004276 /* Set PM8917 USB_OVP debounce time to 15 ms */
4277 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4278 OVP_DEBOUNCE_TIME, 0x6);
4279 if (rc) {
4280 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4281 return rc;
4282 }
4283
4284 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004285 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004286 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004287 rc = pm_chg_uvd_threshold_set(chip,
4288 chip->uvd_voltage_mv);
4289 if (rc) {
4290 pr_err("Failed to set UVD threshold %drc=%d\n",
4291 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004292 return rc;
4293 }
David Keitel0789fc62012-06-07 17:43:27 -07004294 }
4295 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004296
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004297 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004298
David Keitela3c0d822011-11-03 14:18:52 -07004299 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004300 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004301
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004302 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4303 VREF_BATT_THERM_FORCE_ON);
4304 if (rc)
4305 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307 rc = pm_chg_charge_dis(chip, charging_disabled);
4308 if (rc) {
4309 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4310 return rc;
4311 }
4312
4313 rc = pm_chg_auto_enable(chip, !charging_disabled);
4314 if (rc) {
4315 pr_err("Failed to enable charging rc=%d\n", rc);
4316 return rc;
4317 }
4318
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004319 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4320 /* Clear kickstart */
4321 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4322 if (rc) {
4323 pr_err("Failed to clear kickstart rc=%d\n", rc);
4324 return rc;
4325 }
4326
4327 /* From here the lpm_workaround will be active */
4328 chip->lockup_lpm_wrkarnd = true;
4329
4330 /* Enable LPM */
4331 pm8921_chg_set_lpm(chip, 1);
4332 }
4333
4334 if (chip->lockup_lpm_wrkarnd) {
4335 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4336 if (IS_ERR(chip->vreg_xoadc))
4337 return -ENODEV;
4338
4339 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4340 if (rc < 0) {
4341 pr_err("Failed to set configure HPM rc=%d\n", rc);
4342 return rc;
4343 }
4344
4345 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4346 if (rc) {
4347 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4348 return rc;
4349 }
4350
4351 rc = regulator_enable(chip->vreg_xoadc);
4352 if (rc) {
4353 pr_err("Failed to enable L14 rc=%d\n", rc);
4354 return rc;
4355 }
4356 }
4357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 return 0;
4359}
4360
4361static int get_rt_status(void *data, u64 * val)
4362{
4363 int i = (int)data;
4364 int ret;
4365
4366 /* global irq number is passed in via data */
4367 ret = pm_chg_get_rt_status(the_chip, i);
4368 *val = ret;
4369 return 0;
4370}
4371DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4372
4373static int get_fsm_status(void *data, u64 * val)
4374{
4375 u8 temp;
4376
4377 temp = pm_chg_get_fsm_state(the_chip);
4378 *val = temp;
4379 return 0;
4380}
4381DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4382
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004383static int get_reg_loop(void *data, u64 * val)
4384{
4385 u8 temp;
4386
4387 if (!the_chip) {
4388 pr_err("%s called before init\n", __func__);
4389 return -EINVAL;
4390 }
4391 temp = pm_chg_get_regulation_loop(the_chip);
4392 *val = temp;
4393 return 0;
4394}
4395DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4396
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004397static int get_reg(void *data, u64 * val)
4398{
4399 int addr = (int)data;
4400 int ret;
4401 u8 temp;
4402
4403 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4404 if (ret) {
4405 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4406 addr, temp, ret);
4407 return -EAGAIN;
4408 }
4409 *val = temp;
4410 return 0;
4411}
4412
4413static int set_reg(void *data, u64 val)
4414{
4415 int addr = (int)data;
4416 int ret;
4417 u8 temp;
4418
4419 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004420 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004421 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004422 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004423 addr, temp, ret);
4424 return -EAGAIN;
4425 }
4426 return 0;
4427}
4428DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4429
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004430static int reg_loop;
4431#define MAX_REG_LOOP_CHAR 10
4432static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4433{
4434 u8 temp;
4435
4436 if (!the_chip) {
4437 pr_err("called before init\n");
4438 return -EINVAL;
4439 }
4440 temp = pm_chg_get_regulation_loop(the_chip);
4441 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4442}
4443module_param_call(reg_loop, NULL, get_reg_loop_param,
4444 &reg_loop, 0644);
4445
4446static int max_chg_ma;
4447#define MAX_MA_CHAR 10
4448static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4449{
4450 if (!the_chip) {
4451 pr_err("called before init\n");
4452 return -EINVAL;
4453 }
4454 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4455}
4456module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4457 &max_chg_ma, 0644);
4458static int ibatmax_ma;
4459static int set_ibat_max(const char *val, struct kernel_param *kp)
4460{
4461 int rc;
4462
4463 if (!the_chip) {
4464 pr_err("called before init\n");
4465 return -EINVAL;
4466 }
4467
4468 rc = param_set_int(val, kp);
4469 if (rc) {
4470 pr_err("error setting value %d\n", rc);
4471 return rc;
4472 }
4473
4474 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4475 <= the_chip->ibatmax_max_adj_ma) {
4476 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4477 if (rc) {
4478 pr_err("Failed to set ibatmax rc = %d\n", rc);
4479 return rc;
4480 }
4481 }
4482
4483 return 0;
4484}
4485static int get_ibat_max(char *buf, struct kernel_param *kp)
4486{
4487 int ibat_ma;
4488 int rc;
4489
4490 if (!the_chip) {
4491 pr_err("called before init\n");
4492 return -EINVAL;
4493 }
4494
4495 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4496 if (rc) {
4497 pr_err("ibatmax_get error = %d\n", rc);
4498 return rc;
4499 }
4500
4501 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4502}
4503module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4504 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004505enum {
4506 BAT_WARM_ZONE,
4507 BAT_COOL_ZONE,
4508};
4509static int get_warm_cool(void *data, u64 * val)
4510{
4511 if (!the_chip) {
4512 pr_err("%s called before init\n", __func__);
4513 return -EINVAL;
4514 }
4515 if ((int)data == BAT_WARM_ZONE)
4516 *val = the_chip->is_bat_warm;
4517 if ((int)data == BAT_COOL_ZONE)
4518 *val = the_chip->is_bat_cool;
4519 return 0;
4520}
4521DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4522
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004523static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4524{
4525 int i;
4526
4527 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4528
4529 if (IS_ERR(chip->dent)) {
4530 pr_err("pmic charger couldnt create debugfs dir\n");
4531 return;
4532 }
4533
4534 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4535 (void *)CHG_CNTRL, &reg_fops);
4536 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4537 (void *)CHG_CNTRL_2, &reg_fops);
4538 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4539 (void *)CHG_CNTRL_3, &reg_fops);
4540 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4541 (void *)PBL_ACCESS1, &reg_fops);
4542 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4543 (void *)PBL_ACCESS2, &reg_fops);
4544 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4545 (void *)SYS_CONFIG_1, &reg_fops);
4546 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4547 (void *)SYS_CONFIG_2, &reg_fops);
4548 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4549 (void *)CHG_VDD_MAX, &reg_fops);
4550 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4551 (void *)CHG_VDD_SAFE, &reg_fops);
4552 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4553 (void *)CHG_VBAT_DET, &reg_fops);
4554 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4555 (void *)CHG_IBAT_MAX, &reg_fops);
4556 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4557 (void *)CHG_IBAT_SAFE, &reg_fops);
4558 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4559 (void *)CHG_VIN_MIN, &reg_fops);
4560 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4561 (void *)CHG_VTRICKLE, &reg_fops);
4562 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4563 (void *)CHG_ITRICKLE, &reg_fops);
4564 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4565 (void *)CHG_ITERM, &reg_fops);
4566 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4567 (void *)CHG_TCHG_MAX, &reg_fops);
4568 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4569 (void *)CHG_TWDOG, &reg_fops);
4570 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4571 (void *)CHG_TEMP_THRESH, &reg_fops);
4572 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4573 (void *)CHG_COMP_OVR, &reg_fops);
4574 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4575 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4576 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4577 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4578 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4579 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4580 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4581 (void *)CHG_TEST, &reg_fops);
4582
4583 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4584 &fsm_fops);
4585
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004586 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4587 &reg_loop_fops);
4588
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004589 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4590 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4591 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4592 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004594 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4595 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4596 debugfs_create_file(chg_irq_data[i].name, 0444,
4597 chip->dent,
4598 (void *)chg_irq_data[i].irq_id,
4599 &rt_fops);
4600 }
4601}
4602
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004603static int pm8921_charger_suspend_noirq(struct device *dev)
4604{
4605 int rc;
4606 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4607
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004608 if (chip->lockup_lpm_wrkarnd) {
4609 rc = regulator_disable(chip->vreg_xoadc);
4610 if (rc)
4611 pr_err("Failed to disable L14 rc=%d\n", rc);
4612
4613 rc = pm8921_apply_19p2mhz_kickstart(chip);
4614 if (rc)
4615 pr_err("Failed to apply kickstart rc=%d\n", rc);
4616 }
4617
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004618 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4619 if (rc)
4620 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004621 return 0;
4622}
4623
4624static int pm8921_charger_resume_noirq(struct device *dev)
4625{
4626 int rc;
4627 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4628
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004629 if (chip->lockup_lpm_wrkarnd) {
4630 rc = regulator_enable(chip->vreg_xoadc);
4631 if (rc)
4632 pr_err("Failed to enable L14 rc=%d\n", rc);
4633
4634 rc = pm8921_apply_19p2mhz_kickstart(chip);
4635 if (rc)
4636 pr_err("Failed to apply kickstart rc=%d\n", rc);
4637 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004638
4639 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4640 VREF_BATT_THERM_FORCE_ON);
4641 if (rc)
4642 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4643 return 0;
4644}
4645
David Keitelf2226022011-12-13 15:55:50 -08004646static int pm8921_charger_resume(struct device *dev)
4647{
David Keitelf2226022011-12-13 15:55:50 -08004648 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4649
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004650 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4651 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4652 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4653 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004654
4655 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4656 is_usb_chg_plugged_in(the_chip)))
4657 schedule_delayed_work(&chip->btc_override_work, 0);
4658
David Keitelf2226022011-12-13 15:55:50 -08004659 return 0;
4660}
4661
4662static int pm8921_charger_suspend(struct device *dev)
4663{
David Keitelf2226022011-12-13 15:55:50 -08004664 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4665
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004666 if (chip->btc_override)
4667 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004668
4669 if (is_usb_chg_plugged_in(chip)) {
4670 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4671 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4672 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004673
David Keitelf2226022011-12-13 15:55:50 -08004674 return 0;
4675}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004676static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4677{
4678 int rc = 0;
4679 struct pm8921_chg_chip *chip;
4680 const struct pm8921_charger_platform_data *pdata
4681 = pdev->dev.platform_data;
4682
4683 if (!pdata) {
4684 pr_err("missing platform data\n");
4685 return -EINVAL;
4686 }
4687
4688 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4689 GFP_KERNEL);
4690 if (!chip) {
4691 pr_err("Cannot allocate pm_chg_chip\n");
4692 return -ENOMEM;
4693 }
4694
4695 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004696 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004697 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004698 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004699 chip->alarm_low_mv = pdata->alarm_low_mv;
4700 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004701 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004702 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004703 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004704 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004705 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004706 chip->term_current = pdata->term_current;
4707 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004708 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004709 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4710 chip->batt_id_min = pdata->batt_id_min;
4711 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004712 if (pdata->cool_temp != INT_MIN)
4713 chip->cool_temp_dc = pdata->cool_temp * 10;
4714 else
4715 chip->cool_temp_dc = INT_MIN;
4716
4717 if (pdata->warm_temp != INT_MIN)
4718 chip->warm_temp_dc = pdata->warm_temp * 10;
4719 else
4720 chip->warm_temp_dc = INT_MIN;
4721
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004722 chip->temp_check_period = pdata->temp_check_period;
4723 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004724 /* Assign to corresponding module parameter */
4725 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004726 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4727 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4728 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4729 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004730 chip->trkl_voltage = pdata->trkl_voltage;
4731 chip->weak_voltage = pdata->weak_voltage;
4732 chip->trkl_current = pdata->trkl_current;
4733 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004734 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004735 chip->thermal_mitigation = pdata->thermal_mitigation;
4736 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004738 chip->cold_thr = pdata->cold_thr;
4739 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004740 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004741 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004742 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004743 chip->battery_less_hardware = pdata->battery_less_hardware;
4744 chip->btc_override = pdata->btc_override;
4745 if (chip->btc_override) {
4746 chip->btc_delay_ms = pdata->btc_delay_ms;
4747 chip->btc_override_cold_decidegc
4748 = pdata->btc_override_cold_degc * 10;
4749 chip->btc_override_hot_decidegc
4750 = pdata->btc_override_hot_degc * 10;
4751 chip->btc_panic_if_cant_stop_chg
4752 = pdata->btc_panic_if_cant_stop_chg;
4753 }
4754
4755 if (chip->battery_less_hardware)
4756 charging_disabled = 1;
4757
4758 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4759 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761 rc = pm8921_chg_hw_init(chip);
4762 if (rc) {
4763 pr_err("couldn't init hardware rc=%d\n", rc);
4764 goto free_chip;
4765 }
4766
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004767 if (chip->btc_override)
4768 pm8921_chg_btc_override_init(chip);
4769
4770 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
4771
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004772 chip->usb_psy.name = "usb";
4773 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4774 chip->usb_psy.supplied_to = pm_power_supplied_to;
4775 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4776 chip->usb_psy.properties = pm_power_props_usb;
4777 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4778 chip->usb_psy.get_property = pm_power_get_property_usb;
4779 chip->usb_psy.set_property = pm_power_set_property_usb;
4780 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004781
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004782 chip->dc_psy.name = "pm8921-dc";
4783 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4784 chip->dc_psy.supplied_to = pm_power_supplied_to;
4785 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4786 chip->dc_psy.properties = pm_power_props_mains;
4787 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4788 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004789
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004790 chip->batt_psy.name = "battery";
4791 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4792 chip->batt_psy.properties = msm_batt_power_props;
4793 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4794 chip->batt_psy.get_property = pm_batt_power_get_property;
4795 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796 rc = power_supply_register(chip->dev, &chip->usb_psy);
4797 if (rc < 0) {
4798 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004799 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004800 }
4801
David Keitel6ed71a52012-01-30 12:42:18 -08004802 rc = power_supply_register(chip->dev, &chip->dc_psy);
4803 if (rc < 0) {
4804 pr_err("power_supply_register usb failed rc = %d\n", rc);
4805 goto unregister_usb;
4806 }
4807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808 rc = power_supply_register(chip->dev, &chip->batt_psy);
4809 if (rc < 0) {
4810 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004811 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 }
4813
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004814 platform_set_drvdata(pdev, chip);
4815 the_chip = chip;
4816
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004817 /* set initial state of the USB charger type to UNKNOWN */
4818 power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
4819
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004820 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004821 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004822 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4823 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004824 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004825
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004826 INIT_WORK(&chip->bms_notify.work, bms_notify);
4827 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4828
4829 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4830 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 rc = request_irqs(chip, pdev);
4833 if (rc) {
4834 pr_err("couldn't register interrupts rc=%d\n", rc);
4835 goto unregister_batt;
4836 }
4837
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004838 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004839 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004840 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004841 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843 create_debugfs_entries(chip);
4844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004845 /* determine what state the charger is in */
4846 determine_initial_state(chip);
4847
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004848 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004849 schedule_delayed_work(&chip->update_heartbeat_work,
4850 round_jiffies_relative(msecs_to_jiffies
4851 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004852 return 0;
4853
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004854unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004855 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004856 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004857unregister_dc:
4858 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004859unregister_usb:
4860 power_supply_unregister(&chip->usb_psy);
4861free_chip:
4862 kfree(chip);
4863 return rc;
4864}
4865
4866static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4867{
4868 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4869
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004870 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004871 free_irqs(chip);
4872 platform_set_drvdata(pdev, NULL);
4873 the_chip = NULL;
4874 kfree(chip);
4875 return 0;
4876}
David Keitelf2226022011-12-13 15:55:50 -08004877static const struct dev_pm_ops pm8921_pm_ops = {
4878 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004879 .suspend_noirq = pm8921_charger_suspend_noirq,
4880 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004881 .resume = pm8921_charger_resume,
4882};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004883static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004884 .probe = pm8921_charger_probe,
4885 .remove = __devexit_p(pm8921_charger_remove),
4886 .driver = {
4887 .name = PM8921_CHARGER_DEV_NAME,
4888 .owner = THIS_MODULE,
4889 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004890 },
4891};
4892
4893static int __init pm8921_charger_init(void)
4894{
4895 return platform_driver_register(&pm8921_charger_driver);
4896}
4897
4898static void __exit pm8921_charger_exit(void)
4899{
4900 platform_driver_unregister(&pm8921_charger_driver);
4901}
4902
4903late_initcall(pm8921_charger_init);
4904module_exit(pm8921_charger_exit);
4905
4906MODULE_LICENSE("GPL v2");
4907MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4908MODULE_VERSION("1.0");
4909MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);