blob: 7478ab959656f8afad7b6aebb5b32a4b5a61496f [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
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301950 if (usb_target_ma)
1951 usb_target_ma = mA;
1952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 spin_lock_irqsave(&vbus_lock, flags);
1954 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001955 if (mA > USB_WALL_THRESHOLD_MA)
1956 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1957 else
1958 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959 } else {
1960 /*
1961 * called before pmic initialized,
1962 * save this value and use it at probe
1963 */
David Keitelacf57c82012-03-07 18:48:50 -08001964 if (mA > USB_WALL_THRESHOLD_MA)
1965 usb_chg_current = USB_WALL_THRESHOLD_MA;
1966 else
1967 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001968 }
1969 spin_unlock_irqrestore(&vbus_lock, flags);
1970}
1971EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1972
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001973int pm8921_is_usb_chg_plugged_in(void)
1974{
1975 if (!the_chip) {
1976 pr_err("called before init\n");
1977 return -EINVAL;
1978 }
1979 return is_usb_chg_plugged_in(the_chip);
1980}
1981EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1982
1983int pm8921_is_dc_chg_plugged_in(void)
1984{
1985 if (!the_chip) {
1986 pr_err("called before init\n");
1987 return -EINVAL;
1988 }
1989 return is_dc_chg_plugged_in(the_chip);
1990}
1991EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1992
1993int pm8921_is_battery_present(void)
1994{
1995 if (!the_chip) {
1996 pr_err("called before init\n");
1997 return -EINVAL;
1998 }
1999 return get_prop_batt_present(the_chip);
2000}
2001EXPORT_SYMBOL(pm8921_is_battery_present);
2002
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002003int pm8921_is_batfet_closed(void)
2004{
2005 if (!the_chip) {
2006 pr_err("called before init\n");
2007 return -EINVAL;
2008 }
2009 return is_batfet_closed(the_chip);
2010}
2011EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002012/*
2013 * Disabling the charge current limit causes current
2014 * current limits to have no monitoring. An adequate charger
2015 * capable of supplying high current while sustaining VIN_MIN
2016 * is required if the limiting is disabled.
2017 */
2018int pm8921_disable_input_current_limit(bool disable)
2019{
2020 if (!the_chip) {
2021 pr_err("called before init\n");
2022 return -EINVAL;
2023 }
2024 if (disable) {
2025 pr_warn("Disabling input current limit!\n");
2026
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002027 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002028 }
2029 return 0;
2030}
2031EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2032
David Keitel0789fc62012-06-07 17:43:27 -07002033int pm8917_set_under_voltage_detection_threshold(int mv)
2034{
2035 if (!the_chip) {
2036 pr_err("called before init\n");
2037 return -EINVAL;
2038 }
2039 return pm_chg_uvd_threshold_set(the_chip, mv);
2040}
2041EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2042
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002043int pm8921_set_max_battery_charge_current(int ma)
2044{
2045 if (!the_chip) {
2046 pr_err("called before init\n");
2047 return -EINVAL;
2048 }
2049 return pm_chg_ibatmax_set(the_chip, ma);
2050}
2051EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2052
2053int pm8921_disable_source_current(bool disable)
2054{
2055 if (!the_chip) {
2056 pr_err("called before init\n");
2057 return -EINVAL;
2058 }
2059 if (disable)
2060 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002061
2062 pm_chg_usb_suspend_enable(the_chip, disable);
2063
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002064 return pm_chg_charge_dis(the_chip, disable);
2065}
2066EXPORT_SYMBOL(pm8921_disable_source_current);
2067
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002068int pm8921_regulate_input_voltage(int voltage)
2069{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002070 int rc;
2071
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002072 if (!the_chip) {
2073 pr_err("called before init\n");
2074 return -EINVAL;
2075 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002076 rc = pm_chg_vinmin_set(the_chip, voltage);
2077
2078 if (rc == 0)
2079 the_chip->vin_min = voltage;
2080
2081 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002082}
2083
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002084#define USB_OV_THRESHOLD_MASK 0x60
2085#define USB_OV_THRESHOLD_SHIFT 5
2086int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2087{
2088 u8 temp;
2089
2090 if (!the_chip) {
2091 pr_err("called before init\n");
2092 return -EINVAL;
2093 }
2094
2095 if (ov > PM_USB_OV_7V) {
2096 pr_err("limiting to over voltage threshold to 7volts\n");
2097 ov = PM_USB_OV_7V;
2098 }
2099
2100 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2101
2102 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2103 USB_OV_THRESHOLD_MASK, temp);
2104}
2105EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2106
2107#define USB_DEBOUNCE_TIME_MASK 0x06
2108#define USB_DEBOUNCE_TIME_SHIFT 1
2109int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2110{
2111 u8 temp;
2112
2113 if (!the_chip) {
2114 pr_err("called before init\n");
2115 return -EINVAL;
2116 }
2117
2118 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2119 pr_err("limiting debounce to 80.5ms\n");
2120 ms = PM_USB_DEBOUNCE_80P5MS;
2121 }
2122
2123 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2124
2125 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2126 USB_DEBOUNCE_TIME_MASK, temp);
2127}
2128EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2129
2130#define USB_OVP_DISABLE_MASK 0x80
2131int pm8921_usb_ovp_disable(int disable)
2132{
2133 u8 temp = 0;
2134
2135 if (!the_chip) {
2136 pr_err("called before init\n");
2137 return -EINVAL;
2138 }
2139
2140 if (disable)
2141 temp = USB_OVP_DISABLE_MASK;
2142
2143 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2144 USB_OVP_DISABLE_MASK, temp);
2145}
2146
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002147bool pm8921_is_battery_charging(int *source)
2148{
2149 int fsm_state, is_charging, dc_present, usb_present;
2150
2151 if (!the_chip) {
2152 pr_err("called before init\n");
2153 return -EINVAL;
2154 }
2155 fsm_state = pm_chg_get_fsm_state(the_chip);
2156 is_charging = is_battery_charging(fsm_state);
2157 if (is_charging == 0) {
2158 *source = PM8921_CHG_SRC_NONE;
2159 return is_charging;
2160 }
2161
2162 if (source == NULL)
2163 return is_charging;
2164
2165 /* the battery is charging, the source is requested, find it */
2166 dc_present = is_dc_chg_plugged_in(the_chip);
2167 usb_present = is_usb_chg_plugged_in(the_chip);
2168
2169 if (dc_present && !usb_present)
2170 *source = PM8921_CHG_SRC_DC;
2171
2172 if (usb_present && !dc_present)
2173 *source = PM8921_CHG_SRC_USB;
2174
2175 if (usb_present && dc_present)
2176 /*
2177 * The system always chooses dc for charging since it has
2178 * higher priority.
2179 */
2180 *source = PM8921_CHG_SRC_DC;
2181
2182 return is_charging;
2183}
2184EXPORT_SYMBOL(pm8921_is_battery_charging);
2185
David Keitel86034022012-04-18 12:33:58 -07002186int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2187{
2188 if (!the_chip) {
2189 pr_err("called before init\n");
2190 return -EINVAL;
2191 }
2192
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002193 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002194 return -EINVAL;
2195
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002196 the_chip->usb_psy.type = type;
David Keitel86034022012-04-18 12:33:58 -07002197 power_supply_changed(&the_chip->usb_psy);
2198 power_supply_changed(&the_chip->dc_psy);
2199 return 0;
2200}
2201EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2202
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002203int pm8921_batt_temperature(void)
2204{
2205 if (!the_chip) {
2206 pr_err("called before init\n");
2207 return -EINVAL;
2208 }
2209 return get_prop_batt_temp(the_chip);
2210}
2211
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002212static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002213{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002214 int err;
2215 u8 temp;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002216
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002217
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002218 temp = 0xD1;
2219 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2220 if (err) {
2221 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002222 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002223 }
2224
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002225 temp = 0xD3;
2226 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2227 if (err) {
2228 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002229 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002230 }
2231
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002232 temp = 0xD1;
2233 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2234 if (err) {
2235 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002236 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002237 }
2238
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002239 temp = 0xD5;
2240 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2241 if (err) {
2242 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002243 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002244 }
2245
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002246 /* Wait a few clock cycles before re-enabling hw clock switching */
2247 udelay(183);
2248
2249 temp = 0xD1;
2250 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2251 if (err) {
2252 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002253 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002254 }
2255
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002256 temp = 0xD0;
2257 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2258 if (err) {
2259 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002260 return err;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002261 }
2262
2263 /* Wait for few clock cycles before re-enabling LPM */
2264 udelay(32);
2265
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002266 return 0;
2267}
2268
2269static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
2270{
2271 int err;
2272 unsigned long flags = 0;
2273
2274 spin_lock_irqsave(&lpm_lock, flags);
2275 err = pm8921_chg_set_lpm(chip, 0);
2276 if (err) {
2277 pr_err("Error settig LPM rc=%d\n", err);
2278 goto kick_err;
2279 }
2280
2281 __pm8921_apply_19p2mhz_kickstart(chip);
2282
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002283kick_err:
2284 err = pm8921_chg_set_lpm(chip, 1);
2285 if (err)
2286 pr_err("Error settig LPM rc=%d\n", err);
2287
2288 spin_unlock_irqrestore(&lpm_lock, flags);
2289
2290 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002291}
2292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2294{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002295 int usb_present, rc = 0;
2296
2297 if (chip->lockup_lpm_wrkarnd) {
2298 rc = pm8921_apply_19p2mhz_kickstart(chip);
2299 if (rc)
2300 pr_err("Failed to apply kickstart rc=%d\n", rc);
2301 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002303 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304 usb_present = is_usb_chg_plugged_in(chip);
2305 if (chip->usb_present ^ usb_present) {
2306 notify_usb_of_the_plugin_event(usb_present);
2307 chip->usb_present = usb_present;
2308 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002309 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002310 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002311
2312 /* Enable/disable bypass if charger is on battery */
2313 if (chip->lockup_lpm_wrkarnd)
2314 pm8921_chg_bypass_bat_gone_debounce(chip,
2315 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002316 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002317 if (usb_present) {
2318 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002319 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002320 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2321 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002322 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002323 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002324 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002325 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002326 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327}
2328
Amir Samuelovd31ef502011-10-26 14:41:36 +02002329static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2330{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002331 if (chip->lockup_lpm_wrkarnd)
2332 /* Enable bypass if charger is on battery */
2333 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2334
David Keitel88e1b572012-01-11 11:57:14 -08002335 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002336 pr_debug("external charger not registered.\n");
2337 return;
2338 }
2339
2340 if (!chip->ext_charging) {
2341 pr_debug("already not charging.\n");
2342 return;
2343 }
2344
David Keitel88e1b572012-01-11 11:57:14 -08002345 power_supply_set_charge_type(chip->ext_psy,
2346 POWER_SUPPLY_CHARGE_TYPE_NONE);
2347 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002348 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002349 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002350 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002351 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002352 /* Update battery charging LEDs and user space battery info */
2353 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002354}
2355
2356static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2357{
2358 int dc_present;
2359 int batt_present;
2360 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002361 unsigned long delay =
2362 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2363
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002364 /* Disable bypass if charger connected and not running on bat */
2365 if (chip->lockup_lpm_wrkarnd)
2366 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2367
David Keitel88e1b572012-01-11 11:57:14 -08002368 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002369 pr_debug("external charger not registered.\n");
2370 return;
2371 }
2372
2373 if (chip->ext_charging) {
2374 pr_debug("already charging.\n");
2375 return;
2376 }
2377
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002378 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002379 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2380 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002381
2382 if (!dc_present) {
2383 pr_warn("%s. dc not present.\n", __func__);
2384 return;
2385 }
2386 if (!batt_present) {
2387 pr_warn("%s. battery not present.\n", __func__);
2388 return;
2389 }
2390 if (!batt_temp_ok) {
2391 pr_warn("%s. battery temperature not ok.\n", __func__);
2392 return;
2393 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002394
2395 /* Force BATFET=ON */
2396 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002397
David Keitel6ccbf132012-05-30 14:21:24 -07002398 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002399 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002400
David Keitel63f71662012-02-08 20:30:00 -08002401 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002402 power_supply_set_charge_type(chip->ext_psy,
2403 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002404 chip->ext_charging = true;
2405 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002406 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002407 /*
2408 * since we wont get a fastchg irq from external charger
2409 * use eoc worker to detect end of charging
2410 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002411 schedule_delayed_work(&chip->eoc_work, delay);
2412 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002413 if (chip->btc_override)
2414 schedule_delayed_work(&chip->btc_override_work,
2415 round_jiffies_relative(msecs_to_jiffies
2416 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002417 /* Update battery charging LEDs and user space battery info */
2418 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002419}
2420
David Keitel6ccbf132012-05-30 14:21:24 -07002421static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002422{
2423 u8 temp;
2424 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002425
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002426 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002427 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002428 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002429 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002430 }
David Keitel6ccbf132012-05-30 14:21:24 -07002431 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002432 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002433 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002434 return;
2435 }
2436 /* set ovp fet disable bit and the write bit */
2437 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002438 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002439 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002440 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002441 return;
2442 }
2443}
2444
David Keitel6ccbf132012-05-30 14:21:24 -07002445static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002446{
2447 u8 temp;
2448 int rc;
2449
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002450 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002451 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002452 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002453 return;
2454 }
David Keitel6ccbf132012-05-30 14:21:24 -07002455 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002456 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002457 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002458 return;
2459 }
2460 /* unset ovp fet disable bit and set the write bit */
2461 temp &= 0xFE;
2462 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002463 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002464 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002465 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002466 temp, rc);
2467 return;
2468 }
2469}
2470
2471static int param_open_ovp_counter = 10;
2472module_param(param_open_ovp_counter, int, 0644);
2473
David Keitel6ccbf132012-05-30 14:21:24 -07002474#define USB_ACTIVE_BIT BIT(5)
2475#define DC_ACTIVE_BIT BIT(6)
2476static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2477 u8 active_chg_mask)
2478{
2479 if (active_chg_mask & USB_ACTIVE_BIT)
2480 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2481 else if (active_chg_mask & DC_ACTIVE_BIT)
2482 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2483 else
2484 return 0;
2485}
2486
David Keitel8c5201a2012-02-24 16:08:54 -08002487#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002488#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002489static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002490{
David Keitel6ccbf132012-05-30 14:21:24 -07002491 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002492 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002493 u8 active_mask = 0;
2494 u16 ovpreg, ovptestreg;
2495
2496 if (is_usb_chg_plugged_in(chip) &&
2497 (chip->active_path & USB_ACTIVE_BIT)) {
2498 ovpreg = USB_OVP_CONTROL;
2499 ovptestreg = USB_OVP_TEST;
2500 active_mask = USB_ACTIVE_BIT;
2501 } else if (is_dc_chg_plugged_in(chip) &&
2502 (chip->active_path & DC_ACTIVE_BIT)) {
2503 ovpreg = DC_OVP_CONTROL;
2504 ovptestreg = DC_OVP_TEST;
2505 active_mask = DC_ACTIVE_BIT;
2506 } else {
2507 return;
2508 }
David Keitel8c5201a2012-02-24 16:08:54 -08002509
2510 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002511 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002512 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002513 active_chg_plugged_in
2514 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002515 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002516 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2517 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002518
2519 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002520 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002521 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002522 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002523
2524 msleep(20);
2525
David Keitel6ccbf132012-05-30 14:21:24 -07002526 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002527 } else {
David Keitel712782e2012-03-29 14:11:47 -07002528 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002529 }
2530 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002531 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2532 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2533 else
2534 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2535
David Keitel6ccbf132012-05-30 14:21:24 -07002536 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2537 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002538 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002539}
David Keitelacf57c82012-03-07 18:48:50 -08002540
2541static int find_usb_ma_value(int value)
2542{
2543 int i;
2544
2545 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2546 if (value >= usb_ma_table[i].usb_ma)
2547 break;
2548 }
2549
2550 return i;
2551}
2552
2553static void decrease_usb_ma_value(int *value)
2554{
2555 int i;
2556
2557 if (value) {
2558 i = find_usb_ma_value(*value);
2559 if (i > 0)
2560 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002561 while (!the_chip->iusb_fine_res && i > 0
2562 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2563 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002564
2565 if (i < 0) {
2566 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2567 *value);
2568 i = 0;
2569 }
2570
David Keitelacf57c82012-03-07 18:48:50 -08002571 *value = usb_ma_table[i].usb_ma;
2572 }
2573}
2574
2575static void increase_usb_ma_value(int *value)
2576{
2577 int i;
2578
2579 if (value) {
2580 i = find_usb_ma_value(*value);
2581
2582 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2583 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002584 /* Get next correct entry if IUSB_FINE_RES is not available */
2585 while (!the_chip->iusb_fine_res
2586 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2587 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2588 i++;
2589
David Keitelacf57c82012-03-07 18:48:50 -08002590 *value = usb_ma_table[i].usb_ma;
2591 }
2592}
2593
2594static void vin_collapse_check_worker(struct work_struct *work)
2595{
2596 struct delayed_work *dwork = to_delayed_work(work);
2597 struct pm8921_chg_chip *chip = container_of(dwork,
2598 struct pm8921_chg_chip, vin_collapse_check_work);
2599
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002600 /*
2601 * AICL only for wall-chargers. If the charger appears to be plugged
2602 * back in now, the corresponding unplug must have been because of we
2603 * were trying to draw more current than the charger can support. In
2604 * such a case reset usb current to 500mA and decrease the target.
2605 * The AICL algorithm will step up the current from 500mA to target
2606 */
2607 if (is_usb_chg_plugged_in(chip)
2608 && usb_target_ma > USB_WALL_THRESHOLD_MA) {
David Keitelacf57c82012-03-07 18:48:50 -08002609 /* decrease usb_target_ma */
2610 decrease_usb_ma_value(&usb_target_ma);
2611 /* reset here, increase in unplug_check_worker */
2612 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2613 pr_debug("usb_now=%d, usb_target = %d\n",
2614 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002615 if (!delayed_work_pending(&chip->unplug_check_work))
2616 schedule_delayed_work(&chip->unplug_check_work,
2617 msecs_to_jiffies
2618 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002619 } else {
2620 handle_usb_insertion_removal(chip);
2621 }
2622}
2623
2624#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2626{
David Keitelacf57c82012-03-07 18:48:50 -08002627 if (usb_target_ma)
2628 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2629 round_jiffies_relative(msecs_to_jiffies
2630 (VIN_MIN_COLLAPSE_CHECK_MS)));
2631 else
2632 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633 return IRQ_HANDLED;
2634}
2635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2637{
2638 struct pm8921_chg_chip *chip = data;
2639 int status;
2640
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002641 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2642 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002643 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 pr_debug("battery present=%d", status);
2645 power_supply_changed(&chip->batt_psy);
2646 return IRQ_HANDLED;
2647}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002648
2649/*
2650 * this interrupt used to restart charging a battery.
2651 *
2652 * Note: When DC-inserted the VBAT can't go low.
2653 * VPH_PWR is provided by the ext-charger.
2654 * After End-Of-Charging from DC, charging can be resumed only
2655 * if DC is removed and then inserted after the battery was in use.
2656 * Therefore the handle_start_ext_chg() is not called.
2657 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2659{
2660 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002661 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002663 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002664
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002665 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002666 /* enable auto charging */
2667 pm_chg_auto_enable(chip, !charging_disabled);
2668 pr_info("batt fell below resume voltage %s\n",
2669 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002670 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002671 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002673 power_supply_changed(&chip->batt_psy);
2674 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002675 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677 return IRQ_HANDLED;
2678}
2679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2681{
2682 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2683 return IRQ_HANDLED;
2684}
2685
2686static irqreturn_t vcp_irq_handler(int irq, void *data)
2687{
David Keitel8c5201a2012-02-24 16:08:54 -08002688 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689 return IRQ_HANDLED;
2690}
2691
2692static irqreturn_t atcdone_irq_handler(int irq, void *data)
2693{
2694 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2695 return IRQ_HANDLED;
2696}
2697
2698static irqreturn_t atcfail_irq_handler(int irq, void *data)
2699{
2700 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2701 return IRQ_HANDLED;
2702}
2703
2704static irqreturn_t chgdone_irq_handler(int irq, void *data)
2705{
2706 struct pm8921_chg_chip *chip = data;
2707
2708 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002709
2710 handle_stop_ext_chg(chip);
2711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 power_supply_changed(&chip->batt_psy);
2713 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002714 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002715
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002716 bms_notify_check(chip);
2717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718 return IRQ_HANDLED;
2719}
2720
2721static irqreturn_t chgfail_irq_handler(int irq, void *data)
2722{
2723 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002724 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002725
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002726 if (!chip->stop_chg_upon_expiry) {
2727 ret = pm_chg_failed_clear(chip, 1);
2728 if (ret)
2729 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2730 }
David Keitel753ec8d2011-11-02 10:56:37 -07002731
2732 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2733 get_prop_batt_present(chip),
2734 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2735 pm_chg_get_fsm_state(data));
2736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 power_supply_changed(&chip->batt_psy);
2738 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002739 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002740 return IRQ_HANDLED;
2741}
2742
2743static irqreturn_t chgstate_irq_handler(int irq, void *data)
2744{
2745 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002746
2747 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2748 power_supply_changed(&chip->batt_psy);
2749 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002750 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002752 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002754 return IRQ_HANDLED;
2755}
2756
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002757enum {
2758 PON_TIME_25NS = 0x04,
2759 PON_TIME_50NS = 0x08,
2760 PON_TIME_100NS = 0x0C,
2761};
David Keitel8c5201a2012-02-24 16:08:54 -08002762
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002763static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002764{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002765 u8 temp;
2766 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002767
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002768 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2769 if (rc) {
2770 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2771 return;
2772 }
2773 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2774 if (rc) {
2775 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2776 return;
2777 }
2778 /* clear the min pon time select bit */
2779 temp &= 0xF3;
2780 /* set the pon time */
2781 temp |= (u8)pon_time_ns;
2782 /* write enable bank 4 */
2783 temp |= 0x80;
2784 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2785 if (rc) {
2786 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2787 return;
2788 }
2789}
David Keitel8c5201a2012-02-24 16:08:54 -08002790
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002791static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2792{
2793 pr_debug("Start\n");
2794 set_min_pon_time(chip, PON_TIME_100NS);
2795 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2796 msleep(250);
2797 pm_chg_vinmin_set(chip, chip->vin_min);
2798 set_min_pon_time(chip, PON_TIME_25NS);
2799 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002800}
2801
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002802#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002803#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2804#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002805static void unplug_check_worker(struct work_struct *work)
2806{
2807 struct delayed_work *dwork = to_delayed_work(work);
2808 struct pm8921_chg_chip *chip = container_of(dwork,
2809 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002810 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002811 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002812 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002813 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002814
2815 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2816 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002817 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2818 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002819 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002820
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002821 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002822 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002823 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2824 active_path, active_chg_plugged_in);
2825 if (active_path & USB_ACTIVE_BIT) {
2826 pr_debug("USB charger active\n");
2827
2828 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002829
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002830 if (usb_ma <= 100) {
2831 pr_debug(
2832 "Unenumerated or suspended usb_ma = %d skip\n",
2833 usb_ma);
2834 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002835 }
2836 } else if (active_path & DC_ACTIVE_BIT) {
2837 pr_debug("DC charger active\n");
2838 } else {
2839 /* No charger active */
2840 if (!(is_usb_chg_plugged_in(chip)
2841 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002842 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002843 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2844 pm_chg_get_regulation_loop(chip),
2845 pm_chg_get_fsm_state(chip),
2846 get_prop_batt_current(chip)
2847 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002848 if (chip->lockup_lpm_wrkarnd) {
2849 rc = pm8921_apply_19p2mhz_kickstart(chip);
2850 if (rc)
2851 pr_err("Failed kickstart rc=%d\n", rc);
2852
2853 /*
2854 * Make sure kickstart happens at least 200 ms
2855 * after charger has been removed.
2856 */
2857 if (chip->final_kickstart) {
2858 chip->final_kickstart = false;
2859 goto check_again_later;
2860 }
2861 }
2862 return;
2863 } else {
2864 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002865 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002866 }
David Keitel8c5201a2012-02-24 16:08:54 -08002867
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002868 chip->final_kickstart = true;
2869
2870 /* AICL only for usb wall charger */
2871 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
David Keitel6ccbf132012-05-30 14:21:24 -07002872 reg_loop = pm_chg_get_regulation_loop(chip);
2873 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2874 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002875 (usb_ma > USB_WALL_THRESHOLD_MA)
2876 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002877 decrease_usb_ma_value(&usb_ma);
2878 usb_target_ma = usb_ma;
2879 /* end AICL here */
2880 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002881 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002882 usb_ma, usb_target_ma);
2883 }
David Keitelacf57c82012-03-07 18:48:50 -08002884 }
2885
2886 reg_loop = pm_chg_get_regulation_loop(chip);
2887 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2888
David Keitel6ccbf132012-05-30 14:21:24 -07002889 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002890 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002891 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002892 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2893 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2894 attempt_reverse_boost_fix(chip);
2895 /* after reverse boost fix check if the active
2896 * charger was detected as removed */
2897 active_chg_plugged_in
2898 = is_active_chg_plugged_in(chip,
2899 active_path);
2900 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2901 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002902 }
2903 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002904
2905 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002906 pr_debug("active_path = 0x%x, active_chg = %d\n",
2907 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002908 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2909
David Keitel6ccbf132012-05-30 14:21:24 -07002910 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2911 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2912 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002913 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002914 }
2915
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002916 /* AICL only for usb wall charger */
2917 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2918 && usb_target_ma > 0
2919 && !charging_disabled) {
David Keitelacf57c82012-03-07 18:48:50 -08002920 /* only increase iusb_max if vin loop not active */
2921 if (usb_ma < usb_target_ma) {
2922 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302923 if (usb_ma > usb_target_ma)
2924 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002925 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002926 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002927 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002928 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002929 } else {
2930 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002931 }
2932 }
Devin Kim2073afb2012-09-05 13:01:51 -07002933check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002934 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002935 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002936 if (ramp)
2937 schedule_delayed_work(&chip->unplug_check_work,
2938 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2939 else
2940 schedule_delayed_work(&chip->unplug_check_work,
2941 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002942}
2943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002944static irqreturn_t loop_change_irq_handler(int irq, void *data)
2945{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002946 struct pm8921_chg_chip *chip = data;
2947
2948 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2949 pm_chg_get_fsm_state(data),
2950 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002951 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002952 return IRQ_HANDLED;
2953}
2954
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002955struct ibatmax_max_adj_entry {
2956 int ibat_max_ma;
2957 int max_adj_ma;
2958};
2959
2960static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2961 {975, 300},
2962 {1475, 150},
2963 {1975, 200},
2964 {2475, 250},
2965};
2966
2967static int find_ibat_max_adj_ma(int ibat_target_ma)
2968{
2969 int i = 0;
2970
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002971 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2972 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002973 break;
2974 }
2975
2976 return ibatmax_adj_table[i].max_adj_ma;
2977}
2978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979static irqreturn_t fastchg_irq_handler(int irq, void *data)
2980{
2981 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002982 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002984 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2985 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2986 wake_lock(&chip->eoc_wake_lock);
2987 schedule_delayed_work(&chip->eoc_work,
2988 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002989 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002990 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002991 if (high_transition
2992 && chip->btc_override
2993 && !delayed_work_pending(&chip->btc_override_work)) {
2994 schedule_delayed_work(&chip->btc_override_work,
2995 round_jiffies_relative(msecs_to_jiffies
2996 (chip->btc_delay_ms)));
2997 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002998 power_supply_changed(&chip->batt_psy);
2999 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 return IRQ_HANDLED;
3001}
3002
3003static irqreturn_t trklchg_irq_handler(int irq, void *data)
3004{
3005 struct pm8921_chg_chip *chip = data;
3006
3007 power_supply_changed(&chip->batt_psy);
3008 return IRQ_HANDLED;
3009}
3010
3011static irqreturn_t batt_removed_irq_handler(int irq, void *data)
3012{
3013 struct pm8921_chg_chip *chip = data;
3014 int status;
3015
3016 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3017 pr_debug("battery present=%d state=%d", !status,
3018 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003019 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003020 power_supply_changed(&chip->batt_psy);
3021 return IRQ_HANDLED;
3022}
3023
3024static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3025{
3026 struct pm8921_chg_chip *chip = data;
3027
Amir Samuelovd31ef502011-10-26 14:41:36 +02003028 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029 power_supply_changed(&chip->batt_psy);
3030 return IRQ_HANDLED;
3031}
3032
3033static irqreturn_t chghot_irq_handler(int irq, void *data)
3034{
3035 struct pm8921_chg_chip *chip = data;
3036
3037 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3038 power_supply_changed(&chip->batt_psy);
3039 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003040 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041 return IRQ_HANDLED;
3042}
3043
3044static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3045{
3046 struct pm8921_chg_chip *chip = data;
3047
3048 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003049 handle_stop_ext_chg(chip);
3050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 power_supply_changed(&chip->batt_psy);
3052 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return IRQ_HANDLED;
3054}
3055
3056static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3057{
3058 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003059 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003060
3061 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3062 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3063
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003064 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3065 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003066
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067 power_supply_changed(&chip->batt_psy);
3068 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 return IRQ_HANDLED;
3070}
David Keitel52fda532011-11-10 10:43:44 -08003071/*
3072 *
3073 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3074 * fire for two cases:
3075 *
3076 * If the interrupt line switches to high temperature is okay
3077 * and thus charging begins.
3078 * If bat_temp_ok is low this means the temperature is now
3079 * too hot or cold, so charging is stopped.
3080 *
3081 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3083{
David Keitel52fda532011-11-10 10:43:44 -08003084 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 struct pm8921_chg_chip *chip = data;
3086
David Keitel52fda532011-11-10 10:43:44 -08003087 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3088
3089 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3090 bat_temp_ok, pm_chg_get_fsm_state(data));
3091
3092 if (bat_temp_ok)
3093 handle_start_ext_chg(chip);
3094 else
3095 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003096
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 power_supply_changed(&chip->batt_psy);
3098 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003099 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100 return IRQ_HANDLED;
3101}
3102
3103static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3104{
3105 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3106 return IRQ_HANDLED;
3107}
3108
3109static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3110{
3111 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3112 return IRQ_HANDLED;
3113}
3114
3115static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3116{
3117 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3118 return IRQ_HANDLED;
3119}
3120
3121static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3122{
3123 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3124 return IRQ_HANDLED;
3125}
3126
3127static irqreturn_t batfet_irq_handler(int irq, void *data)
3128{
3129 struct pm8921_chg_chip *chip = data;
3130
3131 pr_debug("vreg ov\n");
3132 power_supply_changed(&chip->batt_psy);
3133 return IRQ_HANDLED;
3134}
3135
3136static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3137{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003138 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003139 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003140
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003141 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003142 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003143
3144 if (chip->dc_present ^ dc_present)
3145 pm8921_bms_calibrate_hkadc();
3146
David Keitel88e1b572012-01-11 11:57:14 -08003147 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003148 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003149 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003150 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3151
3152 chip->dc_present = dc_present;
3153
3154 if (chip->ext_psy) {
3155 if (dc_present)
3156 handle_start_ext_chg(chip);
3157 else
3158 handle_stop_ext_chg(chip);
3159 } else {
3160 if (chip->lockup_lpm_wrkarnd)
3161 /* if no external supply call bypass debounce here */
3162 pm8921_chg_bypass_bat_gone_debounce(chip,
3163 is_chg_on_bat(chip));
3164
3165 if (dc_present)
3166 schedule_delayed_work(&chip->unplug_check_work,
3167 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3168 power_supply_changed(&chip->dc_psy);
3169 }
3170
3171 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172 return IRQ_HANDLED;
3173}
3174
3175static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3176{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003177 struct pm8921_chg_chip *chip = data;
3178
Amir Samuelovd31ef502011-10-26 14:41:36 +02003179 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 return IRQ_HANDLED;
3181}
3182
3183static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3184{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003185 struct pm8921_chg_chip *chip = data;
3186
Amir Samuelovd31ef502011-10-26 14:41:36 +02003187 handle_stop_ext_chg(chip);
3188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189 return IRQ_HANDLED;
3190}
3191
David Keitel88e1b572012-01-11 11:57:14 -08003192static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3193{
3194 struct power_supply *psy = &the_chip->batt_psy;
3195 struct power_supply *epsy = dev_get_drvdata(dev);
3196 int i, dcin_irq;
3197
3198 /* Only search for external supply if none is registered */
3199 if (!the_chip->ext_psy) {
3200 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3201 for (i = 0; i < epsy->num_supplicants; i++) {
3202 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3203 if (!strncmp(epsy->name, "dc", 2)) {
3204 the_chip->ext_psy = epsy;
3205 dcin_valid_irq_handler(dcin_irq,
3206 the_chip);
3207 }
3208 }
3209 }
3210 }
3211 return 0;
3212}
3213
3214static void pm_batt_external_power_changed(struct power_supply *psy)
3215{
3216 /* Only look for an external supply if it hasn't been registered */
3217 if (!the_chip->ext_psy)
3218 class_for_each_device(power_supply_class, NULL, psy,
3219 __pm_batt_external_power_changed_work);
3220}
3221
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003222/**
3223 * update_heartbeat - internal function to update userspace
3224 * per update_time minutes
3225 *
3226 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003227#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003228static void update_heartbeat(struct work_struct *work)
3229{
3230 struct delayed_work *dwork = to_delayed_work(work);
3231 struct pm8921_chg_chip *chip = container_of(dwork,
3232 struct pm8921_chg_chip, update_heartbeat_work);
3233
3234 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003235 if (chip->recent_reported_soc <= 20)
3236 schedule_delayed_work(&chip->update_heartbeat_work,
3237 round_jiffies_relative(msecs_to_jiffies
3238 (LOW_SOC_HEARTBEAT_MS)));
3239 else
3240 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003241 round_jiffies_relative(msecs_to_jiffies
3242 (chip->update_time)));
3243}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003244#define VDD_LOOP_ACTIVE_BIT BIT(3)
3245#define VDD_MAX_INCREASE_MV 400
3246static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3247module_param(vdd_max_increase_mv, int, 0644);
3248
3249static int ichg_threshold_ua = -400000;
3250module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003251
3252#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003253static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3254 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003255{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003256 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003257 int vbat_batt_terminal_mv;
3258 int reg_loop;
3259 int delta_mv = 0;
3260
3261 if (chip->rconn_mohm == 0) {
3262 pr_debug("Exiting as rconn_mohm is 0\n");
3263 return;
3264 }
3265 /* adjust vdd_max only in normal temperature zone */
3266 if (chip->is_bat_cool || chip->is_bat_warm) {
3267 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3268 chip->is_bat_cool, chip->is_bat_warm);
3269 return;
3270 }
3271
3272 reg_loop = pm_chg_get_regulation_loop(chip);
3273 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3274 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3275 reg_loop);
3276 return;
3277 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003278 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3279 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3280
3281 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3282
3283 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3284 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3285 delta_mv,
3286 programmed_vdd_max,
3287 adj_vdd_max_mv);
3288
3289 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3290 pr_debug("adj vdd_max lower than default max voltage\n");
3291 return;
3292 }
3293
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003294 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3295 * PM8921_CHG_VDDMAX_RES_MV;
3296
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003297 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3298 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003299 pr_debug("adjusting vdd_max_mv to %d to make "
3300 "vbat_batt_termial_uv = %d to %d\n",
3301 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3302 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3303}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003304
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003305static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3306{
3307 if (chip->is_bat_cool)
3308 pm_chg_vbatdet_set(the_chip,
3309 the_chip->cool_bat_voltage
3310 - the_chip->resume_voltage_delta);
3311 else if (chip->is_bat_warm)
3312 pm_chg_vbatdet_set(the_chip,
3313 the_chip->warm_bat_voltage
3314 - the_chip->resume_voltage_delta);
3315 else
3316 pm_chg_vbatdet_set(the_chip,
3317 the_chip->max_voltage_mv
3318 - the_chip->resume_voltage_delta);
3319}
3320
3321static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3322{
3323 unsigned int chg_current = chip->max_bat_chg_current;
3324
3325 if (chip->is_bat_cool)
3326 chg_current = min(chg_current, chip->cool_bat_chg_current);
3327
3328 if (chip->is_bat_warm)
3329 chg_current = min(chg_current, chip->warm_bat_chg_current);
3330
3331 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3332 chg_current = min(chg_current,
3333 chip->thermal_mitigation[thermal_mitigation]);
3334
3335 pm_chg_ibatmax_set(the_chip, chg_current);
3336}
3337
3338#define TEMP_HYSTERISIS_DECIDEGC 20
3339static void battery_cool(bool enter)
3340{
3341 pr_debug("enter = %d\n", enter);
3342 if (enter == the_chip->is_bat_cool)
3343 return;
3344 the_chip->is_bat_cool = enter;
3345 if (enter)
3346 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3347 else
3348 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3349 set_appropriate_battery_current(the_chip);
3350 set_appropriate_vbatdet(the_chip);
3351}
3352
3353static void battery_warm(bool enter)
3354{
3355 pr_debug("enter = %d\n", enter);
3356 if (enter == the_chip->is_bat_warm)
3357 return;
3358 the_chip->is_bat_warm = enter;
3359 if (enter)
3360 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3361 else
3362 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3363
3364 set_appropriate_battery_current(the_chip);
3365 set_appropriate_vbatdet(the_chip);
3366}
3367
3368static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3369{
3370 int temp = 0;
3371
3372 temp = get_prop_batt_temp(chip);
3373 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3374 temp, chip->warm_temp_dc,
3375 chip->cool_temp_dc);
3376
3377 if (chip->warm_temp_dc != INT_MIN) {
3378 if (chip->is_bat_warm
3379 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3380 battery_warm(false);
3381 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3382 battery_warm(true);
3383 }
3384
3385 if (chip->cool_temp_dc != INT_MIN) {
3386 if (chip->is_bat_cool
3387 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3388 battery_cool(false);
3389 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3390 battery_cool(true);
3391 }
3392}
3393
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003394enum {
3395 CHG_IN_PROGRESS,
3396 CHG_NOT_IN_PROGRESS,
3397 CHG_FINISHED,
3398};
3399
3400#define VBAT_TOLERANCE_MV 70
3401#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003402static int is_charging_finished(struct pm8921_chg_chip *chip,
3403 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003404{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003405 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003406 int regulation_loop, fast_chg, vcp;
3407 int rc;
3408 static int last_vbat_programmed = -EINVAL;
3409
3410 if (!is_ext_charging(chip)) {
3411 /* return if the battery is not being fastcharged */
3412 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3413 pr_debug("fast_chg = %d\n", fast_chg);
3414 if (fast_chg == 0)
3415 return CHG_NOT_IN_PROGRESS;
3416
3417 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3418 pr_debug("vcp = %d\n", vcp);
3419 if (vcp == 1)
3420 return CHG_IN_PROGRESS;
3421
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003422 /* reset count if battery is hot/cold */
3423 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3424 pr_debug("batt_temp_ok = %d\n", rc);
3425 if (rc == 0)
3426 return CHG_IN_PROGRESS;
3427
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003428 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3429 if (rc) {
3430 pr_err("couldnt read vddmax rc = %d\n", rc);
3431 return CHG_IN_PROGRESS;
3432 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003433 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3434 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003435
3436 if (last_vbat_programmed == -EINVAL)
3437 last_vbat_programmed = vbat_programmed;
3438 if (last_vbat_programmed != vbat_programmed) {
3439 /* vddmax changed, reset and check again */
3440 pr_debug("vddmax = %d last_vdd_max=%d\n",
3441 vbat_programmed, last_vbat_programmed);
3442 last_vbat_programmed = vbat_programmed;
3443 return CHG_IN_PROGRESS;
3444 }
3445
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003446 if (chip->is_bat_cool)
3447 vbat_intended = chip->cool_bat_voltage;
3448 else if (chip->is_bat_warm)
3449 vbat_intended = chip->warm_bat_voltage;
3450 else
3451 vbat_intended = chip->max_voltage_mv;
3452
3453 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3454 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3455 vbat_batt_terminal_uv,
3456 vbat_intended);
3457 return CHG_IN_PROGRESS;
3458 }
3459
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003460 regulation_loop = pm_chg_get_regulation_loop(chip);
3461 if (regulation_loop < 0) {
3462 pr_err("couldnt read the regulation loop err=%d\n",
3463 regulation_loop);
3464 return CHG_IN_PROGRESS;
3465 }
3466 pr_debug("regulation_loop=%d\n", regulation_loop);
3467
3468 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3469 return CHG_IN_PROGRESS;
3470 } /* !is_ext_charging */
3471
3472 /* reset count if battery chg current is more than iterm */
3473 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3474 if (rc) {
3475 pr_err("couldnt read iterm rc = %d\n", rc);
3476 return CHG_IN_PROGRESS;
3477 }
3478
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003479 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3480 iterm_programmed, ichg_meas_ma);
3481 /*
3482 * ichg_meas_ma < 0 means battery is drawing current
3483 * ichg_meas_ma > 0 means battery is providing current
3484 */
3485 if (ichg_meas_ma > 0)
3486 return CHG_IN_PROGRESS;
3487
3488 if (ichg_meas_ma * -1 > iterm_programmed)
3489 return CHG_IN_PROGRESS;
3490
3491 return CHG_FINISHED;
3492}
3493
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003494#define COMP_OVERRIDE_HOT_BANK 6
3495#define COMP_OVERRIDE_COLD_BANK 7
3496#define COMP_OVERRIDE_BIT BIT(1)
3497static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3498{
3499 u8 val;
3500 int rc = 0;
3501
3502 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3503
3504 if (flag)
3505 val |= 0x01;
3506
3507 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3508 if (rc < 0)
3509 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3510
3511 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3512 return rc;
3513}
3514
3515static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3516{
3517 u8 val;
3518 int rc = 0;
3519
3520 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3521
3522 if (flag)
3523 val |= 0x01;
3524
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
3529 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3530 return rc;
3531}
3532
3533static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3534{
3535 int rc = 0;
3536 u8 reg;
3537 u8 val;
3538
3539 val = COMP_OVERRIDE_HOT_BANK << 2;
3540 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3541 if (rc < 0) {
3542 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3543 goto cold_init;
3544 }
3545 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3546 if (rc < 0) {
3547 pr_err("Could not read bank %d of override rc = %d\n",
3548 COMP_OVERRIDE_HOT_BANK, rc);
3549 goto cold_init;
3550 }
3551 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3552 /* for now override it as not hot */
3553 rc = pm_chg_override_hot(chip, 0);
3554 if (rc < 0)
3555 pr_err("Could not override hot rc = %d\n", rc);
3556 }
3557
3558cold_init:
3559 val = COMP_OVERRIDE_COLD_BANK << 2;
3560 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3561 if (rc < 0) {
3562 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3563 return;
3564 }
3565 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3566 if (rc < 0) {
3567 pr_err("Could not read bank %d of override rc = %d\n",
3568 COMP_OVERRIDE_COLD_BANK, rc);
3569 return;
3570 }
3571 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3572 /* for now override it as not cold */
3573 rc = pm_chg_override_cold(chip, 0);
3574 if (rc < 0)
3575 pr_err("Could not override cold rc = %d\n", rc);
3576 }
3577}
3578
3579static void btc_override_worker(struct work_struct *work)
3580{
3581 int decidegc;
3582 int temp;
3583 int rc = 0;
3584 struct delayed_work *dwork = to_delayed_work(work);
3585 struct pm8921_chg_chip *chip = container_of(dwork,
3586 struct pm8921_chg_chip, btc_override_work);
3587
3588 if (!chip->btc_override) {
3589 pr_err("called when not enabled\n");
3590 return;
3591 }
3592
3593 decidegc = get_prop_batt_temp(chip);
3594
3595 pr_debug("temp=%d\n", decidegc);
3596
3597 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3598 if (temp) {
3599 if (decidegc < chip->btc_override_hot_decidegc)
3600 /* stop forcing batt hot */
3601 rc = pm_chg_override_hot(chip, 0);
3602 if (rc)
3603 pr_err("Couldnt write 0 to hot comp\n");
3604 } else {
3605 if (decidegc >= chip->btc_override_hot_decidegc)
3606 /* start forcing batt hot */
3607 rc = pm_chg_override_hot(chip, 1);
3608 if (rc && chip->btc_panic_if_cant_stop_chg)
3609 panic("Couldnt override comps to stop chg\n");
3610 }
3611
3612 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3613 if (temp) {
3614 if (decidegc > chip->btc_override_cold_decidegc)
3615 /* stop forcing batt cold */
3616 rc = pm_chg_override_cold(chip, 0);
3617 if (rc)
3618 pr_err("Couldnt write 0 to cold comp\n");
3619 } else {
3620 if (decidegc <= chip->btc_override_cold_decidegc)
3621 /* start forcing batt cold */
3622 rc = pm_chg_override_cold(chip, 1);
3623 if (rc && chip->btc_panic_if_cant_stop_chg)
3624 panic("Couldnt override comps to stop chg\n");
3625 }
3626
3627 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3628 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3629 schedule_delayed_work(&chip->btc_override_work,
3630 round_jiffies_relative(msecs_to_jiffies
3631 (chip->btc_delay_ms)));
3632 return;
3633 }
3634
3635 rc = pm_chg_override_hot(chip, 0);
3636 if (rc)
3637 pr_err("Couldnt write 0 to hot comp\n");
3638 rc = pm_chg_override_cold(chip, 0);
3639 if (rc)
3640 pr_err("Couldnt write 0 to cold comp\n");
3641}
3642
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003643/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003644 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003645 * has happened
3646 *
3647 * If all conditions favouring, if the charge current is
3648 * less than the term current for three consecutive times
3649 * an EOC has happened.
3650 * The wakelock is released if there is no need to reshedule
3651 * - this happens when the battery is removed or EOC has
3652 * happened
3653 */
3654#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003655static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003656{
3657 struct delayed_work *dwork = to_delayed_work(work);
3658 struct pm8921_chg_chip *chip = container_of(dwork,
3659 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003660 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003661 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003662 int vbat_meas_uv, vbat_meas_mv;
3663 int ichg_meas_ua, ichg_meas_ma;
3664 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003665
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003666 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3667 &ichg_meas_ua, &vbat_meas_uv);
3668 vbat_meas_mv = vbat_meas_uv / 1000;
3669 /* rconn_mohm is in milliOhms */
3670 ichg_meas_ma = ichg_meas_ua / 1000;
3671 vbat_batt_terminal_uv = vbat_meas_uv
3672 + ichg_meas_ma
3673 * the_chip->rconn_mohm;
3674
3675 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003676
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003677 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003678 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003679 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003680 }
3681
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003682 if (end == CHG_FINISHED) {
3683 count++;
3684 } else {
3685 count = 0;
3686 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003687
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003688 if (count == CONSECUTIVE_COUNT) {
3689 count = 0;
3690 pr_info("End of Charging\n");
3691
3692 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003693
Amir Samuelovd31ef502011-10-26 14:41:36 +02003694 if (is_ext_charging(chip))
3695 chip->ext_charge_done = true;
3696
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003697 if (chip->is_bat_warm || chip->is_bat_cool)
3698 chip->bms_notify.is_battery_full = 0;
3699 else
3700 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003701 /* declare end of charging by invoking chgdone interrupt */
3702 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003703 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003704 check_temp_thresholds(chip);
3705 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003706 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003707 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003708 round_jiffies_relative(msecs_to_jiffies
3709 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003710 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003711 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003712
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003713eoc_worker_stop:
3714 wake_unlock(&chip->eoc_wake_lock);
3715 /* set the vbatdet back, in case it was changed to trigger charging */
3716 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003717}
3718
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003719/**
3720 * set_disable_status_param -
3721 *
3722 * Internal function to disable battery charging and also disable drawing
3723 * any current from the source. The device is forced to run on a battery
3724 * after this.
3725 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726static int set_disable_status_param(const char *val, struct kernel_param *kp)
3727{
3728 int ret;
3729 struct pm8921_chg_chip *chip = the_chip;
3730
3731 ret = param_set_int(val, kp);
3732 if (ret) {
3733 pr_err("error setting value %d\n", ret);
3734 return ret;
3735 }
3736 pr_info("factory set disable param to %d\n", charging_disabled);
3737 if (chip) {
3738 pm_chg_auto_enable(chip, !charging_disabled);
3739 pm_chg_charge_dis(chip, charging_disabled);
3740 }
3741 return 0;
3742}
3743module_param_call(disabled, set_disable_status_param, param_get_uint,
3744 &charging_disabled, 0644);
3745
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003746static int rconn_mohm;
3747static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3748{
3749 int ret;
3750 struct pm8921_chg_chip *chip = the_chip;
3751
3752 ret = param_set_int(val, kp);
3753 if (ret) {
3754 pr_err("error setting value %d\n", ret);
3755 return ret;
3756 }
3757 if (chip)
3758 chip->rconn_mohm = rconn_mohm;
3759 return 0;
3760}
3761module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3762 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003763/**
3764 * set_thermal_mitigation_level -
3765 *
3766 * Internal function to control battery charging current to reduce
3767 * temperature
3768 */
3769static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3770{
3771 int ret;
3772 struct pm8921_chg_chip *chip = the_chip;
3773
3774 ret = param_set_int(val, kp);
3775 if (ret) {
3776 pr_err("error setting value %d\n", ret);
3777 return ret;
3778 }
3779
3780 if (!chip) {
3781 pr_err("called before init\n");
3782 return -EINVAL;
3783 }
3784
3785 if (!chip->thermal_mitigation) {
3786 pr_err("no thermal mitigation\n");
3787 return -EINVAL;
3788 }
3789
3790 if (thermal_mitigation < 0
3791 || thermal_mitigation >= chip->thermal_levels) {
3792 pr_err("out of bound level selected\n");
3793 return -EINVAL;
3794 }
3795
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003796 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003797 return ret;
3798}
3799module_param_call(thermal_mitigation, set_therm_mitigation_level,
3800 param_get_uint,
3801 &thermal_mitigation, 0644);
3802
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003803static int set_usb_max_current(const char *val, struct kernel_param *kp)
3804{
3805 int ret, mA;
3806 struct pm8921_chg_chip *chip = the_chip;
3807
3808 ret = param_set_int(val, kp);
3809 if (ret) {
3810 pr_err("error setting value %d\n", ret);
3811 return ret;
3812 }
3813 if (chip) {
3814 pr_warn("setting current max to %d\n", usb_max_current);
3815 pm_chg_iusbmax_get(chip, &mA);
3816 if (mA > usb_max_current)
3817 pm8921_charger_vbus_draw(usb_max_current);
3818 return 0;
3819 }
3820 return -EINVAL;
3821}
David Keitelacf57c82012-03-07 18:48:50 -08003822module_param_call(usb_max_current, set_usb_max_current,
3823 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825static void free_irqs(struct pm8921_chg_chip *chip)
3826{
3827 int i;
3828
3829 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3830 if (chip->pmic_chg_irq[i]) {
3831 free_irq(chip->pmic_chg_irq[i], chip);
3832 chip->pmic_chg_irq[i] = 0;
3833 }
3834}
3835
David Keitel88e1b572012-01-11 11:57:14 -08003836/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3838{
3839 unsigned long flags;
3840 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003841 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003842
3843 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3844 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3845
3846 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003847 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003848 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003849 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003850 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852
3853 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3854 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3855 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003856 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003857 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3858 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003859 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003860 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3861 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003862 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003863
3864 spin_lock_irqsave(&vbus_lock, flags);
3865 if (usb_chg_current) {
3866 /* reissue a vbus draw call */
3867 __pm8921_charger_vbus_draw(usb_chg_current);
3868 }
3869 spin_unlock_irqrestore(&vbus_lock, flags);
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003870 /*
3871 * The bootloader could have started charging, a fastchg interrupt
3872 * might not happen. Check the real time status and if it is fast
3873 * charging invoke the handler so that the eoc worker could be
3874 * started
3875 */
3876 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3877 if (is_fast_chg)
3878 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879
3880 fsm_state = pm_chg_get_fsm_state(chip);
3881 if (is_battery_charging(fsm_state)) {
3882 chip->bms_notify.is_charging = 1;
3883 pm8921_bms_charging_began();
3884 }
3885
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003886 check_battery_valid(chip);
3887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003888 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3889 chip->usb_present,
3890 chip->dc_present,
3891 get_prop_batt_present(chip),
3892 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003893
3894 /* Determine which USB trim column to use */
3895 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3896 chip->usb_trim_table = usb_trim_8917_table;
3897 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3898 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003899}
3900
3901struct pm_chg_irq_init_data {
3902 unsigned int irq_id;
3903 char *name;
3904 unsigned long flags;
3905 irqreturn_t (*handler)(int, void *);
3906};
3907
3908#define CHG_IRQ(_id, _flags, _handler) \
3909{ \
3910 .irq_id = _id, \
3911 .name = #_id, \
3912 .flags = _flags, \
3913 .handler = _handler, \
3914}
3915struct pm_chg_irq_init_data chg_irq_data[] = {
3916 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3917 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3919 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003920 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3921 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3923 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3924 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3925 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3926 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3927 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3928 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3929 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003930 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3931 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003932 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3933 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3934 batt_removed_irq_handler),
3935 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3936 batttemp_hot_irq_handler),
3937 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3938 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3939 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003940 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3941 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003942 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3943 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003944 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3945 coarse_det_low_irq_handler),
3946 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3947 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3948 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3949 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3950 batfet_irq_handler),
3951 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3952 dcin_valid_irq_handler),
3953 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3954 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003955 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956};
3957
3958static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3959 struct platform_device *pdev)
3960{
3961 struct resource *res;
3962 int ret, i;
3963
3964 ret = 0;
3965 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3966
3967 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3968 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3969 chg_irq_data[i].name);
3970 if (res == NULL) {
3971 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3972 goto err_out;
3973 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003974 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003975 ret = request_irq(res->start, chg_irq_data[i].handler,
3976 chg_irq_data[i].flags,
3977 chg_irq_data[i].name, chip);
3978 if (ret < 0) {
3979 pr_err("couldn't request %d (%s) %d\n", res->start,
3980 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003981 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003982 goto err_out;
3983 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3985 }
3986 return 0;
3987
3988err_out:
3989 free_irqs(chip);
3990 return -EINVAL;
3991}
3992
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003993#define VREF_BATT_THERM_FORCE_ON BIT(7)
3994static void detect_battery_removal(struct pm8921_chg_chip *chip)
3995{
3996 u8 temp;
3997
3998 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3999 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4000
4001 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4002 /*
4003 * batt therm force on bit is battery backed and is default 0
4004 * The charger sets this bit at init time. If this bit is found
4005 * 0 that means the battery was removed. Tell the bms about it
4006 */
4007 pm8921_bms_invalidate_shutdown_soc();
4008}
4009
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010#define ENUM_TIMER_STOP_BIT BIT(1)
4011#define BOOT_DONE_BIT BIT(6)
4012#define CHG_BATFET_ON_BIT BIT(3)
4013#define CHG_VCP_EN BIT(0)
4014#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4015#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004016#define PM_SUB_REV 0x001
4017#define MIN_CHARGE_CURRENT_MA 350
4018#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004019static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4020{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004021 u8 subrev;
4022 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004024 spin_lock_init(&lpm_lock);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08004025
4026 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4027 rc = __pm8921_apply_19p2mhz_kickstart(chip);
4028 if (rc) {
4029 pr_err("Failed to apply kickstart rc=%d\n", rc);
4030 return rc;
4031 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004032 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004033
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004034 detect_battery_removal(chip);
4035
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004037 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 if (rc) {
4039 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4040 return rc;
4041 }
4042
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004043 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4044
4045 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4046 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4047
4048 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050 if (rc) {
4051 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004052 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053 return rc;
4054 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004055 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004056 chip->max_voltage_mv
4057 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058 if (rc) {
4059 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004060 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004061 return rc;
4062 }
4063
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004064 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 if (rc) {
4066 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004067 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 return rc;
4069 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004070
4071 if (chip->safe_current_ma == 0)
4072 chip->safe_current_ma = SAFE_CURRENT_MA;
4073
4074 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004075 if (rc) {
4076 pr_err("Failed to set max voltage to %d rc=%d\n",
4077 SAFE_CURRENT_MA, rc);
4078 return rc;
4079 }
4080
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004081 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 if (rc) {
4083 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4084 return rc;
4085 }
4086
4087 rc = pm_chg_iterm_set(chip, chip->term_current);
4088 if (rc) {
4089 pr_err("Failed to set term current to %d rc=%d\n",
4090 chip->term_current, rc);
4091 return rc;
4092 }
4093
4094 /* Disable the ENUM TIMER */
4095 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4096 ENUM_TIMER_STOP_BIT);
4097 if (rc) {
4098 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4099 return rc;
4100 }
4101
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004102 fcc_uah = pm8921_bms_get_fcc();
4103 if (fcc_uah > 0) {
4104 safety_time = div_s64((s64)fcc_uah * 60,
4105 1000 * MIN_CHARGE_CURRENT_MA);
4106 /* add 20 minutes of buffer time */
4107 safety_time += 20;
4108
4109 /* make sure we do not exceed the maximum programmable time */
4110 if (safety_time > PM8921_CHG_TCHG_MAX)
4111 safety_time = PM8921_CHG_TCHG_MAX;
4112 }
4113
4114 rc = pm_chg_tchg_max_set(chip, safety_time);
4115 if (rc) {
4116 pr_err("Failed to set max time to %d minutes rc=%d\n",
4117 safety_time, rc);
4118 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004119 }
4120
4121 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004122 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004123 if (rc) {
4124 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004125 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004126 return rc;
4127 }
4128 }
4129
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004130 if (chip->vin_min != 0) {
4131 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4132 if (rc) {
4133 pr_err("Failed to set vin min to %d mV rc=%d\n",
4134 chip->vin_min, rc);
4135 return rc;
4136 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004137 } else {
4138 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004139 }
4140
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 rc = pm_chg_disable_wd(chip);
4142 if (rc) {
4143 pr_err("Failed to disable wd rc=%d\n", rc);
4144 return rc;
4145 }
4146
4147 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4148 CHG_BAT_TEMP_DIS_BIT, 0);
4149 if (rc) {
4150 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4151 return rc;
4152 }
4153 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004154 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4155 rc = pm_chg_write(chip,
4156 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4157 else
4158 rc = pm_chg_write(chip,
4159 CHG_BUCK_CLOCK_CTRL, 0x15);
4160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004161 if (rc) {
4162 pr_err("Failed to switch buck clk rc=%d\n", rc);
4163 return rc;
4164 }
4165
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004166 if (chip->trkl_voltage != 0) {
4167 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4168 if (rc) {
4169 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4170 chip->trkl_voltage, rc);
4171 return rc;
4172 }
4173 }
4174
4175 if (chip->weak_voltage != 0) {
4176 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4177 if (rc) {
4178 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4179 chip->weak_voltage, rc);
4180 return rc;
4181 }
4182 }
4183
4184 if (chip->trkl_current != 0) {
4185 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4186 if (rc) {
4187 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4188 chip->trkl_voltage, rc);
4189 return rc;
4190 }
4191 }
4192
4193 if (chip->weak_current != 0) {
4194 rc = pm_chg_iweak_set(chip, chip->weak_current);
4195 if (rc) {
4196 pr_err("Failed to set weak current to %dmA rc=%d\n",
4197 chip->weak_current, rc);
4198 return rc;
4199 }
4200 }
4201
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004202 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4203 if (rc) {
4204 pr_err("Failed to set cold config %d rc=%d\n",
4205 chip->cold_thr, rc);
4206 }
4207
4208 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4209 if (rc) {
4210 pr_err("Failed to set hot config %d rc=%d\n",
4211 chip->hot_thr, rc);
4212 }
4213
Jay Chokshid674a512012-03-15 14:06:04 -07004214 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4215 if (rc) {
4216 pr_err("Failed to set charger LED src config %d rc=%d\n",
4217 chip->led_src_config, rc);
4218 }
4219
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004220 /* Workarounds for die 3.0 */
4221 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4222 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4223 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4224 if (rc) {
4225 pr_err("read failed: addr=%03X, rc=%d\n",
4226 PM_SUB_REV, rc);
4227 return rc;
4228 }
4229 /* Check if die 3.0.1 is present */
4230 if (subrev & 0x1)
4231 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4232 else
4233 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 }
4235
David Keitel0789fc62012-06-07 17:43:27 -07004236 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004237 /* Set PM8917 USB_OVP debounce time to 15 ms */
4238 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4239 OVP_DEBOUNCE_TIME, 0x6);
4240 if (rc) {
4241 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4242 return rc;
4243 }
4244
4245 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004246 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004247 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004248 rc = pm_chg_uvd_threshold_set(chip,
4249 chip->uvd_voltage_mv);
4250 if (rc) {
4251 pr_err("Failed to set UVD threshold %drc=%d\n",
4252 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004253 return rc;
4254 }
David Keitel0789fc62012-06-07 17:43:27 -07004255 }
4256 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004257
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004258 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004259
David Keitela3c0d822011-11-03 14:18:52 -07004260 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004261 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004262
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004263 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4264 VREF_BATT_THERM_FORCE_ON);
4265 if (rc)
4266 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004268 rc = pm_chg_charge_dis(chip, charging_disabled);
4269 if (rc) {
4270 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4271 return rc;
4272 }
4273
4274 rc = pm_chg_auto_enable(chip, !charging_disabled);
4275 if (rc) {
4276 pr_err("Failed to enable charging rc=%d\n", rc);
4277 return rc;
4278 }
4279
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004280 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4281 /* Clear kickstart */
4282 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4283 if (rc) {
4284 pr_err("Failed to clear kickstart rc=%d\n", rc);
4285 return rc;
4286 }
4287
4288 /* From here the lpm_workaround will be active */
4289 chip->lockup_lpm_wrkarnd = true;
4290
4291 /* Enable LPM */
4292 pm8921_chg_set_lpm(chip, 1);
4293 }
4294
4295 if (chip->lockup_lpm_wrkarnd) {
4296 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4297 if (IS_ERR(chip->vreg_xoadc))
4298 return -ENODEV;
4299
4300 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4301 if (rc < 0) {
4302 pr_err("Failed to set configure HPM rc=%d\n", rc);
4303 return rc;
4304 }
4305
4306 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4307 if (rc) {
4308 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4309 return rc;
4310 }
4311
4312 rc = regulator_enable(chip->vreg_xoadc);
4313 if (rc) {
4314 pr_err("Failed to enable L14 rc=%d\n", rc);
4315 return rc;
4316 }
4317 }
4318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004319 return 0;
4320}
4321
4322static int get_rt_status(void *data, u64 * val)
4323{
4324 int i = (int)data;
4325 int ret;
4326
4327 /* global irq number is passed in via data */
4328 ret = pm_chg_get_rt_status(the_chip, i);
4329 *val = ret;
4330 return 0;
4331}
4332DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4333
4334static int get_fsm_status(void *data, u64 * val)
4335{
4336 u8 temp;
4337
4338 temp = pm_chg_get_fsm_state(the_chip);
4339 *val = temp;
4340 return 0;
4341}
4342DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4343
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004344static int get_reg_loop(void *data, u64 * val)
4345{
4346 u8 temp;
4347
4348 if (!the_chip) {
4349 pr_err("%s called before init\n", __func__);
4350 return -EINVAL;
4351 }
4352 temp = pm_chg_get_regulation_loop(the_chip);
4353 *val = temp;
4354 return 0;
4355}
4356DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358static int get_reg(void *data, u64 * val)
4359{
4360 int addr = (int)data;
4361 int ret;
4362 u8 temp;
4363
4364 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4365 if (ret) {
4366 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4367 addr, temp, ret);
4368 return -EAGAIN;
4369 }
4370 *val = temp;
4371 return 0;
4372}
4373
4374static int set_reg(void *data, u64 val)
4375{
4376 int addr = (int)data;
4377 int ret;
4378 u8 temp;
4379
4380 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004381 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004382 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004383 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004384 addr, temp, ret);
4385 return -EAGAIN;
4386 }
4387 return 0;
4388}
4389DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4390
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004391static int reg_loop;
4392#define MAX_REG_LOOP_CHAR 10
4393static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4394{
4395 u8 temp;
4396
4397 if (!the_chip) {
4398 pr_err("called before init\n");
4399 return -EINVAL;
4400 }
4401 temp = pm_chg_get_regulation_loop(the_chip);
4402 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4403}
4404module_param_call(reg_loop, NULL, get_reg_loop_param,
4405 &reg_loop, 0644);
4406
4407static int max_chg_ma;
4408#define MAX_MA_CHAR 10
4409static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4410{
4411 if (!the_chip) {
4412 pr_err("called before init\n");
4413 return -EINVAL;
4414 }
4415 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4416}
4417module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4418 &max_chg_ma, 0644);
4419static int ibatmax_ma;
4420static int set_ibat_max(const char *val, struct kernel_param *kp)
4421{
4422 int rc;
4423
4424 if (!the_chip) {
4425 pr_err("called before init\n");
4426 return -EINVAL;
4427 }
4428
4429 rc = param_set_int(val, kp);
4430 if (rc) {
4431 pr_err("error setting value %d\n", rc);
4432 return rc;
4433 }
4434
4435 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4436 <= the_chip->ibatmax_max_adj_ma) {
4437 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4438 if (rc) {
4439 pr_err("Failed to set ibatmax rc = %d\n", rc);
4440 return rc;
4441 }
4442 }
4443
4444 return 0;
4445}
4446static int get_ibat_max(char *buf, struct kernel_param *kp)
4447{
4448 int ibat_ma;
4449 int rc;
4450
4451 if (!the_chip) {
4452 pr_err("called before init\n");
4453 return -EINVAL;
4454 }
4455
4456 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4457 if (rc) {
4458 pr_err("ibatmax_get error = %d\n", rc);
4459 return rc;
4460 }
4461
4462 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4463}
4464module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4465 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004466enum {
4467 BAT_WARM_ZONE,
4468 BAT_COOL_ZONE,
4469};
4470static int get_warm_cool(void *data, u64 * val)
4471{
4472 if (!the_chip) {
4473 pr_err("%s called before init\n", __func__);
4474 return -EINVAL;
4475 }
4476 if ((int)data == BAT_WARM_ZONE)
4477 *val = the_chip->is_bat_warm;
4478 if ((int)data == BAT_COOL_ZONE)
4479 *val = the_chip->is_bat_cool;
4480 return 0;
4481}
4482DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004484static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4485{
4486 int i;
4487
4488 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4489
4490 if (IS_ERR(chip->dent)) {
4491 pr_err("pmic charger couldnt create debugfs dir\n");
4492 return;
4493 }
4494
4495 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4496 (void *)CHG_CNTRL, &reg_fops);
4497 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4498 (void *)CHG_CNTRL_2, &reg_fops);
4499 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4500 (void *)CHG_CNTRL_3, &reg_fops);
4501 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4502 (void *)PBL_ACCESS1, &reg_fops);
4503 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4504 (void *)PBL_ACCESS2, &reg_fops);
4505 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4506 (void *)SYS_CONFIG_1, &reg_fops);
4507 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4508 (void *)SYS_CONFIG_2, &reg_fops);
4509 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4510 (void *)CHG_VDD_MAX, &reg_fops);
4511 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4512 (void *)CHG_VDD_SAFE, &reg_fops);
4513 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4514 (void *)CHG_VBAT_DET, &reg_fops);
4515 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4516 (void *)CHG_IBAT_MAX, &reg_fops);
4517 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4518 (void *)CHG_IBAT_SAFE, &reg_fops);
4519 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4520 (void *)CHG_VIN_MIN, &reg_fops);
4521 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4522 (void *)CHG_VTRICKLE, &reg_fops);
4523 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4524 (void *)CHG_ITRICKLE, &reg_fops);
4525 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4526 (void *)CHG_ITERM, &reg_fops);
4527 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4528 (void *)CHG_TCHG_MAX, &reg_fops);
4529 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4530 (void *)CHG_TWDOG, &reg_fops);
4531 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4532 (void *)CHG_TEMP_THRESH, &reg_fops);
4533 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4534 (void *)CHG_COMP_OVR, &reg_fops);
4535 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4536 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4537 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4538 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4539 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4540 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4541 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4542 (void *)CHG_TEST, &reg_fops);
4543
4544 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4545 &fsm_fops);
4546
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004547 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4548 &reg_loop_fops);
4549
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004550 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4551 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4552 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4553 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004555 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4556 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4557 debugfs_create_file(chg_irq_data[i].name, 0444,
4558 chip->dent,
4559 (void *)chg_irq_data[i].irq_id,
4560 &rt_fops);
4561 }
4562}
4563
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004564static int pm8921_charger_suspend_noirq(struct device *dev)
4565{
4566 int rc;
4567 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4568
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004569 if (chip->lockup_lpm_wrkarnd) {
4570 rc = regulator_disable(chip->vreg_xoadc);
4571 if (rc)
4572 pr_err("Failed to disable L14 rc=%d\n", rc);
4573
4574 rc = pm8921_apply_19p2mhz_kickstart(chip);
4575 if (rc)
4576 pr_err("Failed to apply kickstart rc=%d\n", rc);
4577 }
4578
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004579 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4580 if (rc)
4581 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004582 return 0;
4583}
4584
4585static int pm8921_charger_resume_noirq(struct device *dev)
4586{
4587 int rc;
4588 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4589
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004590 if (chip->lockup_lpm_wrkarnd) {
4591 rc = regulator_enable(chip->vreg_xoadc);
4592 if (rc)
4593 pr_err("Failed to enable L14 rc=%d\n", rc);
4594
4595 rc = pm8921_apply_19p2mhz_kickstart(chip);
4596 if (rc)
4597 pr_err("Failed to apply kickstart rc=%d\n", rc);
4598 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004599
4600 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4601 VREF_BATT_THERM_FORCE_ON);
4602 if (rc)
4603 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4604 return 0;
4605}
4606
David Keitelf2226022011-12-13 15:55:50 -08004607static int pm8921_charger_resume(struct device *dev)
4608{
David Keitelf2226022011-12-13 15:55:50 -08004609 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4610
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004611 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4612 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4613 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4614 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004615
4616 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4617 is_usb_chg_plugged_in(the_chip)))
4618 schedule_delayed_work(&chip->btc_override_work, 0);
4619
David Keitelf2226022011-12-13 15:55:50 -08004620 return 0;
4621}
4622
4623static int pm8921_charger_suspend(struct device *dev)
4624{
David Keitelf2226022011-12-13 15:55:50 -08004625 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4626
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004627 if (chip->btc_override)
4628 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004629
4630 if (is_usb_chg_plugged_in(chip)) {
4631 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4632 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4633 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004634
David Keitelf2226022011-12-13 15:55:50 -08004635 return 0;
4636}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004637static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4638{
4639 int rc = 0;
4640 struct pm8921_chg_chip *chip;
4641 const struct pm8921_charger_platform_data *pdata
4642 = pdev->dev.platform_data;
4643
4644 if (!pdata) {
4645 pr_err("missing platform data\n");
4646 return -EINVAL;
4647 }
4648
4649 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4650 GFP_KERNEL);
4651 if (!chip) {
4652 pr_err("Cannot allocate pm_chg_chip\n");
4653 return -ENOMEM;
4654 }
4655
4656 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004657 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004658 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004659 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004660 chip->alarm_low_mv = pdata->alarm_low_mv;
4661 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004662 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004663 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004664 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004665 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004666 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004667 chip->term_current = pdata->term_current;
4668 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004669 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004670 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4671 chip->batt_id_min = pdata->batt_id_min;
4672 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004673 if (pdata->cool_temp != INT_MIN)
4674 chip->cool_temp_dc = pdata->cool_temp * 10;
4675 else
4676 chip->cool_temp_dc = INT_MIN;
4677
4678 if (pdata->warm_temp != INT_MIN)
4679 chip->warm_temp_dc = pdata->warm_temp * 10;
4680 else
4681 chip->warm_temp_dc = INT_MIN;
4682
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004683 chip->temp_check_period = pdata->temp_check_period;
4684 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004685 /* Assign to corresponding module parameter */
4686 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004687 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4688 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4689 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4690 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004691 chip->trkl_voltage = pdata->trkl_voltage;
4692 chip->weak_voltage = pdata->weak_voltage;
4693 chip->trkl_current = pdata->trkl_current;
4694 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004695 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004696 chip->thermal_mitigation = pdata->thermal_mitigation;
4697 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004698
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004699 chip->cold_thr = pdata->cold_thr;
4700 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004701 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004702 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004703 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004704 chip->battery_less_hardware = pdata->battery_less_hardware;
4705 chip->btc_override = pdata->btc_override;
4706 if (chip->btc_override) {
4707 chip->btc_delay_ms = pdata->btc_delay_ms;
4708 chip->btc_override_cold_decidegc
4709 = pdata->btc_override_cold_degc * 10;
4710 chip->btc_override_hot_decidegc
4711 = pdata->btc_override_hot_degc * 10;
4712 chip->btc_panic_if_cant_stop_chg
4713 = pdata->btc_panic_if_cant_stop_chg;
4714 }
4715
4716 if (chip->battery_less_hardware)
4717 charging_disabled = 1;
4718
4719 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4720 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004722 rc = pm8921_chg_hw_init(chip);
4723 if (rc) {
4724 pr_err("couldn't init hardware rc=%d\n", rc);
4725 goto free_chip;
4726 }
4727
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004728 if (chip->btc_override)
4729 pm8921_chg_btc_override_init(chip);
4730
4731 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
4732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 chip->usb_psy.name = "usb",
4734 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4735 chip->usb_psy.supplied_to = pm_power_supplied_to,
4736 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004737 chip->usb_psy.properties = pm_power_props_usb,
4738 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4739 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004740 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741
David Keitel6ed71a52012-01-30 12:42:18 -08004742 chip->dc_psy.name = "pm8921-dc",
4743 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4744 chip->dc_psy.supplied_to = pm_power_supplied_to,
4745 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004746 chip->dc_psy.properties = pm_power_props_mains,
4747 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4748 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750 chip->batt_psy.name = "battery",
4751 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4752 chip->batt_psy.properties = msm_batt_power_props,
4753 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4754 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004755 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756 rc = power_supply_register(chip->dev, &chip->usb_psy);
4757 if (rc < 0) {
4758 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004759 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004760 }
4761
David Keitel6ed71a52012-01-30 12:42:18 -08004762 rc = power_supply_register(chip->dev, &chip->dc_psy);
4763 if (rc < 0) {
4764 pr_err("power_supply_register usb failed rc = %d\n", rc);
4765 goto unregister_usb;
4766 }
4767
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004768 rc = power_supply_register(chip->dev, &chip->batt_psy);
4769 if (rc < 0) {
4770 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004771 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 }
4773
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004774 platform_set_drvdata(pdev, chip);
4775 the_chip = chip;
4776
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004777 /* set initial state of the USB charger type to UNKNOWN */
4778 power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
4779
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004780 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004781 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004782 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4783 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004784 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004785
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004786 INIT_WORK(&chip->bms_notify.work, bms_notify);
4787 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4788
4789 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4790 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004792 rc = request_irqs(chip, pdev);
4793 if (rc) {
4794 pr_err("couldn't register interrupts rc=%d\n", rc);
4795 goto unregister_batt;
4796 }
4797
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004798 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004799 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004800 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004801 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004803 create_debugfs_entries(chip);
4804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805 /* determine what state the charger is in */
4806 determine_initial_state(chip);
4807
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004808 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004809 schedule_delayed_work(&chip->update_heartbeat_work,
4810 round_jiffies_relative(msecs_to_jiffies
4811 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004812 return 0;
4813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004814unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004815 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004816 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004817unregister_dc:
4818 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819unregister_usb:
4820 power_supply_unregister(&chip->usb_psy);
4821free_chip:
4822 kfree(chip);
4823 return rc;
4824}
4825
4826static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4827{
4828 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4829
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004830 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004831 free_irqs(chip);
4832 platform_set_drvdata(pdev, NULL);
4833 the_chip = NULL;
4834 kfree(chip);
4835 return 0;
4836}
David Keitelf2226022011-12-13 15:55:50 -08004837static const struct dev_pm_ops pm8921_pm_ops = {
4838 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004839 .suspend_noirq = pm8921_charger_suspend_noirq,
4840 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004841 .resume = pm8921_charger_resume,
4842};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004844 .probe = pm8921_charger_probe,
4845 .remove = __devexit_p(pm8921_charger_remove),
4846 .driver = {
4847 .name = PM8921_CHARGER_DEV_NAME,
4848 .owner = THIS_MODULE,
4849 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004850 },
4851};
4852
4853static int __init pm8921_charger_init(void)
4854{
4855 return platform_driver_register(&pm8921_charger_driver);
4856}
4857
4858static void __exit pm8921_charger_exit(void)
4859{
4860 platform_driver_unregister(&pm8921_charger_driver);
4861}
4862
4863late_initcall(pm8921_charger_init);
4864module_exit(pm8921_charger_exit);
4865
4866MODULE_LICENSE("GPL v2");
4867MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4868MODULE_VERSION("1.0");
4869MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);