blob: 061be695b31e3a9b9d49a08c6a63a871f8333e65 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297};
298
David Keitelacf57c82012-03-07 18:48:50 -0800299/* user space parameter to limit usb current */
300static unsigned int usb_max_current;
301/*
302 * usb_target_ma is used for wall charger
303 * adaptive input current limiting only. Use
304 * pm_iusbmax_get() to get current maximum usb current setting.
305 */
306static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700308static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
310static struct pm8921_chg_chip *the_chip;
311
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700312static DEFINE_SPINLOCK(lpm_lock);
313#define LPM_ENABLE_BIT BIT(2)
314static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
315{
316 int rc;
317 u8 reg;
318
319 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
320 if (rc) {
321 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
322 CHG_CNTRL, rc);
323 return rc;
324 }
325 reg &= ~LPM_ENABLE_BIT;
326 reg |= (enable ? LPM_ENABLE_BIT : 0);
327
328 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
329 if (rc) {
330 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
331 CHG_CNTRL, rc);
332 return rc;
333 }
334
335 return rc;
336}
337
338static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
339{
340 int rc;
341 unsigned long flags = 0;
342
343 /* Disable LPM */
344 if (chip->lockup_lpm_wrkarnd) {
345 spin_lock_irqsave(&lpm_lock, flags);
346
347 /*
348 * This write could have initiated right after a previous write.
349 * Allow time to settle to go in to lpm from the previous write
350 */
351 udelay(200);
352 rc = pm8921_chg_set_lpm(chip, 0);
353 if (rc)
354 goto lpm_err;
355
356 /* Wait to come out of LPM */
357 udelay(200);
358 }
359
360 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
361 if (rc) {
362 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
363 goto lpm_err;
364 }
365
366 /* Enable LPM */
367 if (chip->lockup_lpm_wrkarnd)
368 rc = pm8921_chg_set_lpm(chip, 1);
369
370lpm_err:
371 if (chip->lockup_lpm_wrkarnd)
372 spin_unlock_irqrestore(&lpm_lock, flags);
373
374 return rc;
375}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
378 u8 mask, u8 val)
379{
380 int rc;
381 u8 reg;
382
383 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
384 if (rc) {
385 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
386 return rc;
387 }
388 reg &= ~mask;
389 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700390 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700392 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 return rc;
394 }
395 return 0;
396}
397
David Keitelcf867232012-01-27 18:40:12 -0800398static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
399{
400 return pm8xxx_read_irq_stat(chip->dev->parent,
401 chip->pmic_chg_irq[irq_id]);
402}
403
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700404static int is_chg_on_bat(struct pm8921_chg_chip *chip)
405{
406 return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
407 || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
408}
409
410static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
411 int bypass)
412{
413 int rc;
414
415 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
416 if (rc) {
417 pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
418 }
419}
420
David Keitelcf867232012-01-27 18:40:12 -0800421/* Treat OverVoltage/UnderVoltage as source missing */
422static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
423{
424 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
425}
426
427/* Treat OverVoltage/UnderVoltage as source missing */
428static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
429{
430 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
431}
432
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700433static int is_batfet_closed(struct pm8921_chg_chip *chip)
434{
435 return pm_chg_get_rt_status(chip, BATFET_IRQ);
436}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437#define CAPTURE_FSM_STATE_CMD 0xC2
438#define READ_BANK_7 0x70
439#define READ_BANK_4 0x40
440static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
441{
442 u8 temp;
443 int err, ret = 0;
444
445 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700446 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 if (err) {
448 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
449 return err;
450 }
451
452 temp = READ_BANK_7;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700453 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 if (err) {
455 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
456 return err;
457 }
458
459 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
460 if (err) {
461 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
462 return err;
463 }
464 /* get the lower 4 bits */
465 ret = temp & 0xF;
466
467 temp = READ_BANK_4;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700468 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 if (err) {
470 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
471 return err;
472 }
473
474 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
475 if (err) {
476 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
477 return err;
478 }
479 /* get the upper 1 bit */
480 ret |= (temp & 0x1) << 4;
481 return ret;
482}
483
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700484#define READ_BANK_6 0x60
485static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
486{
487 u8 temp;
488 int err;
489
490 temp = READ_BANK_6;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700491 err = pm_chg_write(chip, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700492 if (err) {
493 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
494 return err;
495 }
496
497 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
498 if (err) {
499 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
500 return err;
501 }
502
503 /* return the lower 4 bits */
504 return temp & CHG_ALL_LOOPS;
505}
506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507#define CHG_USB_SUSPEND_BIT BIT(2)
508static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
509{
510 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
511 enable ? CHG_USB_SUSPEND_BIT : 0);
512}
513
514#define CHG_EN_BIT BIT(7)
515static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
516{
517 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
518 enable ? CHG_EN_BIT : 0);
519}
520
David Keitel753ec8d2011-11-02 10:56:37 -0700521#define CHG_FAILED_CLEAR BIT(0)
522#define ATC_FAILED_CLEAR BIT(1)
523static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
524{
525 int rc;
526
527 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
528 clear ? ATC_FAILED_CLEAR : 0);
529 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
530 clear ? CHG_FAILED_CLEAR : 0);
531 return rc;
532}
533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534#define CHG_CHARGE_DIS_BIT BIT(1)
535static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
536{
537 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
538 disable ? CHG_CHARGE_DIS_BIT : 0);
539}
540
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800541static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
542{
543 u8 temp;
544
545 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
546 return temp & CHG_CHARGE_DIS_BIT;
547}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548#define PM8921_CHG_V_MIN_MV 3240
549#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800550#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551#define PM8921_CHG_VDDMAX_MAX 4500
552#define PM8921_CHG_VDDMAX_MIN 3400
553#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800554static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800556 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800557 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800559 if (voltage < PM8921_CHG_VDDMAX_MIN
560 || voltage > PM8921_CHG_VDDMAX_MAX) {
561 pr_err("bad mV=%d asked to set\n", voltage);
562 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 }
David Keitelcf867232012-01-27 18:40:12 -0800564
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800565 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
566
567 remainder = voltage % 20;
568 if (remainder >= 10) {
569 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
570 }
571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700573 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574}
575
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700576static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
577{
578 u8 temp;
579 int rc;
580
581 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
582 if (rc) {
583 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700584 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700585 return rc;
586 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800587 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
588 + PM8921_CHG_V_MIN_MV;
589 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
590 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700591 return 0;
592}
593
David Keitelcf867232012-01-27 18:40:12 -0800594static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
595{
596 int current_mv, ret, steps, i;
597 bool increase;
598
599 ret = 0;
600
601 if (voltage < PM8921_CHG_VDDMAX_MIN
602 || voltage > PM8921_CHG_VDDMAX_MAX) {
603 pr_err("bad mV=%d asked to set\n", voltage);
604 return -EINVAL;
605 }
606
607 ret = pm_chg_vddmax_get(chip, &current_mv);
608 if (ret) {
609 pr_err("Failed to read vddmax rc=%d\n", ret);
610 return -EINVAL;
611 }
612 if (current_mv == voltage)
613 return 0;
614
615 /* Only change in increments when USB is present */
616 if (is_usb_chg_plugged_in(chip)) {
617 if (current_mv < voltage) {
618 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
619 increase = true;
620 } else {
621 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
622 increase = false;
623 }
624 for (i = 0; i < steps; i++) {
625 if (increase)
626 current_mv += PM8921_CHG_V_STEP_MV;
627 else
628 current_mv -= PM8921_CHG_V_STEP_MV;
629 ret |= __pm_chg_vddmax_set(chip, current_mv);
630 }
631 }
632 ret |= __pm_chg_vddmax_set(chip, voltage);
633 return ret;
634}
635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636#define PM8921_CHG_VDDSAFE_MIN 3400
637#define PM8921_CHG_VDDSAFE_MAX 4500
638static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
639{
640 u8 temp;
641
642 if (voltage < PM8921_CHG_VDDSAFE_MIN
643 || voltage > PM8921_CHG_VDDSAFE_MAX) {
644 pr_err("bad mV=%d asked to set\n", voltage);
645 return -EINVAL;
646 }
647 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
648 pr_debug("voltage=%d setting %02x\n", voltage, temp);
649 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
650}
651
652#define PM8921_CHG_VBATDET_MIN 3240
653#define PM8921_CHG_VBATDET_MAX 5780
654static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
655{
656 u8 temp;
657
658 if (voltage < PM8921_CHG_VBATDET_MIN
659 || voltage > PM8921_CHG_VBATDET_MAX) {
660 pr_err("bad mV=%d asked to set\n", voltage);
661 return -EINVAL;
662 }
663 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
664 pr_debug("voltage=%d setting %02x\n", voltage, temp);
665 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
666}
667
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700668#define PM8921_CHG_VINMIN_MIN_MV 3800
669#define PM8921_CHG_VINMIN_STEP_MV 100
670#define PM8921_CHG_VINMIN_USABLE_MAX 6500
671#define PM8921_CHG_VINMIN_USABLE_MIN 4300
672#define PM8921_CHG_VINMIN_MASK 0x1F
673static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
674{
675 u8 temp;
676
677 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
678 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
679 pr_err("bad mV=%d asked to set\n", voltage);
680 return -EINVAL;
681 }
682 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
683 pr_debug("voltage=%d setting %02x\n", voltage, temp);
684 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
685 temp);
686}
687
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800688static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
689{
690 u8 temp;
691 int rc, voltage_mv;
692
693 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
694 temp &= PM8921_CHG_VINMIN_MASK;
695
696 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
697 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
698
699 return voltage_mv;
700}
701
David Keitel0789fc62012-06-07 17:43:27 -0700702#define PM8917_USB_UVD_MIN_MV 3850
703#define PM8917_USB_UVD_MAX_MV 4350
704#define PM8917_USB_UVD_STEP_MV 100
705#define PM8917_USB_UVD_MASK 0x7
706static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
707{
708 u8 temp;
709
710 if (thresh_mv < PM8917_USB_UVD_MIN_MV
711 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
712 pr_err("bad mV=%d asked to set\n", thresh_mv);
713 return -EINVAL;
714 }
715 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
716 return pm_chg_masked_write(chip, OVP_USB_UVD,
717 PM8917_USB_UVD_MASK, temp);
718}
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700721#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722#define PM8921_CHG_I_MIN_MA 225
723#define PM8921_CHG_I_STEP_MA 50
724#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700725static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
726{
727 u8 temp;
728 int rc;
729
730 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
731 if (rc) {
732 pr_err("rc = %d while reading ibat max\n", rc);
733 *ibat_ma = 0;
734 return rc;
735 }
736 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
737 + PM8921_CHG_I_MIN_MA;
738 return 0;
739}
740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
742{
743 u8 temp;
744
745 if (chg_current < PM8921_CHG_IBATMAX_MIN
746 || chg_current > PM8921_CHG_IBATMAX_MAX) {
747 pr_err("bad mA=%d asked to set\n", chg_current);
748 return -EINVAL;
749 }
750 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
751 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
752}
753
754#define PM8921_CHG_IBATSAFE_MIN 225
755#define PM8921_CHG_IBATSAFE_MAX 3375
756static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
757{
758 u8 temp;
759
760 if (chg_current < PM8921_CHG_IBATSAFE_MIN
761 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
762 pr_err("bad mA=%d asked to set\n", chg_current);
763 return -EINVAL;
764 }
765 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
766 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
767 PM8921_CHG_I_MASK, temp);
768}
769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700771#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772#define PM8921_CHG_ITERM_STEP_MA 10
773#define PM8921_CHG_ITERM_MASK 0xF
774static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
775{
776 u8 temp;
777
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700778 if (chg_current < PM8921_CHG_ITERM_MIN_MA
779 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 pr_err("bad mA=%d asked to set\n", chg_current);
781 return -EINVAL;
782 }
783
784 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
785 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700786 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 temp);
788}
789
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700790static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
791{
792 u8 temp;
793 int rc;
794
795 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
796 if (rc) {
797 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700798 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700799 return rc;
800 }
801 temp &= PM8921_CHG_ITERM_MASK;
802 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
803 + PM8921_CHG_ITERM_MIN_MA;
804 return 0;
805}
806
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800807struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700808 int usb_ma;
809 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800810};
811
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700812/* USB Trim tables */
813static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
814 0x0,
815 0x0,
816 -0x9,
817 0x0,
818 -0xD,
819 0x0,
820 -0x10,
821 -0x11,
822 0x0,
823 0x0,
824 -0x25,
825 0x0,
826 -0x28,
827 0x0,
828 -0x32,
829 0x0
830};
831
832static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
833 0x0,
834 0x0,
835 0xA,
836 0xC,
837 0x10,
838 0x10,
839 0x13,
840 0x14,
841 0x13,
842 0x3,
843 0x1A,
844 0x1D,
845 0x1D,
846 0x21,
847 0x24,
848 0x26
849};
850
851/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800852static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700853 {100, 0x0},
854 {200, 0x1},
855 {500, 0x2},
856 {600, 0x3},
857 {700, 0x4},
858 {800, 0x5},
859 {850, 0x6},
860 {900, 0x8},
861 {950, 0x7},
862 {1000, 0x9},
863 {1100, 0xA},
864 {1200, 0xB},
865 {1300, 0xC},
866 {1400, 0xD},
867 {1500, 0xE},
868 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800869};
870
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700871#define REG_SBI_CONFIG 0x04F
872#define PAGE3_ENABLE_MASK 0x6
873#define USB_OVP_TRIM_MASK 0x3F
874#define USB_OVP_TRIM_PM8917_MASK 0x7F
875#define USB_OVP_TRIM_MIN 0x00
876#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
877#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
878#define REG_USB_OVP_TRIM_PM8917 0x2B5
879#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
880static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
881{
882 u8 temp, sbi_config, msb, lsb, mask;
883 s8 trim;
884 int rc = 0;
885 static u8 usb_trim_reg_orig = 0xFF;
886
887 /* No trim data for PM8921 */
888 if (!chip->usb_trim_table)
889 return 0;
890
891 if (usb_trim_reg_orig == 0xFF) {
892 rc = pm8xxx_readb(chip->dev->parent,
893 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
894 if (rc) {
895 pr_err("error = %d reading sbi config reg\n", rc);
896 return rc;
897 }
898
899 rc = pm8xxx_readb(chip->dev->parent,
900 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
901 if (rc) {
902 pr_err("error = %d reading sbi config reg\n", rc);
903 return rc;
904 }
905
906 msb = msb >> 5;
907 lsb = lsb >> 5;
908 usb_trim_reg_orig = msb << 3 | lsb;
909
910 if (pm8xxx_get_version(chip->dev->parent)
911 == PM8XXX_VERSION_8917) {
912 rc = pm8xxx_readb(chip->dev->parent,
913 REG_USB_OVP_TRIM_PM8917, &msb);
914 if (rc) {
915 pr_err("error = %d reading config reg\n", rc);
916 return rc;
917 }
918
919 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
920 usb_trim_reg_orig |= msb << 6;
921 }
922 }
923
924 /* use the original trim value */
925 trim = usb_trim_reg_orig;
926
927 trim += chip->usb_trim_table[index];
928 if (trim < 0)
929 trim = 0;
930
931 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
932 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
933
934 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
935 if (rc) {
936 pr_err("error = %d reading sbi config reg\n", rc);
937 return rc;
938 }
939
940 temp = sbi_config | PAGE3_ENABLE_MASK;
941 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
942 if (rc) {
943 pr_err("error = %d writing sbi config reg\n", rc);
944 return rc;
945 }
946
947 mask = USB_OVP_TRIM_MASK;
948
949 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
950 mask = USB_OVP_TRIM_PM8917_MASK;
951
952 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
953 if (rc) {
954 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
955 return rc;
956 }
957
958 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
959 if (rc) {
960 pr_err("error = %d writing sbi config reg\n", rc);
961 return rc;
962 }
963 return rc;
964}
965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700967#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968#define PM8921_CHG_IUSB_MAX 7
969#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700970#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700971static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700973 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700974 int rc;
975
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700976 reg_val = usb_ma_table[index].value >> 1;
977 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700979 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
980 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981 return -EINVAL;
982 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700983 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
984
985 /* IUSB_FINE_RES */
986 if (chip->iusb_fine_res) {
987 /* Clear IUSB_FINE_RES bit to avoid overshoot */
988 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
989 PM8917_IUSB_FINE_RES, 0);
990
991 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
992 PM8921_CHG_IUSB_MASK, temp);
993
994 if (rc) {
995 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
996 return rc;
997 }
998
999 if (fineres) {
1000 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1001 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001002 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001003 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
1004 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001005 return rc;
1006 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001007 }
1008 } else {
1009 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
1010 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001011 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001012 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001013 return rc;
1014 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001015 }
1016
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001017 rc = pm_chg_usb_trim(chip, index);
1018 if (rc)
1019 pr_err("unable to set usb trim rc = %d\n", rc);
1020
David Keitel38bdd4f2012-04-19 15:39:13 -07001021 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022}
1023
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001024static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
1025{
David Keitel38bdd4f2012-04-19 15:39:13 -07001026 u8 temp, fineres;
1027 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001028
David Keitel38bdd4f2012-04-19 15:39:13 -07001029 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001030 *mA = 0;
1031 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
1032 if (rc) {
1033 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1034 return rc;
1035 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001036
1037 if (chip->iusb_fine_res) {
1038 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1039 if (rc) {
1040 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1041 return rc;
1042 }
1043 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001044 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001045 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1046
1047 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1048 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1049 if (usb_ma_table[i].value == temp)
1050 break;
1051 }
1052
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001053 if (i < 0) {
1054 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1055 i = 0;
1056 }
1057
David Keitel38bdd4f2012-04-19 15:39:13 -07001058 *mA = usb_ma_table[i].usb_ma;
1059
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001060 return rc;
1061}
1062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063#define PM8921_CHG_WD_MASK 0x1F
1064static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1065{
1066 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001067 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1068}
1069
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001070#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001071#define PM8921_CHG_TCHG_MIN 4
1072#define PM8921_CHG_TCHG_MAX 512
1073#define PM8921_CHG_TCHG_STEP 4
1074static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1075{
1076 u8 temp;
1077
1078 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1079 pr_err("bad max minutes =%d asked to set\n", minutes);
1080 return -EINVAL;
1081 }
1082
1083 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1084 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1085 temp);
1086}
1087
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001088#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001089#define PM8921_CHG_TTRKL_MIN 1
1090#define PM8921_CHG_TTRKL_MAX 64
1091static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1092{
1093 u8 temp;
1094
1095 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1096 pr_err("bad max minutes =%d asked to set\n", minutes);
1097 return -EINVAL;
1098 }
1099
1100 temp = minutes - 1;
1101 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1102 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103}
1104
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001105#define PM8921_CHG_VTRKL_MIN_MV 2050
1106#define PM8921_CHG_VTRKL_MAX_MV 2800
1107#define PM8921_CHG_VTRKL_STEP_MV 50
1108#define PM8921_CHG_VTRKL_SHIFT 4
1109#define PM8921_CHG_VTRKL_MASK 0xF0
1110static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1111{
1112 u8 temp;
1113
1114 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1115 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1116 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1117 return -EINVAL;
1118 }
1119
1120 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1121 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1122 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1123 temp);
1124}
1125
1126#define PM8921_CHG_VWEAK_MIN_MV 2100
1127#define PM8921_CHG_VWEAK_MAX_MV 3600
1128#define PM8921_CHG_VWEAK_STEP_MV 100
1129#define PM8921_CHG_VWEAK_MASK 0x0F
1130static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1131{
1132 u8 temp;
1133
1134 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1135 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1136 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1137 return -EINVAL;
1138 }
1139
1140 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1141 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1142 temp);
1143}
1144
1145#define PM8921_CHG_ITRKL_MIN_MA 50
1146#define PM8921_CHG_ITRKL_MAX_MA 200
1147#define PM8921_CHG_ITRKL_MASK 0x0F
1148#define PM8921_CHG_ITRKL_STEP_MA 10
1149static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1150{
1151 u8 temp;
1152
1153 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1154 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1155 pr_err("bad current = %dmA asked to set\n", milliamps);
1156 return -EINVAL;
1157 }
1158
1159 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1160
1161 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1162 temp);
1163}
1164
1165#define PM8921_CHG_IWEAK_MIN_MA 325
1166#define PM8921_CHG_IWEAK_MAX_MA 525
1167#define PM8921_CHG_IWEAK_SHIFT 7
1168#define PM8921_CHG_IWEAK_MASK 0x80
1169static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1170{
1171 u8 temp;
1172
1173 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1174 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1175 pr_err("bad current = %dmA asked to set\n", milliamps);
1176 return -EINVAL;
1177 }
1178
1179 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1180 temp = 0;
1181 else
1182 temp = 1;
1183
1184 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1185 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1186 temp);
1187}
1188
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001189#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1190#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1191static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1192 enum pm8921_chg_cold_thr cold_thr)
1193{
1194 u8 temp;
1195
1196 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1197 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1198 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1199 PM8921_CHG_BATT_TEMP_THR_COLD,
1200 temp);
1201}
1202
1203#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1204#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1205static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1206 enum pm8921_chg_hot_thr hot_thr)
1207{
1208 u8 temp;
1209
1210 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1211 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1212 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1213 PM8921_CHG_BATT_TEMP_THR_HOT,
1214 temp);
1215}
1216
Jay Chokshid674a512012-03-15 14:06:04 -07001217#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1218#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1219static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1220 enum pm8921_chg_led_src_config led_src_config)
1221{
1222 u8 temp;
1223
1224 if (led_src_config < LED_SRC_GND ||
1225 led_src_config > LED_SRC_BYPASS)
1226 return -EINVAL;
1227
1228 if (led_src_config == LED_SRC_BYPASS)
1229 return 0;
1230
1231 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1232
1233 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1234 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1235}
1236
David Keitel8c5201a2012-02-24 16:08:54 -08001237
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001238static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1239{
1240 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001241 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001242
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001243 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001244 if (rc) {
1245 pr_err("error reading batt id channel = %d, rc = %d\n",
1246 chip->vbat_channel, rc);
1247 return rc;
1248 }
1249 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1250 result.measurement);
1251 return result.physical;
1252}
1253
1254static int is_battery_valid(struct pm8921_chg_chip *chip)
1255{
1256 int64_t rc;
1257
1258 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1259 return 1;
1260
1261 rc = read_battery_id(chip);
1262 if (rc < 0) {
1263 pr_err("error reading batt id channel = %d, rc = %lld\n",
1264 chip->vbat_channel, rc);
1265 /* assume battery id is valid when adc error happens */
1266 return 1;
1267 }
1268
1269 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1270 pr_err("batt_id phy =%lld is not valid\n", rc);
1271 return 0;
1272 }
1273 return 1;
1274}
1275
1276static void check_battery_valid(struct pm8921_chg_chip *chip)
1277{
1278 if (is_battery_valid(chip) == 0) {
1279 pr_err("batt_id not valid, disbling charging\n");
1280 pm_chg_auto_enable(chip, 0);
1281 } else {
1282 pm_chg_auto_enable(chip, !charging_disabled);
1283 }
1284}
1285
1286static void battery_id_valid(struct work_struct *work)
1287{
1288 struct pm8921_chg_chip *chip = container_of(work,
1289 struct pm8921_chg_chip, battery_id_valid_work);
1290
1291 check_battery_valid(chip);
1292}
1293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1295{
1296 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1297 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1298 enable_irq(chip->pmic_chg_irq[interrupt]);
1299 }
1300}
1301
1302static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1303{
1304 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1305 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1306 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1307 }
1308}
1309
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001310static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1311{
1312 return test_bit(interrupt, chip->enabled_irqs);
1313}
1314
Amir Samuelovd31ef502011-10-26 14:41:36 +02001315static bool is_ext_charging(struct pm8921_chg_chip *chip)
1316{
David Keitel88e1b572012-01-11 11:57:14 -08001317 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001318
David Keitel88e1b572012-01-11 11:57:14 -08001319 if (!chip->ext_psy)
1320 return false;
1321 if (chip->ext_psy->get_property(chip->ext_psy,
1322 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1323 return false;
1324 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1325 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001326
1327 return false;
1328}
1329
1330static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1331{
David Keitel88e1b572012-01-11 11:57:14 -08001332 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001333
David Keitel88e1b572012-01-11 11:57:14 -08001334 if (!chip->ext_psy)
1335 return false;
1336 if (chip->ext_psy->get_property(chip->ext_psy,
1337 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1338 return false;
1339 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001340 return true;
1341
1342 return false;
1343}
1344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345static int is_battery_charging(int fsm_state)
1346{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001347 if (is_ext_charging(the_chip))
1348 return 1;
1349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 switch (fsm_state) {
1351 case FSM_STATE_ATC_2A:
1352 case FSM_STATE_ATC_2B:
1353 case FSM_STATE_ON_CHG_AND_BAT_6:
1354 case FSM_STATE_FAST_CHG_7:
1355 case FSM_STATE_TRKL_CHG_8:
1356 return 1;
1357 }
1358 return 0;
1359}
1360
1361static void bms_notify(struct work_struct *work)
1362{
1363 struct bms_notify *n = container_of(work, struct bms_notify, work);
1364
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001365 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001367 } else {
1368 pm8921_bms_charging_end(n->is_battery_full);
1369 n->is_battery_full = 0;
1370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371}
1372
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001373static void bms_notify_check(struct pm8921_chg_chip *chip)
1374{
1375 int fsm_state, new_is_charging;
1376
1377 fsm_state = pm_chg_get_fsm_state(chip);
1378 new_is_charging = is_battery_charging(fsm_state);
1379
1380 if (chip->bms_notify.is_charging ^ new_is_charging) {
1381 chip->bms_notify.is_charging = new_is_charging;
1382 schedule_work(&(chip->bms_notify.work));
1383 }
1384}
1385
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001386static enum power_supply_property pm_power_props_usb[] = {
1387 POWER_SUPPLY_PROP_PRESENT,
1388 POWER_SUPPLY_PROP_ONLINE,
1389 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001390 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001391};
1392
1393static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001395 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396};
1397
1398static char *pm_power_supplied_to[] = {
1399 "battery",
1400};
1401
David Keitel6ed71a52012-01-30 12:42:18 -08001402#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001403static int pm_power_get_property_mains(struct power_supply *psy,
1404 enum power_supply_property psp,
1405 union power_supply_propval *val)
1406{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001407 int type;
1408
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001409 /* Check if called before init */
1410 if (!the_chip)
1411 return -EINVAL;
1412
1413 switch (psp) {
1414 case POWER_SUPPLY_PROP_PRESENT:
1415 case POWER_SUPPLY_PROP_ONLINE:
1416 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001417
1418 if (the_chip->has_dc_supply) {
1419 val->intval = 1;
1420 return 0;
1421 }
1422
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001423 if (the_chip->dc_present) {
1424 val->intval = 1;
1425 return 0;
1426 }
1427
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001428 type = the_chip->usb_psy.type;
1429 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1430 type == POWER_SUPPLY_TYPE_USB_ACA ||
1431 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001432 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001433
1434 break;
1435 default:
1436 return -EINVAL;
1437 }
1438 return 0;
1439}
1440
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001441static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1442{
1443 int rc;
1444
1445 if (!chip->host_mode)
1446 return 0;
1447
1448 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001449 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001450 if (rc < 0) {
1451 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1452 return rc;
1453 }
1454
1455 chip->host_mode = 0;
1456
1457 return 0;
1458}
1459
1460static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1461{
1462 int rc;
1463
1464 if (chip->host_mode)
1465 return 0;
1466
1467 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001468 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001469 if (rc < 0) {
1470 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1471 return rc;
1472 }
1473
1474 chip->host_mode = 1;
1475
1476 return 0;
1477}
1478
1479static int pm_power_set_property_usb(struct power_supply *psy,
1480 enum power_supply_property psp,
1481 const union power_supply_propval *val)
1482{
1483 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001484 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001485 return -EINVAL;
1486
1487 switch (psp) {
1488 case POWER_SUPPLY_PROP_SCOPE:
1489 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001490 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001491 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001492 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001493 else
1494 return -EINVAL;
1495 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001496 case POWER_SUPPLY_PROP_TYPE:
1497 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001498 default:
1499 return -EINVAL;
1500 }
1501 return 0;
1502}
1503
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001504static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 enum power_supply_property psp,
1506 union power_supply_propval *val)
1507{
David Keitel6ed71a52012-01-30 12:42:18 -08001508 int current_max;
1509
1510 /* Check if called before init */
1511 if (!the_chip)
1512 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513
1514 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001515 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001516 if (pm_is_chg_charge_dis(the_chip)) {
1517 val->intval = 0;
1518 } else {
1519 pm_chg_iusbmax_get(the_chip, &current_max);
1520 val->intval = current_max;
1521 }
David Keitel6ed71a52012-01-30 12:42:18 -08001522 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001524 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001525 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001526
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001527 if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001528 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001531
1532 case POWER_SUPPLY_PROP_SCOPE:
1533 if (the_chip->host_mode)
1534 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1535 else
1536 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1537 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538 default:
1539 return -EINVAL;
1540 }
1541 return 0;
1542}
1543
1544static enum power_supply_property msm_batt_power_props[] = {
1545 POWER_SUPPLY_PROP_STATUS,
1546 POWER_SUPPLY_PROP_CHARGE_TYPE,
1547 POWER_SUPPLY_PROP_HEALTH,
1548 POWER_SUPPLY_PROP_PRESENT,
1549 POWER_SUPPLY_PROP_TECHNOLOGY,
1550 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1551 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1552 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1553 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001554 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001555 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001556 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001557 POWER_SUPPLY_PROP_CHARGE_FULL,
1558 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559};
1560
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001561static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562{
1563 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001564 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001566 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 if (rc) {
1568 pr_err("error reading adc channel = %d, rc = %d\n",
1569 chip->vbat_channel, rc);
1570 return rc;
1571 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001572 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 result.measurement);
1574 return (int)result.physical;
1575}
1576
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001577static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1578{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001579 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1580 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1581 unsigned int low_voltage = chip->min_voltage_mv;
1582 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001583
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001584 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001585 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001586 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001587 return 100;
1588 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001589 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001590 / (high_voltage - low_voltage);
1591}
1592
David Keitel4f9397b2012-04-16 11:46:16 -07001593static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1594{
1595 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1596}
1597
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001598static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1599{
1600 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1601 int fsm_state = pm_chg_get_fsm_state(chip);
1602 int i;
1603
1604 if (chip->ext_psy) {
1605 if (chip->ext_charge_done)
1606 return POWER_SUPPLY_STATUS_FULL;
1607 if (chip->ext_charging)
1608 return POWER_SUPPLY_STATUS_CHARGING;
1609 }
1610
1611 for (i = 0; i < ARRAY_SIZE(map); i++)
1612 if (map[i].fsm_state == fsm_state)
1613 batt_state = map[i].batt_state;
1614
1615 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1616 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1617 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1618 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1619 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1620
1621 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1622 }
1623 return batt_state;
1624}
1625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1627{
David Keitel4f9397b2012-04-16 11:46:16 -07001628 int percent_soc;
1629
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001630 if (chip->battery_less_hardware)
1631 return 100;
1632
David Keitel4f9397b2012-04-16 11:46:16 -07001633 if (!get_prop_batt_present(chip))
1634 percent_soc = voltage_based_capacity(chip);
1635 else
1636 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001637
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001638 if (percent_soc == -ENXIO)
1639 percent_soc = voltage_based_capacity(chip);
1640
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001641 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001642 pr_warn_ratelimited("low battery charge = %d%%\n",
1643 percent_soc);
1644
1645 if (percent_soc <= chip->resume_charge_percent
1646 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1647 pr_debug("soc fell below %d. charging enabled.\n",
1648 chip->resume_charge_percent);
1649 if (chip->is_bat_warm)
1650 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1651 chip->is_bat_warm,
1652 chip->resume_charge_percent);
1653 else if (chip->is_bat_cool)
1654 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1655 chip->is_bat_cool,
1656 chip->resume_charge_percent);
1657 else
1658 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1659 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001660
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001661 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001662 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663}
1664
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001665static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1666{
1667 return pm8921_bms_get_current_max();
1668}
1669
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001670static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1671{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001672 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001673
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001674 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001675 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001676 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001677 }
1678
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001679 if (rc) {
1680 pr_err("unable to get batt current rc = %d\n", rc);
1681 return rc;
1682 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001683 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001684 }
1685}
1686
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001687static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1688{
1689 int rc;
1690
1691 rc = pm8921_bms_get_fcc();
1692 if (rc < 0)
1693 pr_err("unable to get batt fcc rc = %d\n", rc);
1694 return rc;
1695}
1696
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001697static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1698{
1699 int rc;
1700 int cc_uah;
1701
1702 rc = pm8921_bms_cc_uah(&cc_uah);
1703
1704 if (rc == 0)
1705 return cc_uah;
1706
1707 pr_err("unable to get batt fcc rc = %d\n", rc);
1708 return rc;
1709}
1710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1712{
1713 int temp;
1714
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001715 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1716 if (temp)
1717 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001719 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1720 if (temp)
1721 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001723 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724}
1725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1727{
1728 int temp;
1729
Amir Samuelovd31ef502011-10-26 14:41:36 +02001730 if (!get_prop_batt_present(chip))
1731 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1732
1733 if (is_ext_trickle_charging(chip))
1734 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1735
1736 if (is_ext_charging(chip))
1737 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1740 if (temp)
1741 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1742
1743 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1744 if (temp)
1745 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1746
1747 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1748}
1749
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001750#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001751static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1752{
1753 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001754 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001755
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001756 if (chip->battery_less_hardware)
1757 return 300;
1758
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001759 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001760 if (rc) {
1761 pr_err("error reading adc channel = %d, rc = %d\n",
1762 chip->vbat_channel, rc);
1763 return rc;
1764 }
1765 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1766 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001767 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1768 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1769 (int) result.physical);
1770
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001771 return (int)result.physical;
1772}
1773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774static int pm_batt_power_get_property(struct power_supply *psy,
1775 enum power_supply_property psp,
1776 union power_supply_propval *val)
1777{
1778 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1779 batt_psy);
1780
1781 switch (psp) {
1782 case POWER_SUPPLY_PROP_STATUS:
1783 val->intval = get_prop_batt_status(chip);
1784 break;
1785 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1786 val->intval = get_prop_charge_type(chip);
1787 break;
1788 case POWER_SUPPLY_PROP_HEALTH:
1789 val->intval = get_prop_batt_health(chip);
1790 break;
1791 case POWER_SUPPLY_PROP_PRESENT:
1792 val->intval = get_prop_batt_present(chip);
1793 break;
1794 case POWER_SUPPLY_PROP_TECHNOLOGY:
1795 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1796 break;
1797 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001798 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 break;
1800 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001801 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 break;
1803 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001804 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 break;
1806 case POWER_SUPPLY_PROP_CAPACITY:
1807 val->intval = get_prop_batt_capacity(chip);
1808 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001809 case POWER_SUPPLY_PROP_CURRENT_NOW:
1810 val->intval = get_prop_batt_current(chip);
1811 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001812 case POWER_SUPPLY_PROP_CURRENT_MAX:
1813 val->intval = get_prop_batt_current_max(chip);
1814 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001815 case POWER_SUPPLY_PROP_TEMP:
1816 val->intval = get_prop_batt_temp(chip);
1817 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001818 case POWER_SUPPLY_PROP_CHARGE_FULL:
1819 val->intval = get_prop_batt_fcc(chip);
1820 break;
1821 case POWER_SUPPLY_PROP_CHARGE_NOW:
1822 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001823 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 default:
1825 return -EINVAL;
1826 }
1827
1828 return 0;
1829}
1830
1831static void (*notify_vbus_state_func_ptr)(int);
1832static int usb_chg_current;
1833static DEFINE_SPINLOCK(vbus_lock);
1834
1835int pm8921_charger_register_vbus_sn(void (*callback)(int))
1836{
1837 pr_debug("%p\n", callback);
1838 notify_vbus_state_func_ptr = callback;
1839 return 0;
1840}
1841EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1842
1843/* this is passed to the hsusb via platform_data msm_otg_pdata */
1844void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1845{
1846 pr_debug("%p\n", callback);
1847 notify_vbus_state_func_ptr = NULL;
1848}
1849EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1850
1851static void notify_usb_of_the_plugin_event(int plugin)
1852{
1853 plugin = !!plugin;
1854 if (notify_vbus_state_func_ptr) {
1855 pr_debug("notifying plugin\n");
1856 (*notify_vbus_state_func_ptr) (plugin);
1857 } else {
1858 pr_debug("unable to notify plugin\n");
1859 }
1860}
1861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862/* assumes vbus_lock is held */
1863static void __pm8921_charger_vbus_draw(unsigned int mA)
1864{
1865 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001866 if (!the_chip) {
1867 pr_err("called before init\n");
1868 return;
1869 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001871 if (usb_max_current && mA > usb_max_current) {
1872 pr_debug("restricting usb current to %d instead of %d\n",
1873 usb_max_current, mA);
1874 mA = usb_max_current;
1875 }
1876
1877 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001879 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001881 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 }
1883 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1884 if (rc)
1885 pr_err("fail to set suspend bit rc=%d\n", rc);
1886 } else {
1887 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1888 if (rc)
1889 pr_err("fail to reset suspend bit rc=%d\n", rc);
1890 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1891 if (usb_ma_table[i].usb_ma <= mA)
1892 break;
1893 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001894
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001895 if (i < 0) {
1896 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1897 mA);
1898 i = 0;
1899 }
1900
David Keitel38bdd4f2012-04-19 15:39:13 -07001901 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001902 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001903 && !the_chip->iusb_fine_res)
1904 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 if (i < 0)
1906 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001907 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001908 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001909 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 }
1911}
1912
1913/* USB calls these to tell us how much max usb current the system can draw */
1914void pm8921_charger_vbus_draw(unsigned int mA)
1915{
1916 unsigned long flags;
1917
1918 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001919
David Keitel62c6a4b2012-05-17 12:54:59 -07001920 if (!the_chip) {
1921 pr_err("chip not yet initalized\n");
1922 return;
1923 }
1924
1925 /*
1926 * Reject VBUS requests if USB connection is the only available
1927 * power source. This makes sure that if booting without
1928 * battery the iusb_max value is not decreased avoiding potential
1929 * brown_outs.
1930 *
1931 * This would also apply when the battery has been
1932 * removed from the running system.
1933 */
1934 if (!get_prop_batt_present(the_chip)
1935 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001936 if (!the_chip->has_dc_supply) {
1937 pr_err("rejected: no other power source connected\n");
1938 return;
1939 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001940 }
1941
David Keitelacf57c82012-03-07 18:48:50 -08001942 if (usb_max_current && mA > usb_max_current) {
1943 pr_warn("restricting usb current to %d instead of %d\n",
1944 usb_max_current, mA);
1945 mA = usb_max_current;
1946 }
Devin Kim2073afb2012-09-05 13:01:51 -07001947 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1948 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 spin_lock_irqsave(&vbus_lock, flags);
1951 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001952 if (mA > USB_WALL_THRESHOLD_MA)
1953 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1954 else
1955 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 } else {
1957 /*
1958 * called before pmic initialized,
1959 * save this value and use it at probe
1960 */
David Keitelacf57c82012-03-07 18:48:50 -08001961 if (mA > USB_WALL_THRESHOLD_MA)
1962 usb_chg_current = USB_WALL_THRESHOLD_MA;
1963 else
1964 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 }
1966 spin_unlock_irqrestore(&vbus_lock, flags);
1967}
1968EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1969
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001970int pm8921_is_usb_chg_plugged_in(void)
1971{
1972 if (!the_chip) {
1973 pr_err("called before init\n");
1974 return -EINVAL;
1975 }
1976 return is_usb_chg_plugged_in(the_chip);
1977}
1978EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1979
1980int pm8921_is_dc_chg_plugged_in(void)
1981{
1982 if (!the_chip) {
1983 pr_err("called before init\n");
1984 return -EINVAL;
1985 }
1986 return is_dc_chg_plugged_in(the_chip);
1987}
1988EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1989
1990int pm8921_is_battery_present(void)
1991{
1992 if (!the_chip) {
1993 pr_err("called before init\n");
1994 return -EINVAL;
1995 }
1996 return get_prop_batt_present(the_chip);
1997}
1998EXPORT_SYMBOL(pm8921_is_battery_present);
1999
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002000int pm8921_is_batfet_closed(void)
2001{
2002 if (!the_chip) {
2003 pr_err("called before init\n");
2004 return -EINVAL;
2005 }
2006 return is_batfet_closed(the_chip);
2007}
2008EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002009/*
2010 * Disabling the charge current limit causes current
2011 * current limits to have no monitoring. An adequate charger
2012 * capable of supplying high current while sustaining VIN_MIN
2013 * is required if the limiting is disabled.
2014 */
2015int pm8921_disable_input_current_limit(bool disable)
2016{
2017 if (!the_chip) {
2018 pr_err("called before init\n");
2019 return -EINVAL;
2020 }
2021 if (disable) {
2022 pr_warn("Disabling input current limit!\n");
2023
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002024 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002025 }
2026 return 0;
2027}
2028EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2029
David Keitel0789fc62012-06-07 17:43:27 -07002030int pm8917_set_under_voltage_detection_threshold(int mv)
2031{
2032 if (!the_chip) {
2033 pr_err("called before init\n");
2034 return -EINVAL;
2035 }
2036 return pm_chg_uvd_threshold_set(the_chip, mv);
2037}
2038EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2039
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002040int pm8921_set_max_battery_charge_current(int ma)
2041{
2042 if (!the_chip) {
2043 pr_err("called before init\n");
2044 return -EINVAL;
2045 }
2046 return pm_chg_ibatmax_set(the_chip, ma);
2047}
2048EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2049
2050int pm8921_disable_source_current(bool disable)
2051{
2052 if (!the_chip) {
2053 pr_err("called before init\n");
2054 return -EINVAL;
2055 }
2056 if (disable)
2057 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002058
2059 pm_chg_usb_suspend_enable(the_chip, disable);
2060
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002061 return pm_chg_charge_dis(the_chip, disable);
2062}
2063EXPORT_SYMBOL(pm8921_disable_source_current);
2064
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002065int pm8921_regulate_input_voltage(int voltage)
2066{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002067 int rc;
2068
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002069 if (!the_chip) {
2070 pr_err("called before init\n");
2071 return -EINVAL;
2072 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002073 rc = pm_chg_vinmin_set(the_chip, voltage);
2074
2075 if (rc == 0)
2076 the_chip->vin_min = voltage;
2077
2078 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002079}
2080
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002081#define USB_OV_THRESHOLD_MASK 0x60
2082#define USB_OV_THRESHOLD_SHIFT 5
2083int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2084{
2085 u8 temp;
2086
2087 if (!the_chip) {
2088 pr_err("called before init\n");
2089 return -EINVAL;
2090 }
2091
2092 if (ov > PM_USB_OV_7V) {
2093 pr_err("limiting to over voltage threshold to 7volts\n");
2094 ov = PM_USB_OV_7V;
2095 }
2096
2097 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2098
2099 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2100 USB_OV_THRESHOLD_MASK, temp);
2101}
2102EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2103
2104#define USB_DEBOUNCE_TIME_MASK 0x06
2105#define USB_DEBOUNCE_TIME_SHIFT 1
2106int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2107{
2108 u8 temp;
2109
2110 if (!the_chip) {
2111 pr_err("called before init\n");
2112 return -EINVAL;
2113 }
2114
2115 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2116 pr_err("limiting debounce to 80.5ms\n");
2117 ms = PM_USB_DEBOUNCE_80P5MS;
2118 }
2119
2120 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2121
2122 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2123 USB_DEBOUNCE_TIME_MASK, temp);
2124}
2125EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2126
2127#define USB_OVP_DISABLE_MASK 0x80
2128int pm8921_usb_ovp_disable(int disable)
2129{
2130 u8 temp = 0;
2131
2132 if (!the_chip) {
2133 pr_err("called before init\n");
2134 return -EINVAL;
2135 }
2136
2137 if (disable)
2138 temp = USB_OVP_DISABLE_MASK;
2139
2140 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2141 USB_OVP_DISABLE_MASK, temp);
2142}
2143
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002144bool pm8921_is_battery_charging(int *source)
2145{
2146 int fsm_state, is_charging, dc_present, usb_present;
2147
2148 if (!the_chip) {
2149 pr_err("called before init\n");
2150 return -EINVAL;
2151 }
2152 fsm_state = pm_chg_get_fsm_state(the_chip);
2153 is_charging = is_battery_charging(fsm_state);
2154 if (is_charging == 0) {
2155 *source = PM8921_CHG_SRC_NONE;
2156 return is_charging;
2157 }
2158
2159 if (source == NULL)
2160 return is_charging;
2161
2162 /* the battery is charging, the source is requested, find it */
2163 dc_present = is_dc_chg_plugged_in(the_chip);
2164 usb_present = is_usb_chg_plugged_in(the_chip);
2165
2166 if (dc_present && !usb_present)
2167 *source = PM8921_CHG_SRC_DC;
2168
2169 if (usb_present && !dc_present)
2170 *source = PM8921_CHG_SRC_USB;
2171
2172 if (usb_present && dc_present)
2173 /*
2174 * The system always chooses dc for charging since it has
2175 * higher priority.
2176 */
2177 *source = PM8921_CHG_SRC_DC;
2178
2179 return is_charging;
2180}
2181EXPORT_SYMBOL(pm8921_is_battery_charging);
2182
David Keitel86034022012-04-18 12:33:58 -07002183int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2184{
2185 if (!the_chip) {
2186 pr_err("called before init\n");
2187 return -EINVAL;
2188 }
2189
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002190 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002191 return -EINVAL;
2192
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002193 the_chip->usb_psy.type = type;
David Keitel86034022012-04-18 12:33:58 -07002194 power_supply_changed(&the_chip->usb_psy);
2195 power_supply_changed(&the_chip->dc_psy);
2196 return 0;
2197}
2198EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2199
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002200int pm8921_batt_temperature(void)
2201{
2202 if (!the_chip) {
2203 pr_err("called before init\n");
2204 return -EINVAL;
2205 }
2206 return get_prop_batt_temp(the_chip);
2207}
2208
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002209static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002210{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002211 int err;
2212 u8 temp;
2213 unsigned long flags = 0;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002214
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002215 spin_lock_irqsave(&lpm_lock, flags);
2216 err = pm8921_chg_set_lpm(chip, 0);
2217 if (err) {
2218 pr_err("Error settig LPM rc=%d\n", err);
2219 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002220 }
2221
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002222 temp = 0xD1;
2223 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2224 if (err) {
2225 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2226 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002227 }
2228
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002229 temp = 0xD3;
2230 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2231 if (err) {
2232 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2233 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002234 }
2235
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002236 temp = 0xD1;
2237 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2238 if (err) {
2239 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2240 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002241 }
2242
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002243 temp = 0xD5;
2244 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2245 if (err) {
2246 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2247 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002248 }
2249
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002250 /* Wait a few clock cycles before re-enabling hw clock switching */
2251 udelay(183);
2252
2253 temp = 0xD1;
2254 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2255 if (err) {
2256 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2257 goto kick_err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002258 }
2259
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002260 temp = 0xD0;
2261 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2262 if (err) {
2263 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
2264 goto kick_err;
2265 }
2266
2267 /* Wait for few clock cycles before re-enabling LPM */
2268 udelay(32);
2269
2270kick_err:
2271 err = pm8921_chg_set_lpm(chip, 1);
2272 if (err)
2273 pr_err("Error settig LPM rc=%d\n", err);
2274
2275 spin_unlock_irqrestore(&lpm_lock, flags);
2276
2277 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002278}
2279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2281{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002282 int usb_present, rc = 0;
2283
2284 if (chip->lockup_lpm_wrkarnd) {
2285 rc = pm8921_apply_19p2mhz_kickstart(chip);
2286 if (rc)
2287 pr_err("Failed to apply kickstart rc=%d\n", rc);
2288 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002290 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 usb_present = is_usb_chg_plugged_in(chip);
2292 if (chip->usb_present ^ usb_present) {
2293 notify_usb_of_the_plugin_event(usb_present);
2294 chip->usb_present = usb_present;
2295 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002296 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002297 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002298
2299 /* Enable/disable bypass if charger is on battery */
2300 if (chip->lockup_lpm_wrkarnd)
2301 pm8921_chg_bypass_bat_gone_debounce(chip,
2302 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002304 if (usb_present) {
2305 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002306 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002307 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2308 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002309 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002310 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002311 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002312 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002313 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314}
2315
Amir Samuelovd31ef502011-10-26 14:41:36 +02002316static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2317{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002318 if (chip->lockup_lpm_wrkarnd)
2319 /* Enable bypass if charger is on battery */
2320 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2321
David Keitel88e1b572012-01-11 11:57:14 -08002322 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002323 pr_debug("external charger not registered.\n");
2324 return;
2325 }
2326
2327 if (!chip->ext_charging) {
2328 pr_debug("already not charging.\n");
2329 return;
2330 }
2331
David Keitel88e1b572012-01-11 11:57:14 -08002332 power_supply_set_charge_type(chip->ext_psy,
2333 POWER_SUPPLY_CHARGE_TYPE_NONE);
2334 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002335 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002336 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002337 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002338 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002339 /* Update battery charging LEDs and user space battery info */
2340 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002341}
2342
2343static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2344{
2345 int dc_present;
2346 int batt_present;
2347 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002348 unsigned long delay =
2349 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2350
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002351 /* Disable bypass if charger connected and not running on bat */
2352 if (chip->lockup_lpm_wrkarnd)
2353 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2354
David Keitel88e1b572012-01-11 11:57:14 -08002355 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002356 pr_debug("external charger not registered.\n");
2357 return;
2358 }
2359
2360 if (chip->ext_charging) {
2361 pr_debug("already charging.\n");
2362 return;
2363 }
2364
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002365 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002366 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2367 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002368
2369 if (!dc_present) {
2370 pr_warn("%s. dc not present.\n", __func__);
2371 return;
2372 }
2373 if (!batt_present) {
2374 pr_warn("%s. battery not present.\n", __func__);
2375 return;
2376 }
2377 if (!batt_temp_ok) {
2378 pr_warn("%s. battery temperature not ok.\n", __func__);
2379 return;
2380 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002381
2382 /* Force BATFET=ON */
2383 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002384
David Keitel6ccbf132012-05-30 14:21:24 -07002385 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002386 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002387
David Keitel63f71662012-02-08 20:30:00 -08002388 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002389 power_supply_set_charge_type(chip->ext_psy,
2390 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002391 chip->ext_charging = true;
2392 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002393 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002394 /*
2395 * since we wont get a fastchg irq from external charger
2396 * use eoc worker to detect end of charging
2397 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002398 schedule_delayed_work(&chip->eoc_work, delay);
2399 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002400 if (chip->btc_override)
2401 schedule_delayed_work(&chip->btc_override_work,
2402 round_jiffies_relative(msecs_to_jiffies
2403 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002404 /* Update battery charging LEDs and user space battery info */
2405 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002406}
2407
David Keitel6ccbf132012-05-30 14:21:24 -07002408static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002409{
2410 u8 temp;
2411 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002412
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002413 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002414 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002415 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002416 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002417 }
David Keitel6ccbf132012-05-30 14:21:24 -07002418 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002419 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002420 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002421 return;
2422 }
2423 /* set ovp fet disable bit and the write bit */
2424 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002425 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002426 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002427 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002428 return;
2429 }
2430}
2431
David Keitel6ccbf132012-05-30 14:21:24 -07002432static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002433{
2434 u8 temp;
2435 int rc;
2436
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002437 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002438 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002439 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002440 return;
2441 }
David Keitel6ccbf132012-05-30 14:21:24 -07002442 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002443 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002444 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002445 return;
2446 }
2447 /* unset ovp fet disable bit and set the write bit */
2448 temp &= 0xFE;
2449 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002450 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002451 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002452 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002453 temp, rc);
2454 return;
2455 }
2456}
2457
2458static int param_open_ovp_counter = 10;
2459module_param(param_open_ovp_counter, int, 0644);
2460
David Keitel6ccbf132012-05-30 14:21:24 -07002461#define USB_ACTIVE_BIT BIT(5)
2462#define DC_ACTIVE_BIT BIT(6)
2463static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2464 u8 active_chg_mask)
2465{
2466 if (active_chg_mask & USB_ACTIVE_BIT)
2467 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2468 else if (active_chg_mask & DC_ACTIVE_BIT)
2469 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2470 else
2471 return 0;
2472}
2473
David Keitel8c5201a2012-02-24 16:08:54 -08002474#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002475#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002476static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002477{
David Keitel6ccbf132012-05-30 14:21:24 -07002478 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002479 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002480 u8 active_mask = 0;
2481 u16 ovpreg, ovptestreg;
2482
2483 if (is_usb_chg_plugged_in(chip) &&
2484 (chip->active_path & USB_ACTIVE_BIT)) {
2485 ovpreg = USB_OVP_CONTROL;
2486 ovptestreg = USB_OVP_TEST;
2487 active_mask = USB_ACTIVE_BIT;
2488 } else if (is_dc_chg_plugged_in(chip) &&
2489 (chip->active_path & DC_ACTIVE_BIT)) {
2490 ovpreg = DC_OVP_CONTROL;
2491 ovptestreg = DC_OVP_TEST;
2492 active_mask = DC_ACTIVE_BIT;
2493 } else {
2494 return;
2495 }
David Keitel8c5201a2012-02-24 16:08:54 -08002496
2497 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002498 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002499 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002500 active_chg_plugged_in
2501 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002502 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002503 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2504 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002505
2506 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002507 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002508 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002509 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002510
2511 msleep(20);
2512
David Keitel6ccbf132012-05-30 14:21:24 -07002513 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002514 } else {
David Keitel712782e2012-03-29 14:11:47 -07002515 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002516 }
2517 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002518 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2519 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2520 else
2521 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2522
David Keitel6ccbf132012-05-30 14:21:24 -07002523 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2524 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002525 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002526}
David Keitelacf57c82012-03-07 18:48:50 -08002527
2528static int find_usb_ma_value(int value)
2529{
2530 int i;
2531
2532 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2533 if (value >= usb_ma_table[i].usb_ma)
2534 break;
2535 }
2536
2537 return i;
2538}
2539
2540static void decrease_usb_ma_value(int *value)
2541{
2542 int i;
2543
2544 if (value) {
2545 i = find_usb_ma_value(*value);
2546 if (i > 0)
2547 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002548 while (!the_chip->iusb_fine_res && i > 0
2549 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2550 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002551
2552 if (i < 0) {
2553 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2554 *value);
2555 i = 0;
2556 }
2557
David Keitelacf57c82012-03-07 18:48:50 -08002558 *value = usb_ma_table[i].usb_ma;
2559 }
2560}
2561
2562static void increase_usb_ma_value(int *value)
2563{
2564 int i;
2565
2566 if (value) {
2567 i = find_usb_ma_value(*value);
2568
2569 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2570 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002571 /* Get next correct entry if IUSB_FINE_RES is not available */
2572 while (!the_chip->iusb_fine_res
2573 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2574 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2575 i++;
2576
David Keitelacf57c82012-03-07 18:48:50 -08002577 *value = usb_ma_table[i].usb_ma;
2578 }
2579}
2580
2581static void vin_collapse_check_worker(struct work_struct *work)
2582{
2583 struct delayed_work *dwork = to_delayed_work(work);
2584 struct pm8921_chg_chip *chip = container_of(dwork,
2585 struct pm8921_chg_chip, vin_collapse_check_work);
2586
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002587 /*
2588 * AICL only for wall-chargers. If the charger appears to be plugged
2589 * back in now, the corresponding unplug must have been because of we
2590 * were trying to draw more current than the charger can support. In
2591 * such a case reset usb current to 500mA and decrease the target.
2592 * The AICL algorithm will step up the current from 500mA to target
2593 */
2594 if (is_usb_chg_plugged_in(chip)
2595 && usb_target_ma > USB_WALL_THRESHOLD_MA) {
David Keitelacf57c82012-03-07 18:48:50 -08002596 /* decrease usb_target_ma */
2597 decrease_usb_ma_value(&usb_target_ma);
2598 /* reset here, increase in unplug_check_worker */
2599 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2600 pr_debug("usb_now=%d, usb_target = %d\n",
2601 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002602 if (!delayed_work_pending(&chip->unplug_check_work))
2603 schedule_delayed_work(&chip->unplug_check_work,
2604 msecs_to_jiffies
2605 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002606 } else {
2607 handle_usb_insertion_removal(chip);
2608 }
2609}
2610
2611#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002612static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2613{
David Keitelacf57c82012-03-07 18:48:50 -08002614 if (usb_target_ma)
2615 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2616 round_jiffies_relative(msecs_to_jiffies
2617 (VIN_MIN_COLLAPSE_CHECK_MS)));
2618 else
2619 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 return IRQ_HANDLED;
2621}
2622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2624{
2625 struct pm8921_chg_chip *chip = data;
2626 int status;
2627
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002628 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2629 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002630 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002631 pr_debug("battery present=%d", status);
2632 power_supply_changed(&chip->batt_psy);
2633 return IRQ_HANDLED;
2634}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002635
2636/*
2637 * this interrupt used to restart charging a battery.
2638 *
2639 * Note: When DC-inserted the VBAT can't go low.
2640 * VPH_PWR is provided by the ext-charger.
2641 * After End-Of-Charging from DC, charging can be resumed only
2642 * if DC is removed and then inserted after the battery was in use.
2643 * Therefore the handle_start_ext_chg() is not called.
2644 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2646{
2647 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002648 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002650 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002651
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002652 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002653 /* enable auto charging */
2654 pm_chg_auto_enable(chip, !charging_disabled);
2655 pr_info("batt fell below resume voltage %s\n",
2656 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002657 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 power_supply_changed(&chip->batt_psy);
2661 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002662 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664 return IRQ_HANDLED;
2665}
2666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2668{
2669 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2670 return IRQ_HANDLED;
2671}
2672
2673static irqreturn_t vcp_irq_handler(int irq, void *data)
2674{
David Keitel8c5201a2012-02-24 16:08:54 -08002675 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676 return IRQ_HANDLED;
2677}
2678
2679static irqreturn_t atcdone_irq_handler(int irq, void *data)
2680{
2681 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2682 return IRQ_HANDLED;
2683}
2684
2685static irqreturn_t atcfail_irq_handler(int irq, void *data)
2686{
2687 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2688 return IRQ_HANDLED;
2689}
2690
2691static irqreturn_t chgdone_irq_handler(int irq, void *data)
2692{
2693 struct pm8921_chg_chip *chip = data;
2694
2695 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002696
2697 handle_stop_ext_chg(chip);
2698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 power_supply_changed(&chip->batt_psy);
2700 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002701 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002702
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002703 bms_notify_check(chip);
2704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002705 return IRQ_HANDLED;
2706}
2707
2708static irqreturn_t chgfail_irq_handler(int irq, void *data)
2709{
2710 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002711 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002713 if (!chip->stop_chg_upon_expiry) {
2714 ret = pm_chg_failed_clear(chip, 1);
2715 if (ret)
2716 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2717 }
David Keitel753ec8d2011-11-02 10:56:37 -07002718
2719 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2720 get_prop_batt_present(chip),
2721 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2722 pm_chg_get_fsm_state(data));
2723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002724 power_supply_changed(&chip->batt_psy);
2725 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002726 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002727 return IRQ_HANDLED;
2728}
2729
2730static irqreturn_t chgstate_irq_handler(int irq, void *data)
2731{
2732 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002733
2734 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2735 power_supply_changed(&chip->batt_psy);
2736 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002737 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002739 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 return IRQ_HANDLED;
2742}
2743
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002744enum {
2745 PON_TIME_25NS = 0x04,
2746 PON_TIME_50NS = 0x08,
2747 PON_TIME_100NS = 0x0C,
2748};
David Keitel8c5201a2012-02-24 16:08:54 -08002749
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002750static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002751{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002752 u8 temp;
2753 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002754
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002755 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2756 if (rc) {
2757 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2758 return;
2759 }
2760 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2761 if (rc) {
2762 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2763 return;
2764 }
2765 /* clear the min pon time select bit */
2766 temp &= 0xF3;
2767 /* set the pon time */
2768 temp |= (u8)pon_time_ns;
2769 /* write enable bank 4 */
2770 temp |= 0x80;
2771 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2772 if (rc) {
2773 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2774 return;
2775 }
2776}
David Keitel8c5201a2012-02-24 16:08:54 -08002777
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002778static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2779{
2780 pr_debug("Start\n");
2781 set_min_pon_time(chip, PON_TIME_100NS);
2782 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2783 msleep(250);
2784 pm_chg_vinmin_set(chip, chip->vin_min);
2785 set_min_pon_time(chip, PON_TIME_25NS);
2786 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002787}
2788
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002789#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002790#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2791#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002792static void unplug_check_worker(struct work_struct *work)
2793{
2794 struct delayed_work *dwork = to_delayed_work(work);
2795 struct pm8921_chg_chip *chip = container_of(dwork,
2796 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002797 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002798 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002799 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002800 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002801
2802 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2803 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002804 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2805 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002806 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002807
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002808 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002809 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002810 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2811 active_path, active_chg_plugged_in);
2812 if (active_path & USB_ACTIVE_BIT) {
2813 pr_debug("USB charger active\n");
2814
2815 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002816
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002817 if (usb_ma <= 100) {
2818 pr_debug(
2819 "Unenumerated or suspended usb_ma = %d skip\n",
2820 usb_ma);
2821 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002822 }
2823 } else if (active_path & DC_ACTIVE_BIT) {
2824 pr_debug("DC charger active\n");
2825 } else {
2826 /* No charger active */
2827 if (!(is_usb_chg_plugged_in(chip)
2828 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002829 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002830 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2831 pm_chg_get_regulation_loop(chip),
2832 pm_chg_get_fsm_state(chip),
2833 get_prop_batt_current(chip)
2834 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002835 if (chip->lockup_lpm_wrkarnd) {
2836 rc = pm8921_apply_19p2mhz_kickstart(chip);
2837 if (rc)
2838 pr_err("Failed kickstart rc=%d\n", rc);
2839
2840 /*
2841 * Make sure kickstart happens at least 200 ms
2842 * after charger has been removed.
2843 */
2844 if (chip->final_kickstart) {
2845 chip->final_kickstart = false;
2846 goto check_again_later;
2847 }
2848 }
2849 return;
2850 } else {
2851 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002852 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002853 }
David Keitel8c5201a2012-02-24 16:08:54 -08002854
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002855 chip->final_kickstart = true;
2856
2857 /* AICL only for usb wall charger */
2858 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
David Keitel6ccbf132012-05-30 14:21:24 -07002859 reg_loop = pm_chg_get_regulation_loop(chip);
2860 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2861 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002862 (usb_ma > USB_WALL_THRESHOLD_MA)
2863 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002864 decrease_usb_ma_value(&usb_ma);
2865 usb_target_ma = usb_ma;
2866 /* end AICL here */
2867 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002868 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002869 usb_ma, usb_target_ma);
2870 }
David Keitelacf57c82012-03-07 18:48:50 -08002871 }
2872
2873 reg_loop = pm_chg_get_regulation_loop(chip);
2874 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2875
David Keitel6ccbf132012-05-30 14:21:24 -07002876 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002877 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002878 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002879 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2880 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2881 attempt_reverse_boost_fix(chip);
2882 /* after reverse boost fix check if the active
2883 * charger was detected as removed */
2884 active_chg_plugged_in
2885 = is_active_chg_plugged_in(chip,
2886 active_path);
2887 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2888 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002889 }
2890 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002891
2892 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002893 pr_debug("active_path = 0x%x, active_chg = %d\n",
2894 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002895 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2896
David Keitel6ccbf132012-05-30 14:21:24 -07002897 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2898 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2899 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002900 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002901 }
2902
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002903 /* AICL only for usb wall charger */
2904 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2905 && usb_target_ma > 0
2906 && !charging_disabled) {
David Keitelacf57c82012-03-07 18:48:50 -08002907 /* only increase iusb_max if vin loop not active */
2908 if (usb_ma < usb_target_ma) {
2909 increase_usb_ma_value(&usb_ma);
2910 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002911 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002912 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002913 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002914 } else {
2915 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002916 }
2917 }
Devin Kim2073afb2012-09-05 13:01:51 -07002918check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002919 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002920 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002921 if (ramp)
2922 schedule_delayed_work(&chip->unplug_check_work,
2923 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2924 else
2925 schedule_delayed_work(&chip->unplug_check_work,
2926 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002927}
2928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929static irqreturn_t loop_change_irq_handler(int irq, void *data)
2930{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002931 struct pm8921_chg_chip *chip = data;
2932
2933 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2934 pm_chg_get_fsm_state(data),
2935 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002936 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002937 return IRQ_HANDLED;
2938}
2939
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002940struct ibatmax_max_adj_entry {
2941 int ibat_max_ma;
2942 int max_adj_ma;
2943};
2944
2945static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2946 {975, 300},
2947 {1475, 150},
2948 {1975, 200},
2949 {2475, 250},
2950};
2951
2952static int find_ibat_max_adj_ma(int ibat_target_ma)
2953{
2954 int i = 0;
2955
2956 for (i = ARRAY_SIZE(ibatmax_adj_table) - 1; i >= 0; i--) {
2957 if (ibat_target_ma <= ibatmax_adj_table[i].ibat_max_ma)
2958 break;
2959 }
2960
2961 return ibatmax_adj_table[i].max_adj_ma;
2962}
2963
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002964static irqreturn_t fastchg_irq_handler(int irq, void *data)
2965{
2966 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002967 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002968
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002969 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2970 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2971 wake_lock(&chip->eoc_wake_lock);
2972 schedule_delayed_work(&chip->eoc_work,
2973 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002974 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002975 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002976 if (high_transition
2977 && chip->btc_override
2978 && !delayed_work_pending(&chip->btc_override_work)) {
2979 schedule_delayed_work(&chip->btc_override_work,
2980 round_jiffies_relative(msecs_to_jiffies
2981 (chip->btc_delay_ms)));
2982 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002983 power_supply_changed(&chip->batt_psy);
2984 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985 return IRQ_HANDLED;
2986}
2987
2988static irqreturn_t trklchg_irq_handler(int irq, void *data)
2989{
2990 struct pm8921_chg_chip *chip = data;
2991
2992 power_supply_changed(&chip->batt_psy);
2993 return IRQ_HANDLED;
2994}
2995
2996static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2997{
2998 struct pm8921_chg_chip *chip = data;
2999 int status;
3000
3001 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3002 pr_debug("battery present=%d state=%d", !status,
3003 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003004 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 power_supply_changed(&chip->batt_psy);
3006 return IRQ_HANDLED;
3007}
3008
3009static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3010{
3011 struct pm8921_chg_chip *chip = data;
3012
Amir Samuelovd31ef502011-10-26 14:41:36 +02003013 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003014 power_supply_changed(&chip->batt_psy);
3015 return IRQ_HANDLED;
3016}
3017
3018static irqreturn_t chghot_irq_handler(int irq, void *data)
3019{
3020 struct pm8921_chg_chip *chip = data;
3021
3022 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3023 power_supply_changed(&chip->batt_psy);
3024 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003025 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 return IRQ_HANDLED;
3027}
3028
3029static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3030{
3031 struct pm8921_chg_chip *chip = data;
3032
3033 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003034 handle_stop_ext_chg(chip);
3035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 power_supply_changed(&chip->batt_psy);
3037 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 return IRQ_HANDLED;
3039}
3040
3041static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3042{
3043 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003044 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003045
3046 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3047 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3048
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003049 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3050 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052 power_supply_changed(&chip->batt_psy);
3053 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003054 return IRQ_HANDLED;
3055}
David Keitel52fda532011-11-10 10:43:44 -08003056/*
3057 *
3058 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3059 * fire for two cases:
3060 *
3061 * If the interrupt line switches to high temperature is okay
3062 * and thus charging begins.
3063 * If bat_temp_ok is low this means the temperature is now
3064 * too hot or cold, so charging is stopped.
3065 *
3066 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3068{
David Keitel52fda532011-11-10 10:43:44 -08003069 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003070 struct pm8921_chg_chip *chip = data;
3071
David Keitel52fda532011-11-10 10:43:44 -08003072 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3073
3074 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3075 bat_temp_ok, pm_chg_get_fsm_state(data));
3076
3077 if (bat_temp_ok)
3078 handle_start_ext_chg(chip);
3079 else
3080 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082 power_supply_changed(&chip->batt_psy);
3083 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003084 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 return IRQ_HANDLED;
3086}
3087
3088static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3089{
3090 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3091 return IRQ_HANDLED;
3092}
3093
3094static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3095{
3096 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3097 return IRQ_HANDLED;
3098}
3099
3100static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3101{
3102 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3103 return IRQ_HANDLED;
3104}
3105
3106static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3107{
3108 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3109 return IRQ_HANDLED;
3110}
3111
3112static irqreturn_t batfet_irq_handler(int irq, void *data)
3113{
3114 struct pm8921_chg_chip *chip = data;
3115
3116 pr_debug("vreg ov\n");
3117 power_supply_changed(&chip->batt_psy);
3118 return IRQ_HANDLED;
3119}
3120
3121static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3122{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003123 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003124 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003125
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003126 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003127 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003128
3129 if (chip->dc_present ^ dc_present)
3130 pm8921_bms_calibrate_hkadc();
3131
David Keitel88e1b572012-01-11 11:57:14 -08003132 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003133 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003134 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003135 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3136
3137 chip->dc_present = dc_present;
3138
3139 if (chip->ext_psy) {
3140 if (dc_present)
3141 handle_start_ext_chg(chip);
3142 else
3143 handle_stop_ext_chg(chip);
3144 } else {
3145 if (chip->lockup_lpm_wrkarnd)
3146 /* if no external supply call bypass debounce here */
3147 pm8921_chg_bypass_bat_gone_debounce(chip,
3148 is_chg_on_bat(chip));
3149
3150 if (dc_present)
3151 schedule_delayed_work(&chip->unplug_check_work,
3152 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3153 power_supply_changed(&chip->dc_psy);
3154 }
3155
3156 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157 return IRQ_HANDLED;
3158}
3159
3160static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3161{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003162 struct pm8921_chg_chip *chip = data;
3163
Amir Samuelovd31ef502011-10-26 14:41:36 +02003164 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 return IRQ_HANDLED;
3166}
3167
3168static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3169{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003170 struct pm8921_chg_chip *chip = data;
3171
Amir Samuelovd31ef502011-10-26 14:41:36 +02003172 handle_stop_ext_chg(chip);
3173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174 return IRQ_HANDLED;
3175}
3176
David Keitel88e1b572012-01-11 11:57:14 -08003177static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3178{
3179 struct power_supply *psy = &the_chip->batt_psy;
3180 struct power_supply *epsy = dev_get_drvdata(dev);
3181 int i, dcin_irq;
3182
3183 /* Only search for external supply if none is registered */
3184 if (!the_chip->ext_psy) {
3185 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3186 for (i = 0; i < epsy->num_supplicants; i++) {
3187 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3188 if (!strncmp(epsy->name, "dc", 2)) {
3189 the_chip->ext_psy = epsy;
3190 dcin_valid_irq_handler(dcin_irq,
3191 the_chip);
3192 }
3193 }
3194 }
3195 }
3196 return 0;
3197}
3198
3199static void pm_batt_external_power_changed(struct power_supply *psy)
3200{
3201 /* Only look for an external supply if it hasn't been registered */
3202 if (!the_chip->ext_psy)
3203 class_for_each_device(power_supply_class, NULL, psy,
3204 __pm_batt_external_power_changed_work);
3205}
3206
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003207/**
3208 * update_heartbeat - internal function to update userspace
3209 * per update_time minutes
3210 *
3211 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003212#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003213static void update_heartbeat(struct work_struct *work)
3214{
3215 struct delayed_work *dwork = to_delayed_work(work);
3216 struct pm8921_chg_chip *chip = container_of(dwork,
3217 struct pm8921_chg_chip, update_heartbeat_work);
3218
3219 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003220 if (chip->recent_reported_soc <= 20)
3221 schedule_delayed_work(&chip->update_heartbeat_work,
3222 round_jiffies_relative(msecs_to_jiffies
3223 (LOW_SOC_HEARTBEAT_MS)));
3224 else
3225 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003226 round_jiffies_relative(msecs_to_jiffies
3227 (chip->update_time)));
3228}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003229#define VDD_LOOP_ACTIVE_BIT BIT(3)
3230#define VDD_MAX_INCREASE_MV 400
3231static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3232module_param(vdd_max_increase_mv, int, 0644);
3233
3234static int ichg_threshold_ua = -400000;
3235module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003236
3237#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003238static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3239 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003240{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003241 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003242 int vbat_batt_terminal_mv;
3243 int reg_loop;
3244 int delta_mv = 0;
3245
3246 if (chip->rconn_mohm == 0) {
3247 pr_debug("Exiting as rconn_mohm is 0\n");
3248 return;
3249 }
3250 /* adjust vdd_max only in normal temperature zone */
3251 if (chip->is_bat_cool || chip->is_bat_warm) {
3252 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3253 chip->is_bat_cool, chip->is_bat_warm);
3254 return;
3255 }
3256
3257 reg_loop = pm_chg_get_regulation_loop(chip);
3258 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3259 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3260 reg_loop);
3261 return;
3262 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003263 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3264 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3265
3266 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3267
3268 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3269 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3270 delta_mv,
3271 programmed_vdd_max,
3272 adj_vdd_max_mv);
3273
3274 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3275 pr_debug("adj vdd_max lower than default max voltage\n");
3276 return;
3277 }
3278
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003279 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3280 * PM8921_CHG_VDDMAX_RES_MV;
3281
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003282 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3283 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003284 pr_debug("adjusting vdd_max_mv to %d to make "
3285 "vbat_batt_termial_uv = %d to %d\n",
3286 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3287 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3288}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003289
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003290static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3291{
3292 if (chip->is_bat_cool)
3293 pm_chg_vbatdet_set(the_chip,
3294 the_chip->cool_bat_voltage
3295 - the_chip->resume_voltage_delta);
3296 else if (chip->is_bat_warm)
3297 pm_chg_vbatdet_set(the_chip,
3298 the_chip->warm_bat_voltage
3299 - the_chip->resume_voltage_delta);
3300 else
3301 pm_chg_vbatdet_set(the_chip,
3302 the_chip->max_voltage_mv
3303 - the_chip->resume_voltage_delta);
3304}
3305
3306static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3307{
3308 unsigned int chg_current = chip->max_bat_chg_current;
3309
3310 if (chip->is_bat_cool)
3311 chg_current = min(chg_current, chip->cool_bat_chg_current);
3312
3313 if (chip->is_bat_warm)
3314 chg_current = min(chg_current, chip->warm_bat_chg_current);
3315
3316 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3317 chg_current = min(chg_current,
3318 chip->thermal_mitigation[thermal_mitigation]);
3319
3320 pm_chg_ibatmax_set(the_chip, chg_current);
3321}
3322
3323#define TEMP_HYSTERISIS_DECIDEGC 20
3324static void battery_cool(bool enter)
3325{
3326 pr_debug("enter = %d\n", enter);
3327 if (enter == the_chip->is_bat_cool)
3328 return;
3329 the_chip->is_bat_cool = enter;
3330 if (enter)
3331 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3332 else
3333 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3334 set_appropriate_battery_current(the_chip);
3335 set_appropriate_vbatdet(the_chip);
3336}
3337
3338static void battery_warm(bool enter)
3339{
3340 pr_debug("enter = %d\n", enter);
3341 if (enter == the_chip->is_bat_warm)
3342 return;
3343 the_chip->is_bat_warm = enter;
3344 if (enter)
3345 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3346 else
3347 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3348
3349 set_appropriate_battery_current(the_chip);
3350 set_appropriate_vbatdet(the_chip);
3351}
3352
3353static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3354{
3355 int temp = 0;
3356
3357 temp = get_prop_batt_temp(chip);
3358 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3359 temp, chip->warm_temp_dc,
3360 chip->cool_temp_dc);
3361
3362 if (chip->warm_temp_dc != INT_MIN) {
3363 if (chip->is_bat_warm
3364 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3365 battery_warm(false);
3366 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3367 battery_warm(true);
3368 }
3369
3370 if (chip->cool_temp_dc != INT_MIN) {
3371 if (chip->is_bat_cool
3372 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3373 battery_cool(false);
3374 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3375 battery_cool(true);
3376 }
3377}
3378
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003379enum {
3380 CHG_IN_PROGRESS,
3381 CHG_NOT_IN_PROGRESS,
3382 CHG_FINISHED,
3383};
3384
3385#define VBAT_TOLERANCE_MV 70
3386#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003387static int is_charging_finished(struct pm8921_chg_chip *chip,
3388 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003389{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003390 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003391 int regulation_loop, fast_chg, vcp;
3392 int rc;
3393 static int last_vbat_programmed = -EINVAL;
3394
3395 if (!is_ext_charging(chip)) {
3396 /* return if the battery is not being fastcharged */
3397 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3398 pr_debug("fast_chg = %d\n", fast_chg);
3399 if (fast_chg == 0)
3400 return CHG_NOT_IN_PROGRESS;
3401
3402 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3403 pr_debug("vcp = %d\n", vcp);
3404 if (vcp == 1)
3405 return CHG_IN_PROGRESS;
3406
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003407 /* reset count if battery is hot/cold */
3408 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3409 pr_debug("batt_temp_ok = %d\n", rc);
3410 if (rc == 0)
3411 return CHG_IN_PROGRESS;
3412
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003413 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3414 if (rc) {
3415 pr_err("couldnt read vddmax rc = %d\n", rc);
3416 return CHG_IN_PROGRESS;
3417 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003418 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3419 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003420
3421 if (last_vbat_programmed == -EINVAL)
3422 last_vbat_programmed = vbat_programmed;
3423 if (last_vbat_programmed != vbat_programmed) {
3424 /* vddmax changed, reset and check again */
3425 pr_debug("vddmax = %d last_vdd_max=%d\n",
3426 vbat_programmed, last_vbat_programmed);
3427 last_vbat_programmed = vbat_programmed;
3428 return CHG_IN_PROGRESS;
3429 }
3430
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003431 if (chip->is_bat_cool)
3432 vbat_intended = chip->cool_bat_voltage;
3433 else if (chip->is_bat_warm)
3434 vbat_intended = chip->warm_bat_voltage;
3435 else
3436 vbat_intended = chip->max_voltage_mv;
3437
3438 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3439 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3440 vbat_batt_terminal_uv,
3441 vbat_intended);
3442 return CHG_IN_PROGRESS;
3443 }
3444
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003445 regulation_loop = pm_chg_get_regulation_loop(chip);
3446 if (regulation_loop < 0) {
3447 pr_err("couldnt read the regulation loop err=%d\n",
3448 regulation_loop);
3449 return CHG_IN_PROGRESS;
3450 }
3451 pr_debug("regulation_loop=%d\n", regulation_loop);
3452
3453 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3454 return CHG_IN_PROGRESS;
3455 } /* !is_ext_charging */
3456
3457 /* reset count if battery chg current is more than iterm */
3458 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3459 if (rc) {
3460 pr_err("couldnt read iterm rc = %d\n", rc);
3461 return CHG_IN_PROGRESS;
3462 }
3463
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003464 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3465 iterm_programmed, ichg_meas_ma);
3466 /*
3467 * ichg_meas_ma < 0 means battery is drawing current
3468 * ichg_meas_ma > 0 means battery is providing current
3469 */
3470 if (ichg_meas_ma > 0)
3471 return CHG_IN_PROGRESS;
3472
3473 if (ichg_meas_ma * -1 > iterm_programmed)
3474 return CHG_IN_PROGRESS;
3475
3476 return CHG_FINISHED;
3477}
3478
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003479#define COMP_OVERRIDE_HOT_BANK 6
3480#define COMP_OVERRIDE_COLD_BANK 7
3481#define COMP_OVERRIDE_BIT BIT(1)
3482static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3483{
3484 u8 val;
3485 int rc = 0;
3486
3487 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3488
3489 if (flag)
3490 val |= 0x01;
3491
3492 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3493 if (rc < 0)
3494 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3495
3496 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3497 return rc;
3498}
3499
3500static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3501{
3502 u8 val;
3503 int rc = 0;
3504
3505 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3506
3507 if (flag)
3508 val |= 0x01;
3509
3510 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3511 if (rc < 0)
3512 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3513
3514 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3515 return rc;
3516}
3517
3518static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3519{
3520 int rc = 0;
3521 u8 reg;
3522 u8 val;
3523
3524 val = COMP_OVERRIDE_HOT_BANK << 2;
3525 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3526 if (rc < 0) {
3527 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3528 goto cold_init;
3529 }
3530 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3531 if (rc < 0) {
3532 pr_err("Could not read bank %d of override rc = %d\n",
3533 COMP_OVERRIDE_HOT_BANK, rc);
3534 goto cold_init;
3535 }
3536 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3537 /* for now override it as not hot */
3538 rc = pm_chg_override_hot(chip, 0);
3539 if (rc < 0)
3540 pr_err("Could not override hot rc = %d\n", rc);
3541 }
3542
3543cold_init:
3544 val = COMP_OVERRIDE_COLD_BANK << 2;
3545 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3546 if (rc < 0) {
3547 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3548 return;
3549 }
3550 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3551 if (rc < 0) {
3552 pr_err("Could not read bank %d of override rc = %d\n",
3553 COMP_OVERRIDE_COLD_BANK, rc);
3554 return;
3555 }
3556 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3557 /* for now override it as not cold */
3558 rc = pm_chg_override_cold(chip, 0);
3559 if (rc < 0)
3560 pr_err("Could not override cold rc = %d\n", rc);
3561 }
3562}
3563
3564static void btc_override_worker(struct work_struct *work)
3565{
3566 int decidegc;
3567 int temp;
3568 int rc = 0;
3569 struct delayed_work *dwork = to_delayed_work(work);
3570 struct pm8921_chg_chip *chip = container_of(dwork,
3571 struct pm8921_chg_chip, btc_override_work);
3572
3573 if (!chip->btc_override) {
3574 pr_err("called when not enabled\n");
3575 return;
3576 }
3577
3578 decidegc = get_prop_batt_temp(chip);
3579
3580 pr_debug("temp=%d\n", decidegc);
3581
3582 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3583 if (temp) {
3584 if (decidegc < chip->btc_override_hot_decidegc)
3585 /* stop forcing batt hot */
3586 rc = pm_chg_override_hot(chip, 0);
3587 if (rc)
3588 pr_err("Couldnt write 0 to hot comp\n");
3589 } else {
3590 if (decidegc >= chip->btc_override_hot_decidegc)
3591 /* start forcing batt hot */
3592 rc = pm_chg_override_hot(chip, 1);
3593 if (rc && chip->btc_panic_if_cant_stop_chg)
3594 panic("Couldnt override comps to stop chg\n");
3595 }
3596
3597 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3598 if (temp) {
3599 if (decidegc > chip->btc_override_cold_decidegc)
3600 /* stop forcing batt cold */
3601 rc = pm_chg_override_cold(chip, 0);
3602 if (rc)
3603 pr_err("Couldnt write 0 to cold comp\n");
3604 } else {
3605 if (decidegc <= chip->btc_override_cold_decidegc)
3606 /* start forcing batt cold */
3607 rc = pm_chg_override_cold(chip, 1);
3608 if (rc && chip->btc_panic_if_cant_stop_chg)
3609 panic("Couldnt override comps to stop chg\n");
3610 }
3611
3612 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3613 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3614 schedule_delayed_work(&chip->btc_override_work,
3615 round_jiffies_relative(msecs_to_jiffies
3616 (chip->btc_delay_ms)));
3617 return;
3618 }
3619
3620 rc = pm_chg_override_hot(chip, 0);
3621 if (rc)
3622 pr_err("Couldnt write 0 to hot comp\n");
3623 rc = pm_chg_override_cold(chip, 0);
3624 if (rc)
3625 pr_err("Couldnt write 0 to cold comp\n");
3626}
3627
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003628/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003629 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003630 * has happened
3631 *
3632 * If all conditions favouring, if the charge current is
3633 * less than the term current for three consecutive times
3634 * an EOC has happened.
3635 * The wakelock is released if there is no need to reshedule
3636 * - this happens when the battery is removed or EOC has
3637 * happened
3638 */
3639#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003640static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003641{
3642 struct delayed_work *dwork = to_delayed_work(work);
3643 struct pm8921_chg_chip *chip = container_of(dwork,
3644 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003645 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003646 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003647 int vbat_meas_uv, vbat_meas_mv;
3648 int ichg_meas_ua, ichg_meas_ma;
3649 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003650
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003651 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3652 &ichg_meas_ua, &vbat_meas_uv);
3653 vbat_meas_mv = vbat_meas_uv / 1000;
3654 /* rconn_mohm is in milliOhms */
3655 ichg_meas_ma = ichg_meas_ua / 1000;
3656 vbat_batt_terminal_uv = vbat_meas_uv
3657 + ichg_meas_ma
3658 * the_chip->rconn_mohm;
3659
3660 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003661
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003662 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003663 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003664 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003665 }
3666
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003667 if (end == CHG_FINISHED) {
3668 count++;
3669 } else {
3670 count = 0;
3671 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003672
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003673 if (count == CONSECUTIVE_COUNT) {
3674 count = 0;
3675 pr_info("End of Charging\n");
3676
3677 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003678
Amir Samuelovd31ef502011-10-26 14:41:36 +02003679 if (is_ext_charging(chip))
3680 chip->ext_charge_done = true;
3681
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003682 if (chip->is_bat_warm || chip->is_bat_cool)
3683 chip->bms_notify.is_battery_full = 0;
3684 else
3685 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003686 /* declare end of charging by invoking chgdone interrupt */
3687 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003688 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003689 check_temp_thresholds(chip);
3690 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003691 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003692 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003693 round_jiffies_relative(msecs_to_jiffies
3694 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003695 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003696 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003697
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003698eoc_worker_stop:
3699 wake_unlock(&chip->eoc_wake_lock);
3700 /* set the vbatdet back, in case it was changed to trigger charging */
3701 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003702}
3703
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003704/**
3705 * set_disable_status_param -
3706 *
3707 * Internal function to disable battery charging and also disable drawing
3708 * any current from the source. The device is forced to run on a battery
3709 * after this.
3710 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711static int set_disable_status_param(const char *val, struct kernel_param *kp)
3712{
3713 int ret;
3714 struct pm8921_chg_chip *chip = the_chip;
3715
3716 ret = param_set_int(val, kp);
3717 if (ret) {
3718 pr_err("error setting value %d\n", ret);
3719 return ret;
3720 }
3721 pr_info("factory set disable param to %d\n", charging_disabled);
3722 if (chip) {
3723 pm_chg_auto_enable(chip, !charging_disabled);
3724 pm_chg_charge_dis(chip, charging_disabled);
3725 }
3726 return 0;
3727}
3728module_param_call(disabled, set_disable_status_param, param_get_uint,
3729 &charging_disabled, 0644);
3730
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003731static int rconn_mohm;
3732static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3733{
3734 int ret;
3735 struct pm8921_chg_chip *chip = the_chip;
3736
3737 ret = param_set_int(val, kp);
3738 if (ret) {
3739 pr_err("error setting value %d\n", ret);
3740 return ret;
3741 }
3742 if (chip)
3743 chip->rconn_mohm = rconn_mohm;
3744 return 0;
3745}
3746module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3747 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003748/**
3749 * set_thermal_mitigation_level -
3750 *
3751 * Internal function to control battery charging current to reduce
3752 * temperature
3753 */
3754static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3755{
3756 int ret;
3757 struct pm8921_chg_chip *chip = the_chip;
3758
3759 ret = param_set_int(val, kp);
3760 if (ret) {
3761 pr_err("error setting value %d\n", ret);
3762 return ret;
3763 }
3764
3765 if (!chip) {
3766 pr_err("called before init\n");
3767 return -EINVAL;
3768 }
3769
3770 if (!chip->thermal_mitigation) {
3771 pr_err("no thermal mitigation\n");
3772 return -EINVAL;
3773 }
3774
3775 if (thermal_mitigation < 0
3776 || thermal_mitigation >= chip->thermal_levels) {
3777 pr_err("out of bound level selected\n");
3778 return -EINVAL;
3779 }
3780
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003781 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003782 return ret;
3783}
3784module_param_call(thermal_mitigation, set_therm_mitigation_level,
3785 param_get_uint,
3786 &thermal_mitigation, 0644);
3787
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003788static int set_usb_max_current(const char *val, struct kernel_param *kp)
3789{
3790 int ret, mA;
3791 struct pm8921_chg_chip *chip = the_chip;
3792
3793 ret = param_set_int(val, kp);
3794 if (ret) {
3795 pr_err("error setting value %d\n", ret);
3796 return ret;
3797 }
3798 if (chip) {
3799 pr_warn("setting current max to %d\n", usb_max_current);
3800 pm_chg_iusbmax_get(chip, &mA);
3801 if (mA > usb_max_current)
3802 pm8921_charger_vbus_draw(usb_max_current);
3803 return 0;
3804 }
3805 return -EINVAL;
3806}
David Keitelacf57c82012-03-07 18:48:50 -08003807module_param_call(usb_max_current, set_usb_max_current,
3808 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003809
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810static void free_irqs(struct pm8921_chg_chip *chip)
3811{
3812 int i;
3813
3814 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3815 if (chip->pmic_chg_irq[i]) {
3816 free_irq(chip->pmic_chg_irq[i], chip);
3817 chip->pmic_chg_irq[i] = 0;
3818 }
3819}
3820
David Keitel88e1b572012-01-11 11:57:14 -08003821/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3823{
3824 unsigned long flags;
3825 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003826 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003827
3828 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3829 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3830
3831 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003832 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003833 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003834 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003835 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837
3838 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3839 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3840 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003841 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003842 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3843 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003844 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003845 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3846 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003847 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848
3849 spin_lock_irqsave(&vbus_lock, flags);
3850 if (usb_chg_current) {
3851 /* reissue a vbus draw call */
3852 __pm8921_charger_vbus_draw(usb_chg_current);
3853 }
3854 spin_unlock_irqrestore(&vbus_lock, flags);
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003855 /*
3856 * The bootloader could have started charging, a fastchg interrupt
3857 * might not happen. Check the real time status and if it is fast
3858 * charging invoke the handler so that the eoc worker could be
3859 * started
3860 */
3861 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3862 if (is_fast_chg)
3863 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003864
3865 fsm_state = pm_chg_get_fsm_state(chip);
3866 if (is_battery_charging(fsm_state)) {
3867 chip->bms_notify.is_charging = 1;
3868 pm8921_bms_charging_began();
3869 }
3870
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003871 check_battery_valid(chip);
3872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003873 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3874 chip->usb_present,
3875 chip->dc_present,
3876 get_prop_batt_present(chip),
3877 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003878
3879 /* Determine which USB trim column to use */
3880 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3881 chip->usb_trim_table = usb_trim_8917_table;
3882 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3883 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884}
3885
3886struct pm_chg_irq_init_data {
3887 unsigned int irq_id;
3888 char *name;
3889 unsigned long flags;
3890 irqreturn_t (*handler)(int, void *);
3891};
3892
3893#define CHG_IRQ(_id, _flags, _handler) \
3894{ \
3895 .irq_id = _id, \
3896 .name = #_id, \
3897 .flags = _flags, \
3898 .handler = _handler, \
3899}
3900struct pm_chg_irq_init_data chg_irq_data[] = {
3901 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3902 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003903 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3904 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003905 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3906 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3908 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3909 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3910 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3911 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3912 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3913 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3914 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003915 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3916 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3918 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3919 batt_removed_irq_handler),
3920 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3921 batttemp_hot_irq_handler),
3922 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3923 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3924 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003925 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3926 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003927 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3928 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003929 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3930 coarse_det_low_irq_handler),
3931 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3932 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3933 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3934 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3935 batfet_irq_handler),
3936 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3937 dcin_valid_irq_handler),
3938 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3939 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003940 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003941};
3942
3943static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3944 struct platform_device *pdev)
3945{
3946 struct resource *res;
3947 int ret, i;
3948
3949 ret = 0;
3950 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3951
3952 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3953 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3954 chg_irq_data[i].name);
3955 if (res == NULL) {
3956 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3957 goto err_out;
3958 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003959 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003960 ret = request_irq(res->start, chg_irq_data[i].handler,
3961 chg_irq_data[i].flags,
3962 chg_irq_data[i].name, chip);
3963 if (ret < 0) {
3964 pr_err("couldn't request %d (%s) %d\n", res->start,
3965 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003966 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003967 goto err_out;
3968 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3970 }
3971 return 0;
3972
3973err_out:
3974 free_irqs(chip);
3975 return -EINVAL;
3976}
3977
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003978#define VREF_BATT_THERM_FORCE_ON BIT(7)
3979static void detect_battery_removal(struct pm8921_chg_chip *chip)
3980{
3981 u8 temp;
3982
3983 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3984 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3985
3986 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3987 /*
3988 * batt therm force on bit is battery backed and is default 0
3989 * The charger sets this bit at init time. If this bit is found
3990 * 0 that means the battery was removed. Tell the bms about it
3991 */
3992 pm8921_bms_invalidate_shutdown_soc();
3993}
3994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003995#define ENUM_TIMER_STOP_BIT BIT(1)
3996#define BOOT_DONE_BIT BIT(6)
3997#define CHG_BATFET_ON_BIT BIT(3)
3998#define CHG_VCP_EN BIT(0)
3999#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4000#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004001#define PM_SUB_REV 0x001
4002#define MIN_CHARGE_CURRENT_MA 350
4003#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4005{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004006 u8 subrev;
4007 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004009 spin_lock_init(&lpm_lock);
4010 rc = pm8921_apply_19p2mhz_kickstart(chip);
4011 if (rc) {
4012 pr_err("Failed to apply kickstart rc=%d\n", rc);
4013 return rc;
4014 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004015
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004016 detect_battery_removal(chip);
4017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004019 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 if (rc) {
4021 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4022 return rc;
4023 }
4024
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004025 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4026
4027 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4028 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4029
4030 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032 if (rc) {
4033 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004034 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004035 return rc;
4036 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004037 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004038 chip->max_voltage_mv
4039 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040 if (rc) {
4041 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004042 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 return rc;
4044 }
4045
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004046 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004047 if (rc) {
4048 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004049 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050 return rc;
4051 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004052
4053 if (chip->safe_current_ma == 0)
4054 chip->safe_current_ma = SAFE_CURRENT_MA;
4055
4056 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 if (rc) {
4058 pr_err("Failed to set max voltage to %d rc=%d\n",
4059 SAFE_CURRENT_MA, rc);
4060 return rc;
4061 }
4062
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004063 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064 if (rc) {
4065 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4066 return rc;
4067 }
4068
4069 rc = pm_chg_iterm_set(chip, chip->term_current);
4070 if (rc) {
4071 pr_err("Failed to set term current to %d rc=%d\n",
4072 chip->term_current, rc);
4073 return rc;
4074 }
4075
4076 /* Disable the ENUM TIMER */
4077 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4078 ENUM_TIMER_STOP_BIT);
4079 if (rc) {
4080 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4081 return rc;
4082 }
4083
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004084 fcc_uah = pm8921_bms_get_fcc();
4085 if (fcc_uah > 0) {
4086 safety_time = div_s64((s64)fcc_uah * 60,
4087 1000 * MIN_CHARGE_CURRENT_MA);
4088 /* add 20 minutes of buffer time */
4089 safety_time += 20;
4090
4091 /* make sure we do not exceed the maximum programmable time */
4092 if (safety_time > PM8921_CHG_TCHG_MAX)
4093 safety_time = PM8921_CHG_TCHG_MAX;
4094 }
4095
4096 rc = pm_chg_tchg_max_set(chip, safety_time);
4097 if (rc) {
4098 pr_err("Failed to set max time to %d minutes rc=%d\n",
4099 safety_time, rc);
4100 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004101 }
4102
4103 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004104 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004105 if (rc) {
4106 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004107 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004108 return rc;
4109 }
4110 }
4111
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004112 if (chip->vin_min != 0) {
4113 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4114 if (rc) {
4115 pr_err("Failed to set vin min to %d mV rc=%d\n",
4116 chip->vin_min, rc);
4117 return rc;
4118 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004119 } else {
4120 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004121 }
4122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123 rc = pm_chg_disable_wd(chip);
4124 if (rc) {
4125 pr_err("Failed to disable wd rc=%d\n", rc);
4126 return rc;
4127 }
4128
4129 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4130 CHG_BAT_TEMP_DIS_BIT, 0);
4131 if (rc) {
4132 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4133 return rc;
4134 }
4135 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004136 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4137 rc = pm_chg_write(chip,
4138 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4139 else
4140 rc = pm_chg_write(chip,
4141 CHG_BUCK_CLOCK_CTRL, 0x15);
4142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004143 if (rc) {
4144 pr_err("Failed to switch buck clk rc=%d\n", rc);
4145 return rc;
4146 }
4147
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004148 if (chip->trkl_voltage != 0) {
4149 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4150 if (rc) {
4151 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4152 chip->trkl_voltage, rc);
4153 return rc;
4154 }
4155 }
4156
4157 if (chip->weak_voltage != 0) {
4158 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4159 if (rc) {
4160 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4161 chip->weak_voltage, rc);
4162 return rc;
4163 }
4164 }
4165
4166 if (chip->trkl_current != 0) {
4167 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4168 if (rc) {
4169 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4170 chip->trkl_voltage, rc);
4171 return rc;
4172 }
4173 }
4174
4175 if (chip->weak_current != 0) {
4176 rc = pm_chg_iweak_set(chip, chip->weak_current);
4177 if (rc) {
4178 pr_err("Failed to set weak current to %dmA rc=%d\n",
4179 chip->weak_current, rc);
4180 return rc;
4181 }
4182 }
4183
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004184 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4185 if (rc) {
4186 pr_err("Failed to set cold config %d rc=%d\n",
4187 chip->cold_thr, rc);
4188 }
4189
4190 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4191 if (rc) {
4192 pr_err("Failed to set hot config %d rc=%d\n",
4193 chip->hot_thr, rc);
4194 }
4195
Jay Chokshid674a512012-03-15 14:06:04 -07004196 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4197 if (rc) {
4198 pr_err("Failed to set charger LED src config %d rc=%d\n",
4199 chip->led_src_config, rc);
4200 }
4201
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004202 /* Workarounds for die 3.0 */
4203 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4204 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4205 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4206 if (rc) {
4207 pr_err("read failed: addr=%03X, rc=%d\n",
4208 PM_SUB_REV, rc);
4209 return rc;
4210 }
4211 /* Check if die 3.0.1 is present */
4212 if (subrev & 0x1)
4213 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4214 else
4215 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216 }
4217
David Keitel0789fc62012-06-07 17:43:27 -07004218 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004219 /* Set PM8917 USB_OVP debounce time to 15 ms */
4220 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4221 OVP_DEBOUNCE_TIME, 0x6);
4222 if (rc) {
4223 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4224 return rc;
4225 }
4226
4227 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004228 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004229 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004230 rc = pm_chg_uvd_threshold_set(chip,
4231 chip->uvd_voltage_mv);
4232 if (rc) {
4233 pr_err("Failed to set UVD threshold %drc=%d\n",
4234 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004235 return rc;
4236 }
David Keitel0789fc62012-06-07 17:43:27 -07004237 }
4238 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004239
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004240 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004241
David Keitela3c0d822011-11-03 14:18:52 -07004242 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004243 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004244
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004245 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4246 VREF_BATT_THERM_FORCE_ON);
4247 if (rc)
4248 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004250 rc = pm_chg_charge_dis(chip, charging_disabled);
4251 if (rc) {
4252 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4253 return rc;
4254 }
4255
4256 rc = pm_chg_auto_enable(chip, !charging_disabled);
4257 if (rc) {
4258 pr_err("Failed to enable charging rc=%d\n", rc);
4259 return rc;
4260 }
4261
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004262 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4263 /* Clear kickstart */
4264 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4265 if (rc) {
4266 pr_err("Failed to clear kickstart rc=%d\n", rc);
4267 return rc;
4268 }
4269
4270 /* From here the lpm_workaround will be active */
4271 chip->lockup_lpm_wrkarnd = true;
4272
4273 /* Enable LPM */
4274 pm8921_chg_set_lpm(chip, 1);
4275 }
4276
4277 if (chip->lockup_lpm_wrkarnd) {
4278 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4279 if (IS_ERR(chip->vreg_xoadc))
4280 return -ENODEV;
4281
4282 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4283 if (rc < 0) {
4284 pr_err("Failed to set configure HPM rc=%d\n", rc);
4285 return rc;
4286 }
4287
4288 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4289 if (rc) {
4290 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4291 return rc;
4292 }
4293
4294 rc = regulator_enable(chip->vreg_xoadc);
4295 if (rc) {
4296 pr_err("Failed to enable L14 rc=%d\n", rc);
4297 return rc;
4298 }
4299 }
4300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004301 return 0;
4302}
4303
4304static int get_rt_status(void *data, u64 * val)
4305{
4306 int i = (int)data;
4307 int ret;
4308
4309 /* global irq number is passed in via data */
4310 ret = pm_chg_get_rt_status(the_chip, i);
4311 *val = ret;
4312 return 0;
4313}
4314DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4315
4316static int get_fsm_status(void *data, u64 * val)
4317{
4318 u8 temp;
4319
4320 temp = pm_chg_get_fsm_state(the_chip);
4321 *val = temp;
4322 return 0;
4323}
4324DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4325
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004326static int get_reg_loop(void *data, u64 * val)
4327{
4328 u8 temp;
4329
4330 if (!the_chip) {
4331 pr_err("%s called before init\n", __func__);
4332 return -EINVAL;
4333 }
4334 temp = pm_chg_get_regulation_loop(the_chip);
4335 *val = temp;
4336 return 0;
4337}
4338DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004340static int get_reg(void *data, u64 * val)
4341{
4342 int addr = (int)data;
4343 int ret;
4344 u8 temp;
4345
4346 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4347 if (ret) {
4348 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4349 addr, temp, ret);
4350 return -EAGAIN;
4351 }
4352 *val = temp;
4353 return 0;
4354}
4355
4356static int set_reg(void *data, u64 val)
4357{
4358 int addr = (int)data;
4359 int ret;
4360 u8 temp;
4361
4362 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004363 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004364 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004365 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004366 addr, temp, ret);
4367 return -EAGAIN;
4368 }
4369 return 0;
4370}
4371DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4372
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004373static int reg_loop;
4374#define MAX_REG_LOOP_CHAR 10
4375static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4376{
4377 u8 temp;
4378
4379 if (!the_chip) {
4380 pr_err("called before init\n");
4381 return -EINVAL;
4382 }
4383 temp = pm_chg_get_regulation_loop(the_chip);
4384 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4385}
4386module_param_call(reg_loop, NULL, get_reg_loop_param,
4387 &reg_loop, 0644);
4388
4389static int max_chg_ma;
4390#define MAX_MA_CHAR 10
4391static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4392{
4393 if (!the_chip) {
4394 pr_err("called before init\n");
4395 return -EINVAL;
4396 }
4397 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4398}
4399module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4400 &max_chg_ma, 0644);
4401static int ibatmax_ma;
4402static int set_ibat_max(const char *val, struct kernel_param *kp)
4403{
4404 int rc;
4405
4406 if (!the_chip) {
4407 pr_err("called before init\n");
4408 return -EINVAL;
4409 }
4410
4411 rc = param_set_int(val, kp);
4412 if (rc) {
4413 pr_err("error setting value %d\n", rc);
4414 return rc;
4415 }
4416
4417 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4418 <= the_chip->ibatmax_max_adj_ma) {
4419 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4420 if (rc) {
4421 pr_err("Failed to set ibatmax rc = %d\n", rc);
4422 return rc;
4423 }
4424 }
4425
4426 return 0;
4427}
4428static int get_ibat_max(char *buf, struct kernel_param *kp)
4429{
4430 int ibat_ma;
4431 int rc;
4432
4433 if (!the_chip) {
4434 pr_err("called before init\n");
4435 return -EINVAL;
4436 }
4437
4438 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4439 if (rc) {
4440 pr_err("ibatmax_get error = %d\n", rc);
4441 return rc;
4442 }
4443
4444 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4445}
4446module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4447 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004448enum {
4449 BAT_WARM_ZONE,
4450 BAT_COOL_ZONE,
4451};
4452static int get_warm_cool(void *data, u64 * val)
4453{
4454 if (!the_chip) {
4455 pr_err("%s called before init\n", __func__);
4456 return -EINVAL;
4457 }
4458 if ((int)data == BAT_WARM_ZONE)
4459 *val = the_chip->is_bat_warm;
4460 if ((int)data == BAT_COOL_ZONE)
4461 *val = the_chip->is_bat_cool;
4462 return 0;
4463}
4464DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004466static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4467{
4468 int i;
4469
4470 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4471
4472 if (IS_ERR(chip->dent)) {
4473 pr_err("pmic charger couldnt create debugfs dir\n");
4474 return;
4475 }
4476
4477 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4478 (void *)CHG_CNTRL, &reg_fops);
4479 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4480 (void *)CHG_CNTRL_2, &reg_fops);
4481 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4482 (void *)CHG_CNTRL_3, &reg_fops);
4483 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4484 (void *)PBL_ACCESS1, &reg_fops);
4485 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4486 (void *)PBL_ACCESS2, &reg_fops);
4487 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4488 (void *)SYS_CONFIG_1, &reg_fops);
4489 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4490 (void *)SYS_CONFIG_2, &reg_fops);
4491 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4492 (void *)CHG_VDD_MAX, &reg_fops);
4493 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4494 (void *)CHG_VDD_SAFE, &reg_fops);
4495 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4496 (void *)CHG_VBAT_DET, &reg_fops);
4497 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4498 (void *)CHG_IBAT_MAX, &reg_fops);
4499 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4500 (void *)CHG_IBAT_SAFE, &reg_fops);
4501 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4502 (void *)CHG_VIN_MIN, &reg_fops);
4503 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4504 (void *)CHG_VTRICKLE, &reg_fops);
4505 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4506 (void *)CHG_ITRICKLE, &reg_fops);
4507 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4508 (void *)CHG_ITERM, &reg_fops);
4509 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4510 (void *)CHG_TCHG_MAX, &reg_fops);
4511 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4512 (void *)CHG_TWDOG, &reg_fops);
4513 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4514 (void *)CHG_TEMP_THRESH, &reg_fops);
4515 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4516 (void *)CHG_COMP_OVR, &reg_fops);
4517 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4518 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4519 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4520 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4521 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4522 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4523 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4524 (void *)CHG_TEST, &reg_fops);
4525
4526 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4527 &fsm_fops);
4528
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004529 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4530 &reg_loop_fops);
4531
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004532 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4533 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4534 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4535 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004537 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4538 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4539 debugfs_create_file(chg_irq_data[i].name, 0444,
4540 chip->dent,
4541 (void *)chg_irq_data[i].irq_id,
4542 &rt_fops);
4543 }
4544}
4545
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004546static int pm8921_charger_suspend_noirq(struct device *dev)
4547{
4548 int rc;
4549 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4550
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004551 if (chip->lockup_lpm_wrkarnd) {
4552 rc = regulator_disable(chip->vreg_xoadc);
4553 if (rc)
4554 pr_err("Failed to disable L14 rc=%d\n", rc);
4555
4556 rc = pm8921_apply_19p2mhz_kickstart(chip);
4557 if (rc)
4558 pr_err("Failed to apply kickstart rc=%d\n", rc);
4559 }
4560
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004561 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4562 if (rc)
4563 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004564 return 0;
4565}
4566
4567static int pm8921_charger_resume_noirq(struct device *dev)
4568{
4569 int rc;
4570 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4571
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004572 if (chip->lockup_lpm_wrkarnd) {
4573 rc = regulator_enable(chip->vreg_xoadc);
4574 if (rc)
4575 pr_err("Failed to enable L14 rc=%d\n", rc);
4576
4577 rc = pm8921_apply_19p2mhz_kickstart(chip);
4578 if (rc)
4579 pr_err("Failed to apply kickstart rc=%d\n", rc);
4580 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004581
4582 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4583 VREF_BATT_THERM_FORCE_ON);
4584 if (rc)
4585 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4586 return 0;
4587}
4588
David Keitelf2226022011-12-13 15:55:50 -08004589static int pm8921_charger_resume(struct device *dev)
4590{
David Keitelf2226022011-12-13 15:55:50 -08004591 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4592
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004593 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4594 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4595 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4596 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004597
4598 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4599 is_usb_chg_plugged_in(the_chip)))
4600 schedule_delayed_work(&chip->btc_override_work, 0);
4601
David Keitelf2226022011-12-13 15:55:50 -08004602 return 0;
4603}
4604
4605static int pm8921_charger_suspend(struct device *dev)
4606{
David Keitelf2226022011-12-13 15:55:50 -08004607 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4608
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004609 if (chip->btc_override)
4610 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004611
4612 if (is_usb_chg_plugged_in(chip)) {
4613 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4614 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4615 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004616
David Keitelf2226022011-12-13 15:55:50 -08004617 return 0;
4618}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004619static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4620{
4621 int rc = 0;
4622 struct pm8921_chg_chip *chip;
4623 const struct pm8921_charger_platform_data *pdata
4624 = pdev->dev.platform_data;
4625
4626 if (!pdata) {
4627 pr_err("missing platform data\n");
4628 return -EINVAL;
4629 }
4630
4631 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4632 GFP_KERNEL);
4633 if (!chip) {
4634 pr_err("Cannot allocate pm_chg_chip\n");
4635 return -ENOMEM;
4636 }
4637
4638 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004639 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004641 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004642 chip->alarm_low_mv = pdata->alarm_low_mv;
4643 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004644 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004645 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004646 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004647 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004648 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004649 chip->term_current = pdata->term_current;
4650 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004651 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004652 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4653 chip->batt_id_min = pdata->batt_id_min;
4654 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004655 if (pdata->cool_temp != INT_MIN)
4656 chip->cool_temp_dc = pdata->cool_temp * 10;
4657 else
4658 chip->cool_temp_dc = INT_MIN;
4659
4660 if (pdata->warm_temp != INT_MIN)
4661 chip->warm_temp_dc = pdata->warm_temp * 10;
4662 else
4663 chip->warm_temp_dc = INT_MIN;
4664
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004665 chip->temp_check_period = pdata->temp_check_period;
4666 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004667 /* Assign to corresponding module parameter */
4668 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004669 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4670 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4671 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4672 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004673 chip->trkl_voltage = pdata->trkl_voltage;
4674 chip->weak_voltage = pdata->weak_voltage;
4675 chip->trkl_current = pdata->trkl_current;
4676 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004677 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004678 chip->thermal_mitigation = pdata->thermal_mitigation;
4679 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004680
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004681 chip->cold_thr = pdata->cold_thr;
4682 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004683 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004684 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004685 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004686 chip->battery_less_hardware = pdata->battery_less_hardware;
4687 chip->btc_override = pdata->btc_override;
4688 if (chip->btc_override) {
4689 chip->btc_delay_ms = pdata->btc_delay_ms;
4690 chip->btc_override_cold_decidegc
4691 = pdata->btc_override_cold_degc * 10;
4692 chip->btc_override_hot_decidegc
4693 = pdata->btc_override_hot_degc * 10;
4694 chip->btc_panic_if_cant_stop_chg
4695 = pdata->btc_panic_if_cant_stop_chg;
4696 }
4697
4698 if (chip->battery_less_hardware)
4699 charging_disabled = 1;
4700
4701 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4702 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004704 rc = pm8921_chg_hw_init(chip);
4705 if (rc) {
4706 pr_err("couldn't init hardware rc=%d\n", rc);
4707 goto free_chip;
4708 }
4709
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004710 if (chip->btc_override)
4711 pm8921_chg_btc_override_init(chip);
4712
4713 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
4714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004715 chip->usb_psy.name = "usb",
4716 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4717 chip->usb_psy.supplied_to = pm_power_supplied_to,
4718 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004719 chip->usb_psy.properties = pm_power_props_usb,
4720 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4721 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004722 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004723
David Keitel6ed71a52012-01-30 12:42:18 -08004724 chip->dc_psy.name = "pm8921-dc",
4725 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4726 chip->dc_psy.supplied_to = pm_power_supplied_to,
4727 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004728 chip->dc_psy.properties = pm_power_props_mains,
4729 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4730 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004732 chip->batt_psy.name = "battery",
4733 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4734 chip->batt_psy.properties = msm_batt_power_props,
4735 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4736 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004737 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738 rc = power_supply_register(chip->dev, &chip->usb_psy);
4739 if (rc < 0) {
4740 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004741 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 }
4743
David Keitel6ed71a52012-01-30 12:42:18 -08004744 rc = power_supply_register(chip->dev, &chip->dc_psy);
4745 if (rc < 0) {
4746 pr_err("power_supply_register usb failed rc = %d\n", rc);
4747 goto unregister_usb;
4748 }
4749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750 rc = power_supply_register(chip->dev, &chip->batt_psy);
4751 if (rc < 0) {
4752 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004753 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 }
4755
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004756 platform_set_drvdata(pdev, chip);
4757 the_chip = chip;
4758
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004759 /* set initial state of the USB charger type to UNKNOWN */
4760 power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
4761
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004762 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004763 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004764 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4765 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004766 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004767
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004768 INIT_WORK(&chip->bms_notify.work, bms_notify);
4769 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4770
4771 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4772 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 rc = request_irqs(chip, pdev);
4775 if (rc) {
4776 pr_err("couldn't register interrupts rc=%d\n", rc);
4777 goto unregister_batt;
4778 }
4779
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004780 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004781 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004782 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004783 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004784
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785 create_debugfs_entries(chip);
4786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004787 /* determine what state the charger is in */
4788 determine_initial_state(chip);
4789
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004790 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004791 schedule_delayed_work(&chip->update_heartbeat_work,
4792 round_jiffies_relative(msecs_to_jiffies
4793 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794 return 0;
4795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004797 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004799unregister_dc:
4800 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004801unregister_usb:
4802 power_supply_unregister(&chip->usb_psy);
4803free_chip:
4804 kfree(chip);
4805 return rc;
4806}
4807
4808static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4809{
4810 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4811
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004812 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813 free_irqs(chip);
4814 platform_set_drvdata(pdev, NULL);
4815 the_chip = NULL;
4816 kfree(chip);
4817 return 0;
4818}
David Keitelf2226022011-12-13 15:55:50 -08004819static const struct dev_pm_ops pm8921_pm_ops = {
4820 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004821 .suspend_noirq = pm8921_charger_suspend_noirq,
4822 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004823 .resume = pm8921_charger_resume,
4824};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004826 .probe = pm8921_charger_probe,
4827 .remove = __devexit_p(pm8921_charger_remove),
4828 .driver = {
4829 .name = PM8921_CHARGER_DEV_NAME,
4830 .owner = THIS_MODULE,
4831 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 },
4833};
4834
4835static int __init pm8921_charger_init(void)
4836{
4837 return platform_driver_register(&pm8921_charger_driver);
4838}
4839
4840static void __exit pm8921_charger_exit(void)
4841{
4842 platform_driver_unregister(&pm8921_charger_driver);
4843}
4844
4845late_initcall(pm8921_charger_init);
4846module_exit(pm8921_charger_exit);
4847
4848MODULE_LICENSE("GPL v2");
4849MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4850MODULE_VERSION("1.0");
4851MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);