blob: 46bd3aecde391ddc72d267d44586ea2ba6aa2af9 [file] [log] [blame]
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070024#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/delay.h>
27#include <linux/bitops.h>
28#include <linux/workqueue.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
Ajay Dudani11aeb7b2012-06-28 19:14:30 -070031#include <linux/mfd/pm8xxx/batt-alarm.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070032#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033
34#include <mach/msm_xo.h>
35#include <mach/msm_hsusb.h>
36
37#define CHG_BUCK_CLOCK_CTRL 0x14
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070038#define CHG_BUCK_CLOCK_CTRL_8038 0xD
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#define PBL_ACCESS1 0x04
41#define PBL_ACCESS2 0x05
42#define SYS_CONFIG_1 0x06
43#define SYS_CONFIG_2 0x07
44#define CHG_CNTRL 0x204
45#define CHG_IBAT_MAX 0x205
46#define CHG_TEST 0x206
47#define CHG_BUCK_CTRL_TEST1 0x207
48#define CHG_BUCK_CTRL_TEST2 0x208
49#define CHG_BUCK_CTRL_TEST3 0x209
50#define COMPARATOR_OVERRIDE 0x20A
51#define PSI_TXRX_SAMPLE_DATA_0 0x20B
52#define PSI_TXRX_SAMPLE_DATA_1 0x20C
53#define PSI_TXRX_SAMPLE_DATA_2 0x20D
54#define PSI_TXRX_SAMPLE_DATA_3 0x20E
55#define PSI_CONFIG_STATUS 0x20F
56#define CHG_IBAT_SAFE 0x210
57#define CHG_ITRICKLE 0x211
58#define CHG_CNTRL_2 0x212
59#define CHG_VBAT_DET 0x213
60#define CHG_VTRICKLE 0x214
61#define CHG_ITERM 0x215
62#define CHG_CNTRL_3 0x216
63#define CHG_VIN_MIN 0x217
64#define CHG_TWDOG 0x218
65#define CHG_TTRKL_MAX 0x219
66#define CHG_TEMP_THRESH 0x21A
67#define CHG_TCHG_MAX 0x21B
68#define USB_OVP_CONTROL 0x21C
69#define DC_OVP_CONTROL 0x21D
70#define USB_OVP_TEST 0x21E
71#define DC_OVP_TEST 0x21F
72#define CHG_VDD_MAX 0x220
73#define CHG_VDD_SAFE 0x221
74#define CHG_VBAT_BOOT_THRESH 0x222
75#define USB_OVP_TRIM 0x355
76#define BUCK_CONTROL_TRIM1 0x356
77#define BUCK_CONTROL_TRIM2 0x357
78#define BUCK_CONTROL_TRIM3 0x358
79#define BUCK_CONTROL_TRIM4 0x359
80#define CHG_DEFAULTS_TRIM 0x35A
81#define CHG_ITRIM 0x35B
82#define CHG_TTRIM 0x35C
83#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070084#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070085#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070087/* check EOC every 10 seconds */
88#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080089/* check for USB unplug every 200 msecs */
90#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070091#define UNPLUG_CHECK_RAMP_MS 25
92#define USB_TRIM_ENTRIES 16
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094enum chg_fsm_state {
95 FSM_STATE_OFF_0 = 0,
96 FSM_STATE_BATFETDET_START_12 = 12,
97 FSM_STATE_BATFETDET_END_16 = 16,
98 FSM_STATE_ON_CHG_HIGHI_1 = 1,
99 FSM_STATE_ATC_2A = 2,
100 FSM_STATE_ATC_2B = 18,
101 FSM_STATE_ON_BAT_3 = 3,
102 FSM_STATE_ATC_FAIL_4 = 4 ,
103 FSM_STATE_DELAY_5 = 5,
104 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
105 FSM_STATE_FAST_CHG_7 = 7,
106 FSM_STATE_TRKL_CHG_8 = 8,
107 FSM_STATE_CHG_FAIL_9 = 9,
108 FSM_STATE_EOC_10 = 10,
109 FSM_STATE_ON_CHG_VREGOK_11 = 11,
110 FSM_STATE_ATC_PAUSE_13 = 13,
111 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
112 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
113 FSM_STATE_START_BOOT = 20,
114 FSM_STATE_FLCB_VREGOK = 21,
115 FSM_STATE_FLCB = 22,
116};
117
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700118struct fsm_state_to_batt_status {
119 enum chg_fsm_state fsm_state;
120 int batt_state;
121};
122
123static struct fsm_state_to_batt_status map[] = {
124 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
125 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
126 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
127 /*
128 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
129 * too hot/cold, charger too hot
130 */
131 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
132 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
134 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
135 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
136 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
137 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
138 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
139 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
140 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
141 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
142 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
143 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
144 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
146 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
147 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
149};
150
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700151enum chg_regulation_loop {
152 VDD_LOOP = BIT(3),
153 BAT_CURRENT_LOOP = BIT(2),
154 INPUT_CURRENT_LOOP = BIT(1),
155 INPUT_VOLTAGE_LOOP = BIT(0),
156 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
157 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160enum pmic_chg_interrupts {
161 USBIN_VALID_IRQ = 0,
162 USBIN_OV_IRQ,
163 BATT_INSERTED_IRQ,
164 VBATDET_LOW_IRQ,
165 USBIN_UV_IRQ,
166 VBAT_OV_IRQ,
167 CHGWDOG_IRQ,
168 VCP_IRQ,
169 ATCDONE_IRQ,
170 ATCFAIL_IRQ,
171 CHGDONE_IRQ,
172 CHGFAIL_IRQ,
173 CHGSTATE_IRQ,
174 LOOP_CHANGE_IRQ,
175 FASTCHG_IRQ,
176 TRKLCHG_IRQ,
177 BATT_REMOVED_IRQ,
178 BATTTEMP_HOT_IRQ,
179 CHGHOT_IRQ,
180 BATTTEMP_COLD_IRQ,
181 CHG_GONE_IRQ,
182 BAT_TEMP_OK_IRQ,
183 COARSE_DET_LOW_IRQ,
184 VDD_LOOP_IRQ,
185 VREG_OV_IRQ,
186 VBATDET_IRQ,
187 BATFET_IRQ,
188 PSI_IRQ,
189 DCIN_VALID_IRQ,
190 DCIN_OV_IRQ,
191 DCIN_UV_IRQ,
192 PM_CHG_MAX_INTS,
193};
194
195struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700196 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 int is_charging;
198 struct work_struct work;
199};
200
201/**
202 * struct pm8921_chg_chip -device information
203 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 * @usb_present: present status of usb
205 * @dc_present: present status of dc
206 * @usb_charger_current: usb current to charge the battery with used when
207 * the usb path is enabled or charging is resumed
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800209 * @max_voltage_mv: the max volts the batt should be charged up to
210 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700211 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700212 * @alarm_low_mv: the battery alarm voltage low
213 * @alarm_high_mv: the battery alarm voltage high
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800214 * @cool_temp_dc: the cool temp threshold in deciCelcius
215 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700216 * @resume_voltage_delta: the voltage delta from vdd max at which the
217 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 * @term_current: The charging based term current
219 *
220 */
221struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700222 struct device *dev;
223 unsigned int usb_present;
224 unsigned int dc_present;
225 unsigned int usb_charger_current;
226 unsigned int max_bat_chg_current;
227 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700228 unsigned int ttrkl_time;
229 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800230 unsigned int max_voltage_mv;
231 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700232 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700233 unsigned int safe_current_ma;
234 unsigned int alarm_low_mv;
235 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800236 int cool_temp_dc;
237 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700238 unsigned int temp_check_period;
239 unsigned int cool_bat_chg_current;
240 unsigned int warm_bat_chg_current;
241 unsigned int cool_bat_voltage;
242 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700243 unsigned int is_bat_cool;
244 unsigned int is_bat_warm;
245 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700246 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 unsigned int term_current;
248 unsigned int vbat_channel;
249 unsigned int batt_temp_channel;
250 unsigned int batt_id_channel;
251 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800252 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800253 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700254 struct power_supply batt_psy;
255 struct dentry *dent;
256 struct bms_notify bms_notify;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700257 int *usb_trim_table;
258 struct regulator *vreg_xoadc;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200259 bool ext_charging;
260 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700261 bool iusb_fine_res;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700262 bool final_kickstart;
263 bool lockup_lpm_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700265 struct work_struct battery_id_valid_work;
266 int64_t batt_id_min;
267 int64_t batt_id_max;
268 int trkl_voltage;
269 int weak_voltage;
270 int trkl_current;
271 int weak_current;
272 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800273 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700274 int thermal_levels;
275 struct delayed_work update_heartbeat_work;
276 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800277 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800278 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700279 struct delayed_work btc_override_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700280 struct wake_lock eoc_wake_lock;
281 enum pm8921_chg_cold_thr cold_thr;
282 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800283 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700284 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700285 bool host_mode;
David Keitelff4f9ce2012-08-24 15:11:23 -0700286 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700287 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700288 int recent_reported_soc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700289 int battery_less_hardware;
290 int ibatmax_max_adj_ma;
291 int btc_override;
292 int btc_override_cold_decidegc;
293 int btc_override_hot_decidegc;
294 int btc_delay_ms;
295 bool btc_panic_if_cant_stop_chg;
296 int stop_chg_upon_expiry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297};
298
David Keitelacf57c82012-03-07 18:48:50 -0800299/* user space parameter to limit usb current */
300static unsigned int usb_max_current;
301/*
302 * usb_target_ma is used for wall charger
303 * adaptive input current limiting only. Use
304 * pm_iusbmax_get() to get current maximum usb current setting.
305 */
306static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700308static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
310static struct pm8921_chg_chip *the_chip;
311
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700312static DEFINE_SPINLOCK(lpm_lock);
313#define LPM_ENABLE_BIT BIT(2)
314static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
315{
316 int rc;
317 u8 reg;
318
319 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
320 if (rc) {
321 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
322 CHG_CNTRL, rc);
323 return rc;
324 }
325 reg &= ~LPM_ENABLE_BIT;
326 reg |= (enable ? LPM_ENABLE_BIT : 0);
327
328 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
329 if (rc) {
330 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
331 CHG_CNTRL, rc);
332 return rc;
333 }
334
335 return rc;
336}
337
338static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
339{
340 int rc;
341 unsigned long flags = 0;
342
343 /* Disable LPM */
344 if (chip->lockup_lpm_wrkarnd) {
345 spin_lock_irqsave(&lpm_lock, flags);
346
347 /*
348 * This write could have initiated right after a previous write.
349 * Allow time to settle to go in to lpm from the previous write
350 */
351 udelay(200);
352 rc = pm8921_chg_set_lpm(chip, 0);
353 if (rc)
354 goto lpm_err;
355
356 /* Wait to come out of LPM */
357 udelay(200);
358 }
359
360 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
361 if (rc) {
362 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
363 goto lpm_err;
364 }
365
366 /* Enable LPM */
367 if (chip->lockup_lpm_wrkarnd)
368 rc = pm8921_chg_set_lpm(chip, 1);
369
370lpm_err:
371 if (chip->lockup_lpm_wrkarnd)
372 spin_unlock_irqrestore(&lpm_lock, flags);
373
374 return rc;
375}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
378 u8 mask, u8 val)
379{
380 int rc;
381 u8 reg;
382
383 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
384 if (rc) {
385 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
386 return rc;
387 }
388 reg &= ~mask;
389 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700390 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700392 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 return rc;
394 }
395 return 0;
396}
397
David Keitelcf867232012-01-27 18:40:12 -0800398static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
399{
400 return pm8xxx_read_irq_stat(chip->dev->parent,
401 chip->pmic_chg_irq[irq_id]);
402}
403
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700404static int is_chg_on_bat(struct pm8921_chg_chip *chip)
405{
406 return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
407 || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
408}
409
410static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
411 int bypass)
412{
413 int rc;
414
415 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
416 if (rc) {
417 pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
418 }
419}
420
David Keitelcf867232012-01-27 18:40:12 -0800421/* Treat OverVoltage/UnderVoltage as source missing */
422static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
423{
424 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
425}
426
427/* Treat OverVoltage/UnderVoltage as source missing */
428static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
429{
430 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
431}
432
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700433static int is_batfet_closed(struct pm8921_chg_chip *chip)
434{
435 return pm_chg_get_rt_status(chip, BATFET_IRQ);
436}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437#define CAPTURE_FSM_STATE_CMD 0xC2
438#define READ_BANK_7 0x70
439#define READ_BANK_4 0x40
440static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
441{
442 u8 temp;
443 int err, ret = 0;
444
445 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700446 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 if (err) {
448 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
449 return err;
450 }
451
452 temp = READ_BANK_7;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700453 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 if (err) {
455 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
456 return err;
457 }
458
459 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
460 if (err) {
461 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
462 return err;
463 }
464 /* get the lower 4 bits */
465 ret = temp & 0xF;
466
467 temp = READ_BANK_4;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700468 err = pm_chg_write(chip, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 if (err) {
470 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
471 return err;
472 }
473
474 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
475 if (err) {
476 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
477 return err;
478 }
479 /* get the upper 1 bit */
480 ret |= (temp & 0x1) << 4;
481 return ret;
482}
483
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700484#define READ_BANK_6 0x60
485static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
486{
487 u8 temp;
488 int err;
489
490 temp = READ_BANK_6;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700491 err = pm_chg_write(chip, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700492 if (err) {
493 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
494 return err;
495 }
496
497 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
498 if (err) {
499 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
500 return err;
501 }
502
503 /* return the lower 4 bits */
504 return temp & CHG_ALL_LOOPS;
505}
506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507#define CHG_USB_SUSPEND_BIT BIT(2)
508static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
509{
510 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
511 enable ? CHG_USB_SUSPEND_BIT : 0);
512}
513
514#define CHG_EN_BIT BIT(7)
515static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
516{
517 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
518 enable ? CHG_EN_BIT : 0);
519}
520
David Keitel753ec8d2011-11-02 10:56:37 -0700521#define CHG_FAILED_CLEAR BIT(0)
522#define ATC_FAILED_CLEAR BIT(1)
523static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
524{
525 int rc;
526
527 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
528 clear ? ATC_FAILED_CLEAR : 0);
529 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
530 clear ? CHG_FAILED_CLEAR : 0);
531 return rc;
532}
533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534#define CHG_CHARGE_DIS_BIT BIT(1)
535static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
536{
537 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
538 disable ? CHG_CHARGE_DIS_BIT : 0);
539}
540
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800541static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
542{
543 u8 temp;
544
545 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
546 return temp & CHG_CHARGE_DIS_BIT;
547}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548#define PM8921_CHG_V_MIN_MV 3240
549#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800550#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551#define PM8921_CHG_VDDMAX_MAX 4500
552#define PM8921_CHG_VDDMAX_MIN 3400
553#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800554static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800556 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800557 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800559 if (voltage < PM8921_CHG_VDDMAX_MIN
560 || voltage > PM8921_CHG_VDDMAX_MAX) {
561 pr_err("bad mV=%d asked to set\n", voltage);
562 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 }
David Keitelcf867232012-01-27 18:40:12 -0800564
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800565 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
566
567 remainder = voltage % 20;
568 if (remainder >= 10) {
569 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
570 }
571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700573 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574}
575
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700576static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
577{
578 u8 temp;
579 int rc;
580
581 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
582 if (rc) {
583 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700584 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700585 return rc;
586 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800587 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
588 + PM8921_CHG_V_MIN_MV;
589 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
590 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700591 return 0;
592}
593
David Keitelcf867232012-01-27 18:40:12 -0800594static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
595{
596 int current_mv, ret, steps, i;
597 bool increase;
598
599 ret = 0;
600
601 if (voltage < PM8921_CHG_VDDMAX_MIN
602 || voltage > PM8921_CHG_VDDMAX_MAX) {
603 pr_err("bad mV=%d asked to set\n", voltage);
604 return -EINVAL;
605 }
606
607 ret = pm_chg_vddmax_get(chip, &current_mv);
608 if (ret) {
609 pr_err("Failed to read vddmax rc=%d\n", ret);
610 return -EINVAL;
611 }
612 if (current_mv == voltage)
613 return 0;
614
615 /* Only change in increments when USB is present */
616 if (is_usb_chg_plugged_in(chip)) {
617 if (current_mv < voltage) {
618 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
619 increase = true;
620 } else {
621 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
622 increase = false;
623 }
624 for (i = 0; i < steps; i++) {
625 if (increase)
626 current_mv += PM8921_CHG_V_STEP_MV;
627 else
628 current_mv -= PM8921_CHG_V_STEP_MV;
629 ret |= __pm_chg_vddmax_set(chip, current_mv);
630 }
631 }
632 ret |= __pm_chg_vddmax_set(chip, voltage);
633 return ret;
634}
635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636#define PM8921_CHG_VDDSAFE_MIN 3400
637#define PM8921_CHG_VDDSAFE_MAX 4500
638static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
639{
640 u8 temp;
641
642 if (voltage < PM8921_CHG_VDDSAFE_MIN
643 || voltage > PM8921_CHG_VDDSAFE_MAX) {
644 pr_err("bad mV=%d asked to set\n", voltage);
645 return -EINVAL;
646 }
647 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
648 pr_debug("voltage=%d setting %02x\n", voltage, temp);
649 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
650}
651
652#define PM8921_CHG_VBATDET_MIN 3240
653#define PM8921_CHG_VBATDET_MAX 5780
654static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
655{
656 u8 temp;
657
658 if (voltage < PM8921_CHG_VBATDET_MIN
659 || voltage > PM8921_CHG_VBATDET_MAX) {
660 pr_err("bad mV=%d asked to set\n", voltage);
661 return -EINVAL;
662 }
663 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
664 pr_debug("voltage=%d setting %02x\n", voltage, temp);
665 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
666}
667
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700668#define PM8921_CHG_VINMIN_MIN_MV 3800
669#define PM8921_CHG_VINMIN_STEP_MV 100
670#define PM8921_CHG_VINMIN_USABLE_MAX 6500
671#define PM8921_CHG_VINMIN_USABLE_MIN 4300
672#define PM8921_CHG_VINMIN_MASK 0x1F
673static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
674{
675 u8 temp;
676
677 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
678 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
679 pr_err("bad mV=%d asked to set\n", voltage);
680 return -EINVAL;
681 }
682 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
683 pr_debug("voltage=%d setting %02x\n", voltage, temp);
684 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
685 temp);
686}
687
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800688static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
689{
690 u8 temp;
691 int rc, voltage_mv;
692
693 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
694 temp &= PM8921_CHG_VINMIN_MASK;
695
696 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
697 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
698
699 return voltage_mv;
700}
701
David Keitel0789fc62012-06-07 17:43:27 -0700702#define PM8917_USB_UVD_MIN_MV 3850
703#define PM8917_USB_UVD_MAX_MV 4350
704#define PM8917_USB_UVD_STEP_MV 100
705#define PM8917_USB_UVD_MASK 0x7
706static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
707{
708 u8 temp;
709
710 if (thresh_mv < PM8917_USB_UVD_MIN_MV
711 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
712 pr_err("bad mV=%d asked to set\n", thresh_mv);
713 return -EINVAL;
714 }
715 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
716 return pm_chg_masked_write(chip, OVP_USB_UVD,
717 PM8917_USB_UVD_MASK, temp);
718}
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700721#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722#define PM8921_CHG_I_MIN_MA 225
723#define PM8921_CHG_I_STEP_MA 50
724#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700725static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
726{
727 u8 temp;
728 int rc;
729
730 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
731 if (rc) {
732 pr_err("rc = %d while reading ibat max\n", rc);
733 *ibat_ma = 0;
734 return rc;
735 }
736 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
737 + PM8921_CHG_I_MIN_MA;
738 return 0;
739}
740
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
742{
743 u8 temp;
744
745 if (chg_current < PM8921_CHG_IBATMAX_MIN
746 || chg_current > PM8921_CHG_IBATMAX_MAX) {
747 pr_err("bad mA=%d asked to set\n", chg_current);
748 return -EINVAL;
749 }
750 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
751 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
752}
753
754#define PM8921_CHG_IBATSAFE_MIN 225
755#define PM8921_CHG_IBATSAFE_MAX 3375
756static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
757{
758 u8 temp;
759
760 if (chg_current < PM8921_CHG_IBATSAFE_MIN
761 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
762 pr_err("bad mA=%d asked to set\n", chg_current);
763 return -EINVAL;
764 }
765 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
766 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
767 PM8921_CHG_I_MASK, temp);
768}
769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700771#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772#define PM8921_CHG_ITERM_STEP_MA 10
773#define PM8921_CHG_ITERM_MASK 0xF
774static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
775{
776 u8 temp;
777
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700778 if (chg_current < PM8921_CHG_ITERM_MIN_MA
779 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 pr_err("bad mA=%d asked to set\n", chg_current);
781 return -EINVAL;
782 }
783
784 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
785 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700786 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 temp);
788}
789
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700790static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
791{
792 u8 temp;
793 int rc;
794
795 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
796 if (rc) {
797 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700798 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700799 return rc;
800 }
801 temp &= PM8921_CHG_ITERM_MASK;
802 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
803 + PM8921_CHG_ITERM_MIN_MA;
804 return 0;
805}
806
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800807struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700808 int usb_ma;
809 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800810};
811
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700812/* USB Trim tables */
813static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
814 0x0,
815 0x0,
816 -0x9,
817 0x0,
818 -0xD,
819 0x0,
820 -0x10,
821 -0x11,
822 0x0,
823 0x0,
824 -0x25,
825 0x0,
826 -0x28,
827 0x0,
828 -0x32,
829 0x0
830};
831
832static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
833 0x0,
834 0x0,
835 0xA,
836 0xC,
837 0x10,
838 0x10,
839 0x13,
840 0x14,
841 0x13,
842 0x3,
843 0x1A,
844 0x1D,
845 0x1D,
846 0x21,
847 0x24,
848 0x26
849};
850
851/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800852static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700853 {100, 0x0},
854 {200, 0x1},
855 {500, 0x2},
856 {600, 0x3},
857 {700, 0x4},
858 {800, 0x5},
859 {850, 0x6},
860 {900, 0x8},
861 {950, 0x7},
862 {1000, 0x9},
863 {1100, 0xA},
864 {1200, 0xB},
865 {1300, 0xC},
866 {1400, 0xD},
867 {1500, 0xE},
868 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800869};
870
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700871#define REG_SBI_CONFIG 0x04F
872#define PAGE3_ENABLE_MASK 0x6
873#define USB_OVP_TRIM_MASK 0x3F
874#define USB_OVP_TRIM_PM8917_MASK 0x7F
875#define USB_OVP_TRIM_MIN 0x00
876#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
877#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
878#define REG_USB_OVP_TRIM_PM8917 0x2B5
879#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
880static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
881{
882 u8 temp, sbi_config, msb, lsb, mask;
883 s8 trim;
884 int rc = 0;
885 static u8 usb_trim_reg_orig = 0xFF;
886
887 /* No trim data for PM8921 */
888 if (!chip->usb_trim_table)
889 return 0;
890
891 if (usb_trim_reg_orig == 0xFF) {
892 rc = pm8xxx_readb(chip->dev->parent,
893 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
894 if (rc) {
895 pr_err("error = %d reading sbi config reg\n", rc);
896 return rc;
897 }
898
899 rc = pm8xxx_readb(chip->dev->parent,
900 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
901 if (rc) {
902 pr_err("error = %d reading sbi config reg\n", rc);
903 return rc;
904 }
905
906 msb = msb >> 5;
907 lsb = lsb >> 5;
908 usb_trim_reg_orig = msb << 3 | lsb;
909
910 if (pm8xxx_get_version(chip->dev->parent)
911 == PM8XXX_VERSION_8917) {
912 rc = pm8xxx_readb(chip->dev->parent,
913 REG_USB_OVP_TRIM_PM8917, &msb);
914 if (rc) {
915 pr_err("error = %d reading config reg\n", rc);
916 return rc;
917 }
918
919 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
920 usb_trim_reg_orig |= msb << 6;
921 }
922 }
923
924 /* use the original trim value */
925 trim = usb_trim_reg_orig;
926
927 trim += chip->usb_trim_table[index];
928 if (trim < 0)
929 trim = 0;
930
931 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
932 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
933
934 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
935 if (rc) {
936 pr_err("error = %d reading sbi config reg\n", rc);
937 return rc;
938 }
939
940 temp = sbi_config | PAGE3_ENABLE_MASK;
941 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
942 if (rc) {
943 pr_err("error = %d writing sbi config reg\n", rc);
944 return rc;
945 }
946
947 mask = USB_OVP_TRIM_MASK;
948
949 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
950 mask = USB_OVP_TRIM_PM8917_MASK;
951
952 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
953 if (rc) {
954 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
955 return rc;
956 }
957
958 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
959 if (rc) {
960 pr_err("error = %d writing sbi config reg\n", rc);
961 return rc;
962 }
963 return rc;
964}
965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700967#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968#define PM8921_CHG_IUSB_MAX 7
969#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700970#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700971static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700973 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700974 int rc;
975
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700976 reg_val = usb_ma_table[index].value >> 1;
977 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700979 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
980 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700981 return -EINVAL;
982 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700983 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
984
985 /* IUSB_FINE_RES */
986 if (chip->iusb_fine_res) {
987 /* Clear IUSB_FINE_RES bit to avoid overshoot */
988 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
989 PM8917_IUSB_FINE_RES, 0);
990
991 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
992 PM8921_CHG_IUSB_MASK, temp);
993
994 if (rc) {
995 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
996 return rc;
997 }
998
999 if (fineres) {
1000 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1001 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001002 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001003 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
1004 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001005 return rc;
1006 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001007 }
1008 } else {
1009 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
1010 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001011 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001012 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001013 return rc;
1014 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001015 }
1016
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001017 rc = pm_chg_usb_trim(chip, index);
1018 if (rc)
1019 pr_err("unable to set usb trim rc = %d\n", rc);
1020
David Keitel38bdd4f2012-04-19 15:39:13 -07001021 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022}
1023
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001024static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
1025{
David Keitel38bdd4f2012-04-19 15:39:13 -07001026 u8 temp, fineres;
1027 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001028
David Keitel38bdd4f2012-04-19 15:39:13 -07001029 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001030 *mA = 0;
1031 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
1032 if (rc) {
1033 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1034 return rc;
1035 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001036
1037 if (chip->iusb_fine_res) {
1038 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1039 if (rc) {
1040 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1041 return rc;
1042 }
1043 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001044 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001045 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1046
1047 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1048 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1049 if (usb_ma_table[i].value == temp)
1050 break;
1051 }
1052
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001053 if (i < 0) {
1054 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1055 i = 0;
1056 }
1057
David Keitel38bdd4f2012-04-19 15:39:13 -07001058 *mA = usb_ma_table[i].usb_ma;
1059
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001060 return rc;
1061}
1062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063#define PM8921_CHG_WD_MASK 0x1F
1064static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1065{
1066 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001067 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1068}
1069
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001070#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001071#define PM8921_CHG_TCHG_MIN 4
1072#define PM8921_CHG_TCHG_MAX 512
1073#define PM8921_CHG_TCHG_STEP 4
1074static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1075{
1076 u8 temp;
1077
1078 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1079 pr_err("bad max minutes =%d asked to set\n", minutes);
1080 return -EINVAL;
1081 }
1082
1083 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1084 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1085 temp);
1086}
1087
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001088#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001089#define PM8921_CHG_TTRKL_MIN 1
1090#define PM8921_CHG_TTRKL_MAX 64
1091static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1092{
1093 u8 temp;
1094
1095 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1096 pr_err("bad max minutes =%d asked to set\n", minutes);
1097 return -EINVAL;
1098 }
1099
1100 temp = minutes - 1;
1101 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1102 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103}
1104
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001105#define PM8921_CHG_VTRKL_MIN_MV 2050
1106#define PM8921_CHG_VTRKL_MAX_MV 2800
1107#define PM8921_CHG_VTRKL_STEP_MV 50
1108#define PM8921_CHG_VTRKL_SHIFT 4
1109#define PM8921_CHG_VTRKL_MASK 0xF0
1110static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1111{
1112 u8 temp;
1113
1114 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1115 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1116 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1117 return -EINVAL;
1118 }
1119
1120 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1121 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1122 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1123 temp);
1124}
1125
1126#define PM8921_CHG_VWEAK_MIN_MV 2100
1127#define PM8921_CHG_VWEAK_MAX_MV 3600
1128#define PM8921_CHG_VWEAK_STEP_MV 100
1129#define PM8921_CHG_VWEAK_MASK 0x0F
1130static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1131{
1132 u8 temp;
1133
1134 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1135 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1136 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1137 return -EINVAL;
1138 }
1139
1140 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1141 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1142 temp);
1143}
1144
1145#define PM8921_CHG_ITRKL_MIN_MA 50
1146#define PM8921_CHG_ITRKL_MAX_MA 200
1147#define PM8921_CHG_ITRKL_MASK 0x0F
1148#define PM8921_CHG_ITRKL_STEP_MA 10
1149static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1150{
1151 u8 temp;
1152
1153 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1154 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1155 pr_err("bad current = %dmA asked to set\n", milliamps);
1156 return -EINVAL;
1157 }
1158
1159 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1160
1161 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1162 temp);
1163}
1164
1165#define PM8921_CHG_IWEAK_MIN_MA 325
1166#define PM8921_CHG_IWEAK_MAX_MA 525
1167#define PM8921_CHG_IWEAK_SHIFT 7
1168#define PM8921_CHG_IWEAK_MASK 0x80
1169static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1170{
1171 u8 temp;
1172
1173 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1174 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1175 pr_err("bad current = %dmA asked to set\n", milliamps);
1176 return -EINVAL;
1177 }
1178
1179 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1180 temp = 0;
1181 else
1182 temp = 1;
1183
1184 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1185 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1186 temp);
1187}
1188
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001189#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1190#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1191static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1192 enum pm8921_chg_cold_thr cold_thr)
1193{
1194 u8 temp;
1195
1196 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1197 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1198 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1199 PM8921_CHG_BATT_TEMP_THR_COLD,
1200 temp);
1201}
1202
1203#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1204#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1205static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1206 enum pm8921_chg_hot_thr hot_thr)
1207{
1208 u8 temp;
1209
1210 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1211 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1212 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1213 PM8921_CHG_BATT_TEMP_THR_HOT,
1214 temp);
1215}
1216
Jay Chokshid674a512012-03-15 14:06:04 -07001217#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1218#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1219static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1220 enum pm8921_chg_led_src_config led_src_config)
1221{
1222 u8 temp;
1223
1224 if (led_src_config < LED_SRC_GND ||
1225 led_src_config > LED_SRC_BYPASS)
1226 return -EINVAL;
1227
1228 if (led_src_config == LED_SRC_BYPASS)
1229 return 0;
1230
1231 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1232
1233 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1234 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1235}
1236
David Keitel8c5201a2012-02-24 16:08:54 -08001237
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001238static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1239{
1240 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001241 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001242
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001243 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001244 if (rc) {
1245 pr_err("error reading batt id channel = %d, rc = %d\n",
1246 chip->vbat_channel, rc);
1247 return rc;
1248 }
1249 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1250 result.measurement);
1251 return result.physical;
1252}
1253
1254static int is_battery_valid(struct pm8921_chg_chip *chip)
1255{
1256 int64_t rc;
1257
1258 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1259 return 1;
1260
1261 rc = read_battery_id(chip);
1262 if (rc < 0) {
1263 pr_err("error reading batt id channel = %d, rc = %lld\n",
1264 chip->vbat_channel, rc);
1265 /* assume battery id is valid when adc error happens */
1266 return 1;
1267 }
1268
1269 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1270 pr_err("batt_id phy =%lld is not valid\n", rc);
1271 return 0;
1272 }
1273 return 1;
1274}
1275
1276static void check_battery_valid(struct pm8921_chg_chip *chip)
1277{
1278 if (is_battery_valid(chip) == 0) {
1279 pr_err("batt_id not valid, disbling charging\n");
1280 pm_chg_auto_enable(chip, 0);
1281 } else {
1282 pm_chg_auto_enable(chip, !charging_disabled);
1283 }
1284}
1285
1286static void battery_id_valid(struct work_struct *work)
1287{
1288 struct pm8921_chg_chip *chip = container_of(work,
1289 struct pm8921_chg_chip, battery_id_valid_work);
1290
1291 check_battery_valid(chip);
1292}
1293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001294static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1295{
1296 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1297 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1298 enable_irq(chip->pmic_chg_irq[interrupt]);
1299 }
1300}
1301
1302static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1303{
1304 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1305 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1306 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1307 }
1308}
1309
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001310static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1311{
1312 return test_bit(interrupt, chip->enabled_irqs);
1313}
1314
Amir Samuelovd31ef502011-10-26 14:41:36 +02001315static bool is_ext_charging(struct pm8921_chg_chip *chip)
1316{
David Keitel88e1b572012-01-11 11:57:14 -08001317 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001318
David Keitel88e1b572012-01-11 11:57:14 -08001319 if (!chip->ext_psy)
1320 return false;
1321 if (chip->ext_psy->get_property(chip->ext_psy,
1322 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1323 return false;
1324 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1325 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001326
1327 return false;
1328}
1329
1330static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1331{
David Keitel88e1b572012-01-11 11:57:14 -08001332 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001333
David Keitel88e1b572012-01-11 11:57:14 -08001334 if (!chip->ext_psy)
1335 return false;
1336 if (chip->ext_psy->get_property(chip->ext_psy,
1337 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1338 return false;
1339 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001340 return true;
1341
1342 return false;
1343}
1344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345static int is_battery_charging(int fsm_state)
1346{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001347 if (is_ext_charging(the_chip))
1348 return 1;
1349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350 switch (fsm_state) {
1351 case FSM_STATE_ATC_2A:
1352 case FSM_STATE_ATC_2B:
1353 case FSM_STATE_ON_CHG_AND_BAT_6:
1354 case FSM_STATE_FAST_CHG_7:
1355 case FSM_STATE_TRKL_CHG_8:
1356 return 1;
1357 }
1358 return 0;
1359}
1360
1361static void bms_notify(struct work_struct *work)
1362{
1363 struct bms_notify *n = container_of(work, struct bms_notify, work);
1364
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001365 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001367 } else {
1368 pm8921_bms_charging_end(n->is_battery_full);
1369 n->is_battery_full = 0;
1370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371}
1372
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001373static void bms_notify_check(struct pm8921_chg_chip *chip)
1374{
1375 int fsm_state, new_is_charging;
1376
1377 fsm_state = pm_chg_get_fsm_state(chip);
1378 new_is_charging = is_battery_charging(fsm_state);
1379
1380 if (chip->bms_notify.is_charging ^ new_is_charging) {
1381 chip->bms_notify.is_charging = new_is_charging;
1382 schedule_work(&(chip->bms_notify.work));
1383 }
1384}
1385
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001386static enum power_supply_property pm_power_props_usb[] = {
1387 POWER_SUPPLY_PROP_PRESENT,
1388 POWER_SUPPLY_PROP_ONLINE,
1389 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001390 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001391};
1392
1393static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001395 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396};
1397
1398static char *pm_power_supplied_to[] = {
1399 "battery",
1400};
1401
David Keitel6ed71a52012-01-30 12:42:18 -08001402#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001403static int pm_power_get_property_mains(struct power_supply *psy,
1404 enum power_supply_property psp,
1405 union power_supply_propval *val)
1406{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001407 int type;
1408
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001409 /* Check if called before init */
1410 if (!the_chip)
1411 return -EINVAL;
1412
1413 switch (psp) {
1414 case POWER_SUPPLY_PROP_PRESENT:
1415 case POWER_SUPPLY_PROP_ONLINE:
1416 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001417
1418 if (the_chip->has_dc_supply) {
1419 val->intval = 1;
1420 return 0;
1421 }
1422
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001423 if (the_chip->dc_present) {
1424 val->intval = 1;
1425 return 0;
1426 }
1427
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001428 type = the_chip->usb_psy.type;
1429 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1430 type == POWER_SUPPLY_TYPE_USB_ACA ||
1431 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001432 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001433
1434 break;
1435 default:
1436 return -EINVAL;
1437 }
1438 return 0;
1439}
1440
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001441static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1442{
1443 int rc;
1444
1445 if (!chip->host_mode)
1446 return 0;
1447
1448 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001449 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001450 if (rc < 0) {
1451 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1452 return rc;
1453 }
1454
1455 chip->host_mode = 0;
1456
1457 return 0;
1458}
1459
1460static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1461{
1462 int rc;
1463
1464 if (chip->host_mode)
1465 return 0;
1466
1467 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001468 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001469 if (rc < 0) {
1470 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1471 return rc;
1472 }
1473
1474 chip->host_mode = 1;
1475
1476 return 0;
1477}
1478
1479static int pm_power_set_property_usb(struct power_supply *psy,
1480 enum power_supply_property psp,
1481 const union power_supply_propval *val)
1482{
1483 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001484 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001485 return -EINVAL;
1486
1487 switch (psp) {
1488 case POWER_SUPPLY_PROP_SCOPE:
1489 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001490 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001491 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001492 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001493 else
1494 return -EINVAL;
1495 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001496 case POWER_SUPPLY_PROP_TYPE:
1497 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001498 default:
1499 return -EINVAL;
1500 }
1501 return 0;
1502}
1503
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001504static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 enum power_supply_property psp,
1506 union power_supply_propval *val)
1507{
David Keitel6ed71a52012-01-30 12:42:18 -08001508 int current_max;
1509
1510 /* Check if called before init */
1511 if (!the_chip)
1512 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513
1514 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001515 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001516 if (pm_is_chg_charge_dis(the_chip)) {
1517 val->intval = 0;
1518 } else {
1519 pm_chg_iusbmax_get(the_chip, &current_max);
1520 val->intval = current_max;
1521 }
David Keitel6ed71a52012-01-30 12:42:18 -08001522 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001524 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001525 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001526
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001527 if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001528 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001531
1532 case POWER_SUPPLY_PROP_SCOPE:
1533 if (the_chip->host_mode)
1534 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1535 else
1536 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1537 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538 default:
1539 return -EINVAL;
1540 }
1541 return 0;
1542}
1543
1544static enum power_supply_property msm_batt_power_props[] = {
1545 POWER_SUPPLY_PROP_STATUS,
1546 POWER_SUPPLY_PROP_CHARGE_TYPE,
1547 POWER_SUPPLY_PROP_HEALTH,
1548 POWER_SUPPLY_PROP_PRESENT,
1549 POWER_SUPPLY_PROP_TECHNOLOGY,
1550 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1551 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1552 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1553 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001554 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001555 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001556 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001557 POWER_SUPPLY_PROP_CHARGE_FULL,
1558 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559};
1560
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001561static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562{
1563 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001564 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001566 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 if (rc) {
1568 pr_err("error reading adc channel = %d, rc = %d\n",
1569 chip->vbat_channel, rc);
1570 return rc;
1571 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001572 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 result.measurement);
1574 return (int)result.physical;
1575}
1576
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001577static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1578{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001579 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1580 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1581 unsigned int low_voltage = chip->min_voltage_mv;
1582 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001583
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001584 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001585 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001586 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001587 return 100;
1588 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001589 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001590 / (high_voltage - low_voltage);
1591}
1592
David Keitel4f9397b2012-04-16 11:46:16 -07001593static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1594{
1595 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1596}
1597
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001598static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1599{
1600 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1601 int fsm_state = pm_chg_get_fsm_state(chip);
1602 int i;
1603
1604 if (chip->ext_psy) {
1605 if (chip->ext_charge_done)
1606 return POWER_SUPPLY_STATUS_FULL;
1607 if (chip->ext_charging)
1608 return POWER_SUPPLY_STATUS_CHARGING;
1609 }
1610
1611 for (i = 0; i < ARRAY_SIZE(map); i++)
1612 if (map[i].fsm_state == fsm_state)
1613 batt_state = map[i].batt_state;
1614
1615 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1616 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1617 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1618 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1619 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1620
1621 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1622 }
1623 return batt_state;
1624}
1625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1627{
David Keitel4f9397b2012-04-16 11:46:16 -07001628 int percent_soc;
1629
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001630 if (chip->battery_less_hardware)
1631 return 100;
1632
David Keitel4f9397b2012-04-16 11:46:16 -07001633 if (!get_prop_batt_present(chip))
1634 percent_soc = voltage_based_capacity(chip);
1635 else
1636 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001637
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001638 if (percent_soc == -ENXIO)
1639 percent_soc = voltage_based_capacity(chip);
1640
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001641 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001642 pr_warn_ratelimited("low battery charge = %d%%\n",
1643 percent_soc);
1644
1645 if (percent_soc <= chip->resume_charge_percent
1646 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1647 pr_debug("soc fell below %d. charging enabled.\n",
1648 chip->resume_charge_percent);
1649 if (chip->is_bat_warm)
1650 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1651 chip->is_bat_warm,
1652 chip->resume_charge_percent);
1653 else if (chip->is_bat_cool)
1654 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1655 chip->is_bat_cool,
1656 chip->resume_charge_percent);
1657 else
1658 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1659 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001660
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001661 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001662 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663}
1664
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001665static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1666{
1667 return pm8921_bms_get_current_max();
1668}
1669
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001670static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1671{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001672 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001673
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001674 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001675 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001676 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001677 }
1678
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001679 if (rc) {
1680 pr_err("unable to get batt current rc = %d\n", rc);
1681 return rc;
1682 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001683 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001684 }
1685}
1686
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001687static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1688{
1689 int rc;
1690
1691 rc = pm8921_bms_get_fcc();
1692 if (rc < 0)
1693 pr_err("unable to get batt fcc rc = %d\n", rc);
1694 return rc;
1695}
1696
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001697static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1698{
1699 int rc;
1700 int cc_uah;
1701
1702 rc = pm8921_bms_cc_uah(&cc_uah);
1703
1704 if (rc == 0)
1705 return cc_uah;
1706
1707 pr_err("unable to get batt fcc rc = %d\n", rc);
1708 return rc;
1709}
1710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1712{
1713 int temp;
1714
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001715 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1716 if (temp)
1717 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001719 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1720 if (temp)
1721 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001723 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724}
1725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001726static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1727{
1728 int temp;
1729
Amir Samuelovd31ef502011-10-26 14:41:36 +02001730 if (!get_prop_batt_present(chip))
1731 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1732
1733 if (is_ext_trickle_charging(chip))
1734 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1735
1736 if (is_ext_charging(chip))
1737 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1740 if (temp)
1741 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1742
1743 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1744 if (temp)
1745 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1746
1747 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1748}
1749
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001750#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001751static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1752{
1753 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001754 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001755
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001756 if (chip->battery_less_hardware)
1757 return 300;
1758
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001759 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001760 if (rc) {
1761 pr_err("error reading adc channel = %d, rc = %d\n",
1762 chip->vbat_channel, rc);
1763 return rc;
1764 }
1765 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1766 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001767 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1768 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1769 (int) result.physical);
1770
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001771 return (int)result.physical;
1772}
1773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774static int pm_batt_power_get_property(struct power_supply *psy,
1775 enum power_supply_property psp,
1776 union power_supply_propval *val)
1777{
1778 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1779 batt_psy);
1780
1781 switch (psp) {
1782 case POWER_SUPPLY_PROP_STATUS:
1783 val->intval = get_prop_batt_status(chip);
1784 break;
1785 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1786 val->intval = get_prop_charge_type(chip);
1787 break;
1788 case POWER_SUPPLY_PROP_HEALTH:
1789 val->intval = get_prop_batt_health(chip);
1790 break;
1791 case POWER_SUPPLY_PROP_PRESENT:
1792 val->intval = get_prop_batt_present(chip);
1793 break;
1794 case POWER_SUPPLY_PROP_TECHNOLOGY:
1795 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1796 break;
1797 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001798 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 break;
1800 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001801 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 break;
1803 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001804 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 break;
1806 case POWER_SUPPLY_PROP_CAPACITY:
1807 val->intval = get_prop_batt_capacity(chip);
1808 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001809 case POWER_SUPPLY_PROP_CURRENT_NOW:
1810 val->intval = get_prop_batt_current(chip);
1811 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001812 case POWER_SUPPLY_PROP_CURRENT_MAX:
1813 val->intval = get_prop_batt_current_max(chip);
1814 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001815 case POWER_SUPPLY_PROP_TEMP:
1816 val->intval = get_prop_batt_temp(chip);
1817 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001818 case POWER_SUPPLY_PROP_CHARGE_FULL:
1819 val->intval = get_prop_batt_fcc(chip);
1820 break;
1821 case POWER_SUPPLY_PROP_CHARGE_NOW:
1822 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001823 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 default:
1825 return -EINVAL;
1826 }
1827
1828 return 0;
1829}
1830
1831static void (*notify_vbus_state_func_ptr)(int);
1832static int usb_chg_current;
1833static DEFINE_SPINLOCK(vbus_lock);
1834
1835int pm8921_charger_register_vbus_sn(void (*callback)(int))
1836{
1837 pr_debug("%p\n", callback);
1838 notify_vbus_state_func_ptr = callback;
1839 return 0;
1840}
1841EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1842
1843/* this is passed to the hsusb via platform_data msm_otg_pdata */
1844void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1845{
1846 pr_debug("%p\n", callback);
1847 notify_vbus_state_func_ptr = NULL;
1848}
1849EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1850
1851static void notify_usb_of_the_plugin_event(int plugin)
1852{
1853 plugin = !!plugin;
1854 if (notify_vbus_state_func_ptr) {
1855 pr_debug("notifying plugin\n");
1856 (*notify_vbus_state_func_ptr) (plugin);
1857 } else {
1858 pr_debug("unable to notify plugin\n");
1859 }
1860}
1861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862/* assumes vbus_lock is held */
1863static void __pm8921_charger_vbus_draw(unsigned int mA)
1864{
1865 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001866 if (!the_chip) {
1867 pr_err("called before init\n");
1868 return;
1869 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001871 if (usb_max_current && mA > usb_max_current) {
1872 pr_debug("restricting usb current to %d instead of %d\n",
1873 usb_max_current, mA);
1874 mA = usb_max_current;
1875 }
1876
1877 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001879 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001881 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 }
1883 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1884 if (rc)
1885 pr_err("fail to set suspend bit rc=%d\n", rc);
1886 } else {
1887 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1888 if (rc)
1889 pr_err("fail to reset suspend bit rc=%d\n", rc);
1890 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1891 if (usb_ma_table[i].usb_ma <= mA)
1892 break;
1893 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001894
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001895 if (i < 0) {
1896 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1897 mA);
1898 i = 0;
1899 }
1900
David Keitel38bdd4f2012-04-19 15:39:13 -07001901 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001902 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001903 && !the_chip->iusb_fine_res)
1904 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 if (i < 0)
1906 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001907 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001908 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001909 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 }
1911}
1912
1913/* USB calls these to tell us how much max usb current the system can draw */
1914void pm8921_charger_vbus_draw(unsigned int mA)
1915{
1916 unsigned long flags;
1917
1918 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001919
David Keitel62c6a4b2012-05-17 12:54:59 -07001920 if (!the_chip) {
1921 pr_err("chip not yet initalized\n");
1922 return;
1923 }
1924
1925 /*
1926 * Reject VBUS requests if USB connection is the only available
1927 * power source. This makes sure that if booting without
1928 * battery the iusb_max value is not decreased avoiding potential
1929 * brown_outs.
1930 *
1931 * This would also apply when the battery has been
1932 * removed from the running system.
1933 */
1934 if (!get_prop_batt_present(the_chip)
1935 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001936 if (!the_chip->has_dc_supply) {
1937 pr_err("rejected: no other power source connected\n");
1938 return;
1939 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001940 }
1941
David Keitelacf57c82012-03-07 18:48:50 -08001942 if (usb_max_current && mA > usb_max_current) {
1943 pr_warn("restricting usb current to %d instead of %d\n",
1944 usb_max_current, mA);
1945 mA = usb_max_current;
1946 }
Devin Kim2073afb2012-09-05 13:01:51 -07001947 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1948 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 spin_lock_irqsave(&vbus_lock, flags);
1951 if (the_chip) {
David Keitelacf57c82012-03-07 18:48:50 -08001952 if (mA > USB_WALL_THRESHOLD_MA)
1953 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
1954 else
1955 __pm8921_charger_vbus_draw(mA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 } else {
1957 /*
1958 * called before pmic initialized,
1959 * save this value and use it at probe
1960 */
David Keitelacf57c82012-03-07 18:48:50 -08001961 if (mA > USB_WALL_THRESHOLD_MA)
1962 usb_chg_current = USB_WALL_THRESHOLD_MA;
1963 else
1964 usb_chg_current = mA;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 }
1966 spin_unlock_irqrestore(&vbus_lock, flags);
1967}
1968EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1969
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001970int pm8921_is_usb_chg_plugged_in(void)
1971{
1972 if (!the_chip) {
1973 pr_err("called before init\n");
1974 return -EINVAL;
1975 }
1976 return is_usb_chg_plugged_in(the_chip);
1977}
1978EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1979
1980int pm8921_is_dc_chg_plugged_in(void)
1981{
1982 if (!the_chip) {
1983 pr_err("called before init\n");
1984 return -EINVAL;
1985 }
1986 return is_dc_chg_plugged_in(the_chip);
1987}
1988EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1989
1990int pm8921_is_battery_present(void)
1991{
1992 if (!the_chip) {
1993 pr_err("called before init\n");
1994 return -EINVAL;
1995 }
1996 return get_prop_batt_present(the_chip);
1997}
1998EXPORT_SYMBOL(pm8921_is_battery_present);
1999
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002000int pm8921_is_batfet_closed(void)
2001{
2002 if (!the_chip) {
2003 pr_err("called before init\n");
2004 return -EINVAL;
2005 }
2006 return is_batfet_closed(the_chip);
2007}
2008EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002009/*
2010 * Disabling the charge current limit causes current
2011 * current limits to have no monitoring. An adequate charger
2012 * capable of supplying high current while sustaining VIN_MIN
2013 * is required if the limiting is disabled.
2014 */
2015int pm8921_disable_input_current_limit(bool disable)
2016{
2017 if (!the_chip) {
2018 pr_err("called before init\n");
2019 return -EINVAL;
2020 }
2021 if (disable) {
2022 pr_warn("Disabling input current limit!\n");
2023
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002024 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002025 }
2026 return 0;
2027}
2028EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2029
David Keitel0789fc62012-06-07 17:43:27 -07002030int pm8917_set_under_voltage_detection_threshold(int mv)
2031{
2032 if (!the_chip) {
2033 pr_err("called before init\n");
2034 return -EINVAL;
2035 }
2036 return pm_chg_uvd_threshold_set(the_chip, mv);
2037}
2038EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2039
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002040int pm8921_set_max_battery_charge_current(int ma)
2041{
2042 if (!the_chip) {
2043 pr_err("called before init\n");
2044 return -EINVAL;
2045 }
2046 return pm_chg_ibatmax_set(the_chip, ma);
2047}
2048EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2049
2050int pm8921_disable_source_current(bool disable)
2051{
2052 if (!the_chip) {
2053 pr_err("called before init\n");
2054 return -EINVAL;
2055 }
2056 if (disable)
2057 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002058
2059 pm_chg_usb_suspend_enable(the_chip, disable);
2060
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002061 return pm_chg_charge_dis(the_chip, disable);
2062}
2063EXPORT_SYMBOL(pm8921_disable_source_current);
2064
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002065int pm8921_regulate_input_voltage(int voltage)
2066{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002067 int rc;
2068
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002069 if (!the_chip) {
2070 pr_err("called before init\n");
2071 return -EINVAL;
2072 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002073 rc = pm_chg_vinmin_set(the_chip, voltage);
2074
2075 if (rc == 0)
2076 the_chip->vin_min = voltage;
2077
2078 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002079}
2080
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002081#define USB_OV_THRESHOLD_MASK 0x60
2082#define USB_OV_THRESHOLD_SHIFT 5
2083int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2084{
2085 u8 temp;
2086
2087 if (!the_chip) {
2088 pr_err("called before init\n");
2089 return -EINVAL;
2090 }
2091
2092 if (ov > PM_USB_OV_7V) {
2093 pr_err("limiting to over voltage threshold to 7volts\n");
2094 ov = PM_USB_OV_7V;
2095 }
2096
2097 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2098
2099 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2100 USB_OV_THRESHOLD_MASK, temp);
2101}
2102EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2103
2104#define USB_DEBOUNCE_TIME_MASK 0x06
2105#define USB_DEBOUNCE_TIME_SHIFT 1
2106int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2107{
2108 u8 temp;
2109
2110 if (!the_chip) {
2111 pr_err("called before init\n");
2112 return -EINVAL;
2113 }
2114
2115 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2116 pr_err("limiting debounce to 80.5ms\n");
2117 ms = PM_USB_DEBOUNCE_80P5MS;
2118 }
2119
2120 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2121
2122 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2123 USB_DEBOUNCE_TIME_MASK, temp);
2124}
2125EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2126
2127#define USB_OVP_DISABLE_MASK 0x80
2128int pm8921_usb_ovp_disable(int disable)
2129{
2130 u8 temp = 0;
2131
2132 if (!the_chip) {
2133 pr_err("called before init\n");
2134 return -EINVAL;
2135 }
2136
2137 if (disable)
2138 temp = USB_OVP_DISABLE_MASK;
2139
2140 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2141 USB_OVP_DISABLE_MASK, temp);
2142}
2143
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002144bool pm8921_is_battery_charging(int *source)
2145{
2146 int fsm_state, is_charging, dc_present, usb_present;
2147
2148 if (!the_chip) {
2149 pr_err("called before init\n");
2150 return -EINVAL;
2151 }
2152 fsm_state = pm_chg_get_fsm_state(the_chip);
2153 is_charging = is_battery_charging(fsm_state);
2154 if (is_charging == 0) {
2155 *source = PM8921_CHG_SRC_NONE;
2156 return is_charging;
2157 }
2158
2159 if (source == NULL)
2160 return is_charging;
2161
2162 /* the battery is charging, the source is requested, find it */
2163 dc_present = is_dc_chg_plugged_in(the_chip);
2164 usb_present = is_usb_chg_plugged_in(the_chip);
2165
2166 if (dc_present && !usb_present)
2167 *source = PM8921_CHG_SRC_DC;
2168
2169 if (usb_present && !dc_present)
2170 *source = PM8921_CHG_SRC_USB;
2171
2172 if (usb_present && dc_present)
2173 /*
2174 * The system always chooses dc for charging since it has
2175 * higher priority.
2176 */
2177 *source = PM8921_CHG_SRC_DC;
2178
2179 return is_charging;
2180}
2181EXPORT_SYMBOL(pm8921_is_battery_charging);
2182
David Keitel86034022012-04-18 12:33:58 -07002183int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2184{
2185 if (!the_chip) {
2186 pr_err("called before init\n");
2187 return -EINVAL;
2188 }
2189
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002190 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002191 return -EINVAL;
2192
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002193 the_chip->usb_psy.type = type;
David Keitel86034022012-04-18 12:33:58 -07002194 power_supply_changed(&the_chip->usb_psy);
2195 power_supply_changed(&the_chip->dc_psy);
2196 return 0;
2197}
2198EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2199
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002200int pm8921_batt_temperature(void)
2201{
2202 if (!the_chip) {
2203 pr_err("called before init\n");
2204 return -EINVAL;
2205 }
2206 return get_prop_batt_temp(the_chip);
2207}
2208
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002209static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002210{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002211 int err;
2212 u8 temp;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002213
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002214
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002215 temp = 0xD1;
2216 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2217 if (err) {
2218 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002219 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002220 }
2221
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002222 temp = 0xD3;
2223 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2224 if (err) {
2225 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002226 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002227 }
2228
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002229 temp = 0xD1;
2230 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2231 if (err) {
2232 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002233 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002234 }
2235
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002236 temp = 0xD5;
2237 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2238 if (err) {
2239 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002240 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002241 }
2242
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002243 /* Wait a few clock cycles before re-enabling hw clock switching */
2244 udelay(183);
2245
2246 temp = 0xD1;
2247 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2248 if (err) {
2249 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002250 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002251 }
2252
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002253 temp = 0xD0;
2254 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2255 if (err) {
2256 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002257 return err;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002258 }
2259
2260 /* Wait for few clock cycles before re-enabling LPM */
2261 udelay(32);
2262
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002263 return 0;
2264}
2265
2266static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
2267{
2268 int err;
2269 unsigned long flags = 0;
2270
2271 spin_lock_irqsave(&lpm_lock, flags);
2272 err = pm8921_chg_set_lpm(chip, 0);
2273 if (err) {
2274 pr_err("Error settig LPM rc=%d\n", err);
2275 goto kick_err;
2276 }
2277
2278 __pm8921_apply_19p2mhz_kickstart(chip);
2279
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002280kick_err:
2281 err = pm8921_chg_set_lpm(chip, 1);
2282 if (err)
2283 pr_err("Error settig LPM rc=%d\n", err);
2284
2285 spin_unlock_irqrestore(&lpm_lock, flags);
2286
2287 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002288}
2289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002290static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2291{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002292 int usb_present, rc = 0;
2293
2294 if (chip->lockup_lpm_wrkarnd) {
2295 rc = pm8921_apply_19p2mhz_kickstart(chip);
2296 if (rc)
2297 pr_err("Failed to apply kickstart rc=%d\n", rc);
2298 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002300 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301 usb_present = is_usb_chg_plugged_in(chip);
2302 if (chip->usb_present ^ usb_present) {
2303 notify_usb_of_the_plugin_event(usb_present);
2304 chip->usb_present = usb_present;
2305 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002306 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002307 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002308
2309 /* Enable/disable bypass if charger is on battery */
2310 if (chip->lockup_lpm_wrkarnd)
2311 pm8921_chg_bypass_bat_gone_debounce(chip,
2312 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002314 if (usb_present) {
2315 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002316 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002317 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2318 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002319 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002320 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002321 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002322 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002323 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324}
2325
Amir Samuelovd31ef502011-10-26 14:41:36 +02002326static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2327{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002328 if (chip->lockup_lpm_wrkarnd)
2329 /* Enable bypass if charger is on battery */
2330 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2331
David Keitel88e1b572012-01-11 11:57:14 -08002332 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002333 pr_debug("external charger not registered.\n");
2334 return;
2335 }
2336
2337 if (!chip->ext_charging) {
2338 pr_debug("already not charging.\n");
2339 return;
2340 }
2341
David Keitel88e1b572012-01-11 11:57:14 -08002342 power_supply_set_charge_type(chip->ext_psy,
2343 POWER_SUPPLY_CHARGE_TYPE_NONE);
2344 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002345 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002346 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002347 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002348 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002349 /* Update battery charging LEDs and user space battery info */
2350 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002351}
2352
2353static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2354{
2355 int dc_present;
2356 int batt_present;
2357 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002358 unsigned long delay =
2359 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2360
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002361 /* Disable bypass if charger connected and not running on bat */
2362 if (chip->lockup_lpm_wrkarnd)
2363 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2364
David Keitel88e1b572012-01-11 11:57:14 -08002365 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002366 pr_debug("external charger not registered.\n");
2367 return;
2368 }
2369
2370 if (chip->ext_charging) {
2371 pr_debug("already charging.\n");
2372 return;
2373 }
2374
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002375 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002376 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2377 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002378
2379 if (!dc_present) {
2380 pr_warn("%s. dc not present.\n", __func__);
2381 return;
2382 }
2383 if (!batt_present) {
2384 pr_warn("%s. battery not present.\n", __func__);
2385 return;
2386 }
2387 if (!batt_temp_ok) {
2388 pr_warn("%s. battery temperature not ok.\n", __func__);
2389 return;
2390 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002391
2392 /* Force BATFET=ON */
2393 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002394
David Keitel6ccbf132012-05-30 14:21:24 -07002395 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002396 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002397
David Keitel63f71662012-02-08 20:30:00 -08002398 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002399 power_supply_set_charge_type(chip->ext_psy,
2400 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002401 chip->ext_charging = true;
2402 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002403 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002404 /*
2405 * since we wont get a fastchg irq from external charger
2406 * use eoc worker to detect end of charging
2407 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002408 schedule_delayed_work(&chip->eoc_work, delay);
2409 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002410 if (chip->btc_override)
2411 schedule_delayed_work(&chip->btc_override_work,
2412 round_jiffies_relative(msecs_to_jiffies
2413 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002414 /* Update battery charging LEDs and user space battery info */
2415 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002416}
2417
David Keitel6ccbf132012-05-30 14:21:24 -07002418static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002419{
2420 u8 temp;
2421 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002422
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002423 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002424 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002425 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002426 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002427 }
David Keitel6ccbf132012-05-30 14:21:24 -07002428 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002429 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002430 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002431 return;
2432 }
2433 /* set ovp fet disable bit and the write bit */
2434 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002435 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002436 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002437 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002438 return;
2439 }
2440}
2441
David Keitel6ccbf132012-05-30 14:21:24 -07002442static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002443{
2444 u8 temp;
2445 int rc;
2446
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002447 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002448 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002449 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002450 return;
2451 }
David Keitel6ccbf132012-05-30 14:21:24 -07002452 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002453 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002454 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002455 return;
2456 }
2457 /* unset ovp fet disable bit and set the write bit */
2458 temp &= 0xFE;
2459 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002460 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002461 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002462 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002463 temp, rc);
2464 return;
2465 }
2466}
2467
2468static int param_open_ovp_counter = 10;
2469module_param(param_open_ovp_counter, int, 0644);
2470
David Keitel6ccbf132012-05-30 14:21:24 -07002471#define USB_ACTIVE_BIT BIT(5)
2472#define DC_ACTIVE_BIT BIT(6)
2473static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2474 u8 active_chg_mask)
2475{
2476 if (active_chg_mask & USB_ACTIVE_BIT)
2477 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2478 else if (active_chg_mask & DC_ACTIVE_BIT)
2479 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2480 else
2481 return 0;
2482}
2483
David Keitel8c5201a2012-02-24 16:08:54 -08002484#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002485#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002486static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002487{
David Keitel6ccbf132012-05-30 14:21:24 -07002488 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002489 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002490 u8 active_mask = 0;
2491 u16 ovpreg, ovptestreg;
2492
2493 if (is_usb_chg_plugged_in(chip) &&
2494 (chip->active_path & USB_ACTIVE_BIT)) {
2495 ovpreg = USB_OVP_CONTROL;
2496 ovptestreg = USB_OVP_TEST;
2497 active_mask = USB_ACTIVE_BIT;
2498 } else if (is_dc_chg_plugged_in(chip) &&
2499 (chip->active_path & DC_ACTIVE_BIT)) {
2500 ovpreg = DC_OVP_CONTROL;
2501 ovptestreg = DC_OVP_TEST;
2502 active_mask = DC_ACTIVE_BIT;
2503 } else {
2504 return;
2505 }
David Keitel8c5201a2012-02-24 16:08:54 -08002506
2507 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002508 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002509 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002510 active_chg_plugged_in
2511 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002512 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002513 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2514 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002515
2516 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002517 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002518 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002519 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002520
2521 msleep(20);
2522
David Keitel6ccbf132012-05-30 14:21:24 -07002523 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002524 } else {
David Keitel712782e2012-03-29 14:11:47 -07002525 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002526 }
2527 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002528 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2529 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2530 else
2531 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2532
David Keitel6ccbf132012-05-30 14:21:24 -07002533 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2534 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002535 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002536}
David Keitelacf57c82012-03-07 18:48:50 -08002537
2538static int find_usb_ma_value(int value)
2539{
2540 int i;
2541
2542 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2543 if (value >= usb_ma_table[i].usb_ma)
2544 break;
2545 }
2546
2547 return i;
2548}
2549
2550static void decrease_usb_ma_value(int *value)
2551{
2552 int i;
2553
2554 if (value) {
2555 i = find_usb_ma_value(*value);
2556 if (i > 0)
2557 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002558 while (!the_chip->iusb_fine_res && i > 0
2559 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2560 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002561
2562 if (i < 0) {
2563 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2564 *value);
2565 i = 0;
2566 }
2567
David Keitelacf57c82012-03-07 18:48:50 -08002568 *value = usb_ma_table[i].usb_ma;
2569 }
2570}
2571
2572static void increase_usb_ma_value(int *value)
2573{
2574 int i;
2575
2576 if (value) {
2577 i = find_usb_ma_value(*value);
2578
2579 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2580 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002581 /* Get next correct entry if IUSB_FINE_RES is not available */
2582 while (!the_chip->iusb_fine_res
2583 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2584 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2585 i++;
2586
David Keitelacf57c82012-03-07 18:48:50 -08002587 *value = usb_ma_table[i].usb_ma;
2588 }
2589}
2590
2591static void vin_collapse_check_worker(struct work_struct *work)
2592{
2593 struct delayed_work *dwork = to_delayed_work(work);
2594 struct pm8921_chg_chip *chip = container_of(dwork,
2595 struct pm8921_chg_chip, vin_collapse_check_work);
2596
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002597 /*
2598 * AICL only for wall-chargers. If the charger appears to be plugged
2599 * back in now, the corresponding unplug must have been because of we
2600 * were trying to draw more current than the charger can support. In
2601 * such a case reset usb current to 500mA and decrease the target.
2602 * The AICL algorithm will step up the current from 500mA to target
2603 */
2604 if (is_usb_chg_plugged_in(chip)
2605 && usb_target_ma > USB_WALL_THRESHOLD_MA) {
David Keitelacf57c82012-03-07 18:48:50 -08002606 /* decrease usb_target_ma */
2607 decrease_usb_ma_value(&usb_target_ma);
2608 /* reset here, increase in unplug_check_worker */
2609 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2610 pr_debug("usb_now=%d, usb_target = %d\n",
2611 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002612 if (!delayed_work_pending(&chip->unplug_check_work))
2613 schedule_delayed_work(&chip->unplug_check_work,
2614 msecs_to_jiffies
2615 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002616 } else {
2617 handle_usb_insertion_removal(chip);
2618 }
2619}
2620
2621#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2623{
David Keitelacf57c82012-03-07 18:48:50 -08002624 if (usb_target_ma)
2625 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2626 round_jiffies_relative(msecs_to_jiffies
2627 (VIN_MIN_COLLAPSE_CHECK_MS)));
2628 else
2629 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 return IRQ_HANDLED;
2631}
2632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002633static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2634{
2635 struct pm8921_chg_chip *chip = data;
2636 int status;
2637
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002638 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2639 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002640 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002641 pr_debug("battery present=%d", status);
2642 power_supply_changed(&chip->batt_psy);
2643 return IRQ_HANDLED;
2644}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002645
2646/*
2647 * this interrupt used to restart charging a battery.
2648 *
2649 * Note: When DC-inserted the VBAT can't go low.
2650 * VPH_PWR is provided by the ext-charger.
2651 * After End-Of-Charging from DC, charging can be resumed only
2652 * if DC is removed and then inserted after the battery was in use.
2653 * Therefore the handle_start_ext_chg() is not called.
2654 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002655static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2656{
2657 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002658 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002660 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002661
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002662 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002663 /* enable auto charging */
2664 pm_chg_auto_enable(chip, !charging_disabled);
2665 pr_info("batt fell below resume voltage %s\n",
2666 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670 power_supply_changed(&chip->batt_psy);
2671 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002672 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002673
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 return IRQ_HANDLED;
2675}
2676
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2678{
2679 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2680 return IRQ_HANDLED;
2681}
2682
2683static irqreturn_t vcp_irq_handler(int irq, void *data)
2684{
David Keitel8c5201a2012-02-24 16:08:54 -08002685 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 return IRQ_HANDLED;
2687}
2688
2689static irqreturn_t atcdone_irq_handler(int irq, void *data)
2690{
2691 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2692 return IRQ_HANDLED;
2693}
2694
2695static irqreturn_t atcfail_irq_handler(int irq, void *data)
2696{
2697 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2698 return IRQ_HANDLED;
2699}
2700
2701static irqreturn_t chgdone_irq_handler(int irq, void *data)
2702{
2703 struct pm8921_chg_chip *chip = data;
2704
2705 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002706
2707 handle_stop_ext_chg(chip);
2708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 power_supply_changed(&chip->batt_psy);
2710 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002711 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002712
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002713 bms_notify_check(chip);
2714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715 return IRQ_HANDLED;
2716}
2717
2718static irqreturn_t chgfail_irq_handler(int irq, void *data)
2719{
2720 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002721 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002723 if (!chip->stop_chg_upon_expiry) {
2724 ret = pm_chg_failed_clear(chip, 1);
2725 if (ret)
2726 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2727 }
David Keitel753ec8d2011-11-02 10:56:37 -07002728
2729 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2730 get_prop_batt_present(chip),
2731 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2732 pm_chg_get_fsm_state(data));
2733
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002734 power_supply_changed(&chip->batt_psy);
2735 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002736 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002737 return IRQ_HANDLED;
2738}
2739
2740static irqreturn_t chgstate_irq_handler(int irq, void *data)
2741{
2742 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002743
2744 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2745 power_supply_changed(&chip->batt_psy);
2746 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002747 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002749 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751 return IRQ_HANDLED;
2752}
2753
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002754enum {
2755 PON_TIME_25NS = 0x04,
2756 PON_TIME_50NS = 0x08,
2757 PON_TIME_100NS = 0x0C,
2758};
David Keitel8c5201a2012-02-24 16:08:54 -08002759
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002760static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002761{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002762 u8 temp;
2763 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002764
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002765 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2766 if (rc) {
2767 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2768 return;
2769 }
2770 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2771 if (rc) {
2772 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2773 return;
2774 }
2775 /* clear the min pon time select bit */
2776 temp &= 0xF3;
2777 /* set the pon time */
2778 temp |= (u8)pon_time_ns;
2779 /* write enable bank 4 */
2780 temp |= 0x80;
2781 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2782 if (rc) {
2783 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2784 return;
2785 }
2786}
David Keitel8c5201a2012-02-24 16:08:54 -08002787
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002788static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2789{
2790 pr_debug("Start\n");
2791 set_min_pon_time(chip, PON_TIME_100NS);
2792 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2793 msleep(250);
2794 pm_chg_vinmin_set(chip, chip->vin_min);
2795 set_min_pon_time(chip, PON_TIME_25NS);
2796 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002797}
2798
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002799#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002800#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2801#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002802static void unplug_check_worker(struct work_struct *work)
2803{
2804 struct delayed_work *dwork = to_delayed_work(work);
2805 struct pm8921_chg_chip *chip = container_of(dwork,
2806 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002807 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002808 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002809 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002810 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002811
2812 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2813 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002814 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2815 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002816 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002817
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002818 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002819 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002820 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2821 active_path, active_chg_plugged_in);
2822 if (active_path & USB_ACTIVE_BIT) {
2823 pr_debug("USB charger active\n");
2824
2825 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002826
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002827 if (usb_ma <= 100) {
2828 pr_debug(
2829 "Unenumerated or suspended usb_ma = %d skip\n",
2830 usb_ma);
2831 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002832 }
2833 } else if (active_path & DC_ACTIVE_BIT) {
2834 pr_debug("DC charger active\n");
2835 } else {
2836 /* No charger active */
2837 if (!(is_usb_chg_plugged_in(chip)
2838 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002839 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002840 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2841 pm_chg_get_regulation_loop(chip),
2842 pm_chg_get_fsm_state(chip),
2843 get_prop_batt_current(chip)
2844 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002845 if (chip->lockup_lpm_wrkarnd) {
2846 rc = pm8921_apply_19p2mhz_kickstart(chip);
2847 if (rc)
2848 pr_err("Failed kickstart rc=%d\n", rc);
2849
2850 /*
2851 * Make sure kickstart happens at least 200 ms
2852 * after charger has been removed.
2853 */
2854 if (chip->final_kickstart) {
2855 chip->final_kickstart = false;
2856 goto check_again_later;
2857 }
2858 }
2859 return;
2860 } else {
2861 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002862 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002863 }
David Keitel8c5201a2012-02-24 16:08:54 -08002864
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002865 chip->final_kickstart = true;
2866
2867 /* AICL only for usb wall charger */
2868 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0) {
David Keitel6ccbf132012-05-30 14:21:24 -07002869 reg_loop = pm_chg_get_regulation_loop(chip);
2870 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2871 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002872 (usb_ma > USB_WALL_THRESHOLD_MA)
2873 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002874 decrease_usb_ma_value(&usb_ma);
2875 usb_target_ma = usb_ma;
2876 /* end AICL here */
2877 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002878 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002879 usb_ma, usb_target_ma);
2880 }
David Keitelacf57c82012-03-07 18:48:50 -08002881 }
2882
2883 reg_loop = pm_chg_get_regulation_loop(chip);
2884 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2885
David Keitel6ccbf132012-05-30 14:21:24 -07002886 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002887 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002888 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002889 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2890 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2891 attempt_reverse_boost_fix(chip);
2892 /* after reverse boost fix check if the active
2893 * charger was detected as removed */
2894 active_chg_plugged_in
2895 = is_active_chg_plugged_in(chip,
2896 active_path);
2897 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2898 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002899 }
2900 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002901
2902 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002903 pr_debug("active_path = 0x%x, active_chg = %d\n",
2904 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002905 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2906
David Keitel6ccbf132012-05-30 14:21:24 -07002907 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2908 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2909 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002910 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002911 }
2912
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002913 /* AICL only for usb wall charger */
2914 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2915 && usb_target_ma > 0
2916 && !charging_disabled) {
David Keitelacf57c82012-03-07 18:48:50 -08002917 /* only increase iusb_max if vin loop not active */
2918 if (usb_ma < usb_target_ma) {
2919 increase_usb_ma_value(&usb_ma);
2920 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002921 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002922 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002923 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002924 } else {
2925 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002926 }
2927 }
Devin Kim2073afb2012-09-05 13:01:51 -07002928check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002929 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002930 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002931 if (ramp)
2932 schedule_delayed_work(&chip->unplug_check_work,
2933 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2934 else
2935 schedule_delayed_work(&chip->unplug_check_work,
2936 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002937}
2938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002939static irqreturn_t loop_change_irq_handler(int irq, void *data)
2940{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002941 struct pm8921_chg_chip *chip = data;
2942
2943 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2944 pm_chg_get_fsm_state(data),
2945 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002946 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 return IRQ_HANDLED;
2948}
2949
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002950struct ibatmax_max_adj_entry {
2951 int ibat_max_ma;
2952 int max_adj_ma;
2953};
2954
2955static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2956 {975, 300},
2957 {1475, 150},
2958 {1975, 200},
2959 {2475, 250},
2960};
2961
2962static int find_ibat_max_adj_ma(int ibat_target_ma)
2963{
2964 int i = 0;
2965
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002966 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2967 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002968 break;
2969 }
2970
2971 return ibatmax_adj_table[i].max_adj_ma;
2972}
2973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974static irqreturn_t fastchg_irq_handler(int irq, void *data)
2975{
2976 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002977 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002978
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002979 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2980 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2981 wake_lock(&chip->eoc_wake_lock);
2982 schedule_delayed_work(&chip->eoc_work,
2983 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002984 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002985 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002986 if (high_transition
2987 && chip->btc_override
2988 && !delayed_work_pending(&chip->btc_override_work)) {
2989 schedule_delayed_work(&chip->btc_override_work,
2990 round_jiffies_relative(msecs_to_jiffies
2991 (chip->btc_delay_ms)));
2992 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002993 power_supply_changed(&chip->batt_psy);
2994 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002995 return IRQ_HANDLED;
2996}
2997
2998static irqreturn_t trklchg_irq_handler(int irq, void *data)
2999{
3000 struct pm8921_chg_chip *chip = data;
3001
3002 power_supply_changed(&chip->batt_psy);
3003 return IRQ_HANDLED;
3004}
3005
3006static irqreturn_t batt_removed_irq_handler(int irq, void *data)
3007{
3008 struct pm8921_chg_chip *chip = data;
3009 int status;
3010
3011 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3012 pr_debug("battery present=%d state=%d", !status,
3013 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003014 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003015 power_supply_changed(&chip->batt_psy);
3016 return IRQ_HANDLED;
3017}
3018
3019static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3020{
3021 struct pm8921_chg_chip *chip = data;
3022
Amir Samuelovd31ef502011-10-26 14:41:36 +02003023 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003024 power_supply_changed(&chip->batt_psy);
3025 return IRQ_HANDLED;
3026}
3027
3028static irqreturn_t chghot_irq_handler(int irq, void *data)
3029{
3030 struct pm8921_chg_chip *chip = data;
3031
3032 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3033 power_supply_changed(&chip->batt_psy);
3034 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003035 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 return IRQ_HANDLED;
3037}
3038
3039static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3040{
3041 struct pm8921_chg_chip *chip = data;
3042
3043 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003044 handle_stop_ext_chg(chip);
3045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 power_supply_changed(&chip->batt_psy);
3047 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 return IRQ_HANDLED;
3049}
3050
3051static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3052{
3053 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003054 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003055
3056 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3057 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3058
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003059 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3060 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 power_supply_changed(&chip->batt_psy);
3063 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064 return IRQ_HANDLED;
3065}
David Keitel52fda532011-11-10 10:43:44 -08003066/*
3067 *
3068 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3069 * fire for two cases:
3070 *
3071 * If the interrupt line switches to high temperature is okay
3072 * and thus charging begins.
3073 * If bat_temp_ok is low this means the temperature is now
3074 * too hot or cold, so charging is stopped.
3075 *
3076 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003077static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3078{
David Keitel52fda532011-11-10 10:43:44 -08003079 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003080 struct pm8921_chg_chip *chip = data;
3081
David Keitel52fda532011-11-10 10:43:44 -08003082 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3083
3084 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3085 bat_temp_ok, pm_chg_get_fsm_state(data));
3086
3087 if (bat_temp_ok)
3088 handle_start_ext_chg(chip);
3089 else
3090 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003092 power_supply_changed(&chip->batt_psy);
3093 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003094 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 return IRQ_HANDLED;
3096}
3097
3098static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3099{
3100 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3101 return IRQ_HANDLED;
3102}
3103
3104static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3105{
3106 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3107 return IRQ_HANDLED;
3108}
3109
3110static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3111{
3112 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3113 return IRQ_HANDLED;
3114}
3115
3116static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3117{
3118 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3119 return IRQ_HANDLED;
3120}
3121
3122static irqreturn_t batfet_irq_handler(int irq, void *data)
3123{
3124 struct pm8921_chg_chip *chip = data;
3125
3126 pr_debug("vreg ov\n");
3127 power_supply_changed(&chip->batt_psy);
3128 return IRQ_HANDLED;
3129}
3130
3131static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3132{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003133 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003134 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003135
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003136 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003137 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003138
3139 if (chip->dc_present ^ dc_present)
3140 pm8921_bms_calibrate_hkadc();
3141
David Keitel88e1b572012-01-11 11:57:14 -08003142 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003143 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003144 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003145 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3146
3147 chip->dc_present = dc_present;
3148
3149 if (chip->ext_psy) {
3150 if (dc_present)
3151 handle_start_ext_chg(chip);
3152 else
3153 handle_stop_ext_chg(chip);
3154 } else {
3155 if (chip->lockup_lpm_wrkarnd)
3156 /* if no external supply call bypass debounce here */
3157 pm8921_chg_bypass_bat_gone_debounce(chip,
3158 is_chg_on_bat(chip));
3159
3160 if (dc_present)
3161 schedule_delayed_work(&chip->unplug_check_work,
3162 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3163 power_supply_changed(&chip->dc_psy);
3164 }
3165
3166 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167 return IRQ_HANDLED;
3168}
3169
3170static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3171{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003172 struct pm8921_chg_chip *chip = data;
3173
Amir Samuelovd31ef502011-10-26 14:41:36 +02003174 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 return IRQ_HANDLED;
3176}
3177
3178static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3179{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003180 struct pm8921_chg_chip *chip = data;
3181
Amir Samuelovd31ef502011-10-26 14:41:36 +02003182 handle_stop_ext_chg(chip);
3183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184 return IRQ_HANDLED;
3185}
3186
David Keitel88e1b572012-01-11 11:57:14 -08003187static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3188{
3189 struct power_supply *psy = &the_chip->batt_psy;
3190 struct power_supply *epsy = dev_get_drvdata(dev);
3191 int i, dcin_irq;
3192
3193 /* Only search for external supply if none is registered */
3194 if (!the_chip->ext_psy) {
3195 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3196 for (i = 0; i < epsy->num_supplicants; i++) {
3197 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3198 if (!strncmp(epsy->name, "dc", 2)) {
3199 the_chip->ext_psy = epsy;
3200 dcin_valid_irq_handler(dcin_irq,
3201 the_chip);
3202 }
3203 }
3204 }
3205 }
3206 return 0;
3207}
3208
3209static void pm_batt_external_power_changed(struct power_supply *psy)
3210{
3211 /* Only look for an external supply if it hasn't been registered */
3212 if (!the_chip->ext_psy)
3213 class_for_each_device(power_supply_class, NULL, psy,
3214 __pm_batt_external_power_changed_work);
3215}
3216
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003217/**
3218 * update_heartbeat - internal function to update userspace
3219 * per update_time minutes
3220 *
3221 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003222#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003223static void update_heartbeat(struct work_struct *work)
3224{
3225 struct delayed_work *dwork = to_delayed_work(work);
3226 struct pm8921_chg_chip *chip = container_of(dwork,
3227 struct pm8921_chg_chip, update_heartbeat_work);
3228
3229 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003230 if (chip->recent_reported_soc <= 20)
3231 schedule_delayed_work(&chip->update_heartbeat_work,
3232 round_jiffies_relative(msecs_to_jiffies
3233 (LOW_SOC_HEARTBEAT_MS)));
3234 else
3235 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003236 round_jiffies_relative(msecs_to_jiffies
3237 (chip->update_time)));
3238}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003239#define VDD_LOOP_ACTIVE_BIT BIT(3)
3240#define VDD_MAX_INCREASE_MV 400
3241static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3242module_param(vdd_max_increase_mv, int, 0644);
3243
3244static int ichg_threshold_ua = -400000;
3245module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003246
3247#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003248static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3249 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003250{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003251 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003252 int vbat_batt_terminal_mv;
3253 int reg_loop;
3254 int delta_mv = 0;
3255
3256 if (chip->rconn_mohm == 0) {
3257 pr_debug("Exiting as rconn_mohm is 0\n");
3258 return;
3259 }
3260 /* adjust vdd_max only in normal temperature zone */
3261 if (chip->is_bat_cool || chip->is_bat_warm) {
3262 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3263 chip->is_bat_cool, chip->is_bat_warm);
3264 return;
3265 }
3266
3267 reg_loop = pm_chg_get_regulation_loop(chip);
3268 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3269 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3270 reg_loop);
3271 return;
3272 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003273 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3274 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3275
3276 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3277
3278 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3279 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3280 delta_mv,
3281 programmed_vdd_max,
3282 adj_vdd_max_mv);
3283
3284 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3285 pr_debug("adj vdd_max lower than default max voltage\n");
3286 return;
3287 }
3288
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003289 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3290 * PM8921_CHG_VDDMAX_RES_MV;
3291
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003292 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3293 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003294 pr_debug("adjusting vdd_max_mv to %d to make "
3295 "vbat_batt_termial_uv = %d to %d\n",
3296 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3297 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3298}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003299
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003300static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3301{
3302 if (chip->is_bat_cool)
3303 pm_chg_vbatdet_set(the_chip,
3304 the_chip->cool_bat_voltage
3305 - the_chip->resume_voltage_delta);
3306 else if (chip->is_bat_warm)
3307 pm_chg_vbatdet_set(the_chip,
3308 the_chip->warm_bat_voltage
3309 - the_chip->resume_voltage_delta);
3310 else
3311 pm_chg_vbatdet_set(the_chip,
3312 the_chip->max_voltage_mv
3313 - the_chip->resume_voltage_delta);
3314}
3315
3316static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3317{
3318 unsigned int chg_current = chip->max_bat_chg_current;
3319
3320 if (chip->is_bat_cool)
3321 chg_current = min(chg_current, chip->cool_bat_chg_current);
3322
3323 if (chip->is_bat_warm)
3324 chg_current = min(chg_current, chip->warm_bat_chg_current);
3325
3326 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3327 chg_current = min(chg_current,
3328 chip->thermal_mitigation[thermal_mitigation]);
3329
3330 pm_chg_ibatmax_set(the_chip, chg_current);
3331}
3332
3333#define TEMP_HYSTERISIS_DECIDEGC 20
3334static void battery_cool(bool enter)
3335{
3336 pr_debug("enter = %d\n", enter);
3337 if (enter == the_chip->is_bat_cool)
3338 return;
3339 the_chip->is_bat_cool = enter;
3340 if (enter)
3341 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3342 else
3343 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3344 set_appropriate_battery_current(the_chip);
3345 set_appropriate_vbatdet(the_chip);
3346}
3347
3348static void battery_warm(bool enter)
3349{
3350 pr_debug("enter = %d\n", enter);
3351 if (enter == the_chip->is_bat_warm)
3352 return;
3353 the_chip->is_bat_warm = enter;
3354 if (enter)
3355 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3356 else
3357 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3358
3359 set_appropriate_battery_current(the_chip);
3360 set_appropriate_vbatdet(the_chip);
3361}
3362
3363static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3364{
3365 int temp = 0;
3366
3367 temp = get_prop_batt_temp(chip);
3368 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3369 temp, chip->warm_temp_dc,
3370 chip->cool_temp_dc);
3371
3372 if (chip->warm_temp_dc != INT_MIN) {
3373 if (chip->is_bat_warm
3374 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3375 battery_warm(false);
3376 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3377 battery_warm(true);
3378 }
3379
3380 if (chip->cool_temp_dc != INT_MIN) {
3381 if (chip->is_bat_cool
3382 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3383 battery_cool(false);
3384 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3385 battery_cool(true);
3386 }
3387}
3388
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003389enum {
3390 CHG_IN_PROGRESS,
3391 CHG_NOT_IN_PROGRESS,
3392 CHG_FINISHED,
3393};
3394
3395#define VBAT_TOLERANCE_MV 70
3396#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003397static int is_charging_finished(struct pm8921_chg_chip *chip,
3398 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003399{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003400 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003401 int regulation_loop, fast_chg, vcp;
3402 int rc;
3403 static int last_vbat_programmed = -EINVAL;
3404
3405 if (!is_ext_charging(chip)) {
3406 /* return if the battery is not being fastcharged */
3407 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3408 pr_debug("fast_chg = %d\n", fast_chg);
3409 if (fast_chg == 0)
3410 return CHG_NOT_IN_PROGRESS;
3411
3412 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3413 pr_debug("vcp = %d\n", vcp);
3414 if (vcp == 1)
3415 return CHG_IN_PROGRESS;
3416
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003417 /* reset count if battery is hot/cold */
3418 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3419 pr_debug("batt_temp_ok = %d\n", rc);
3420 if (rc == 0)
3421 return CHG_IN_PROGRESS;
3422
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003423 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3424 if (rc) {
3425 pr_err("couldnt read vddmax rc = %d\n", rc);
3426 return CHG_IN_PROGRESS;
3427 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003428 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3429 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003430
3431 if (last_vbat_programmed == -EINVAL)
3432 last_vbat_programmed = vbat_programmed;
3433 if (last_vbat_programmed != vbat_programmed) {
3434 /* vddmax changed, reset and check again */
3435 pr_debug("vddmax = %d last_vdd_max=%d\n",
3436 vbat_programmed, last_vbat_programmed);
3437 last_vbat_programmed = vbat_programmed;
3438 return CHG_IN_PROGRESS;
3439 }
3440
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003441 if (chip->is_bat_cool)
3442 vbat_intended = chip->cool_bat_voltage;
3443 else if (chip->is_bat_warm)
3444 vbat_intended = chip->warm_bat_voltage;
3445 else
3446 vbat_intended = chip->max_voltage_mv;
3447
3448 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3449 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3450 vbat_batt_terminal_uv,
3451 vbat_intended);
3452 return CHG_IN_PROGRESS;
3453 }
3454
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003455 regulation_loop = pm_chg_get_regulation_loop(chip);
3456 if (regulation_loop < 0) {
3457 pr_err("couldnt read the regulation loop err=%d\n",
3458 regulation_loop);
3459 return CHG_IN_PROGRESS;
3460 }
3461 pr_debug("regulation_loop=%d\n", regulation_loop);
3462
3463 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3464 return CHG_IN_PROGRESS;
3465 } /* !is_ext_charging */
3466
3467 /* reset count if battery chg current is more than iterm */
3468 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3469 if (rc) {
3470 pr_err("couldnt read iterm rc = %d\n", rc);
3471 return CHG_IN_PROGRESS;
3472 }
3473
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003474 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3475 iterm_programmed, ichg_meas_ma);
3476 /*
3477 * ichg_meas_ma < 0 means battery is drawing current
3478 * ichg_meas_ma > 0 means battery is providing current
3479 */
3480 if (ichg_meas_ma > 0)
3481 return CHG_IN_PROGRESS;
3482
3483 if (ichg_meas_ma * -1 > iterm_programmed)
3484 return CHG_IN_PROGRESS;
3485
3486 return CHG_FINISHED;
3487}
3488
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003489#define COMP_OVERRIDE_HOT_BANK 6
3490#define COMP_OVERRIDE_COLD_BANK 7
3491#define COMP_OVERRIDE_BIT BIT(1)
3492static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3493{
3494 u8 val;
3495 int rc = 0;
3496
3497 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3498
3499 if (flag)
3500 val |= 0x01;
3501
3502 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3503 if (rc < 0)
3504 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3505
3506 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3507 return rc;
3508}
3509
3510static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3511{
3512 u8 val;
3513 int rc = 0;
3514
3515 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3516
3517 if (flag)
3518 val |= 0x01;
3519
3520 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3521 if (rc < 0)
3522 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3523
3524 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3525 return rc;
3526}
3527
3528static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3529{
3530 int rc = 0;
3531 u8 reg;
3532 u8 val;
3533
3534 val = COMP_OVERRIDE_HOT_BANK << 2;
3535 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3536 if (rc < 0) {
3537 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3538 goto cold_init;
3539 }
3540 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3541 if (rc < 0) {
3542 pr_err("Could not read bank %d of override rc = %d\n",
3543 COMP_OVERRIDE_HOT_BANK, rc);
3544 goto cold_init;
3545 }
3546 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3547 /* for now override it as not hot */
3548 rc = pm_chg_override_hot(chip, 0);
3549 if (rc < 0)
3550 pr_err("Could not override hot rc = %d\n", rc);
3551 }
3552
3553cold_init:
3554 val = COMP_OVERRIDE_COLD_BANK << 2;
3555 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3556 if (rc < 0) {
3557 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3558 return;
3559 }
3560 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3561 if (rc < 0) {
3562 pr_err("Could not read bank %d of override rc = %d\n",
3563 COMP_OVERRIDE_COLD_BANK, rc);
3564 return;
3565 }
3566 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3567 /* for now override it as not cold */
3568 rc = pm_chg_override_cold(chip, 0);
3569 if (rc < 0)
3570 pr_err("Could not override cold rc = %d\n", rc);
3571 }
3572}
3573
3574static void btc_override_worker(struct work_struct *work)
3575{
3576 int decidegc;
3577 int temp;
3578 int rc = 0;
3579 struct delayed_work *dwork = to_delayed_work(work);
3580 struct pm8921_chg_chip *chip = container_of(dwork,
3581 struct pm8921_chg_chip, btc_override_work);
3582
3583 if (!chip->btc_override) {
3584 pr_err("called when not enabled\n");
3585 return;
3586 }
3587
3588 decidegc = get_prop_batt_temp(chip);
3589
3590 pr_debug("temp=%d\n", decidegc);
3591
3592 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3593 if (temp) {
3594 if (decidegc < chip->btc_override_hot_decidegc)
3595 /* stop forcing batt hot */
3596 rc = pm_chg_override_hot(chip, 0);
3597 if (rc)
3598 pr_err("Couldnt write 0 to hot comp\n");
3599 } else {
3600 if (decidegc >= chip->btc_override_hot_decidegc)
3601 /* start forcing batt hot */
3602 rc = pm_chg_override_hot(chip, 1);
3603 if (rc && chip->btc_panic_if_cant_stop_chg)
3604 panic("Couldnt override comps to stop chg\n");
3605 }
3606
3607 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3608 if (temp) {
3609 if (decidegc > chip->btc_override_cold_decidegc)
3610 /* stop forcing batt cold */
3611 rc = pm_chg_override_cold(chip, 0);
3612 if (rc)
3613 pr_err("Couldnt write 0 to cold comp\n");
3614 } else {
3615 if (decidegc <= chip->btc_override_cold_decidegc)
3616 /* start forcing batt cold */
3617 rc = pm_chg_override_cold(chip, 1);
3618 if (rc && chip->btc_panic_if_cant_stop_chg)
3619 panic("Couldnt override comps to stop chg\n");
3620 }
3621
3622 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3623 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3624 schedule_delayed_work(&chip->btc_override_work,
3625 round_jiffies_relative(msecs_to_jiffies
3626 (chip->btc_delay_ms)));
3627 return;
3628 }
3629
3630 rc = pm_chg_override_hot(chip, 0);
3631 if (rc)
3632 pr_err("Couldnt write 0 to hot comp\n");
3633 rc = pm_chg_override_cold(chip, 0);
3634 if (rc)
3635 pr_err("Couldnt write 0 to cold comp\n");
3636}
3637
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003638/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003639 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003640 * has happened
3641 *
3642 * If all conditions favouring, if the charge current is
3643 * less than the term current for three consecutive times
3644 * an EOC has happened.
3645 * The wakelock is released if there is no need to reshedule
3646 * - this happens when the battery is removed or EOC has
3647 * happened
3648 */
3649#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003650static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003651{
3652 struct delayed_work *dwork = to_delayed_work(work);
3653 struct pm8921_chg_chip *chip = container_of(dwork,
3654 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003655 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003656 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003657 int vbat_meas_uv, vbat_meas_mv;
3658 int ichg_meas_ua, ichg_meas_ma;
3659 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003660
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003661 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3662 &ichg_meas_ua, &vbat_meas_uv);
3663 vbat_meas_mv = vbat_meas_uv / 1000;
3664 /* rconn_mohm is in milliOhms */
3665 ichg_meas_ma = ichg_meas_ua / 1000;
3666 vbat_batt_terminal_uv = vbat_meas_uv
3667 + ichg_meas_ma
3668 * the_chip->rconn_mohm;
3669
3670 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003671
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003672 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003673 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003674 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003675 }
3676
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003677 if (end == CHG_FINISHED) {
3678 count++;
3679 } else {
3680 count = 0;
3681 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003682
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003683 if (count == CONSECUTIVE_COUNT) {
3684 count = 0;
3685 pr_info("End of Charging\n");
3686
3687 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003688
Amir Samuelovd31ef502011-10-26 14:41:36 +02003689 if (is_ext_charging(chip))
3690 chip->ext_charge_done = true;
3691
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003692 if (chip->is_bat_warm || chip->is_bat_cool)
3693 chip->bms_notify.is_battery_full = 0;
3694 else
3695 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003696 /* declare end of charging by invoking chgdone interrupt */
3697 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003698 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003699 check_temp_thresholds(chip);
3700 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003701 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003702 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003703 round_jiffies_relative(msecs_to_jiffies
3704 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003705 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003706 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003707
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003708eoc_worker_stop:
3709 wake_unlock(&chip->eoc_wake_lock);
3710 /* set the vbatdet back, in case it was changed to trigger charging */
3711 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003712}
3713
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003714/**
3715 * set_disable_status_param -
3716 *
3717 * Internal function to disable battery charging and also disable drawing
3718 * any current from the source. The device is forced to run on a battery
3719 * after this.
3720 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003721static int set_disable_status_param(const char *val, struct kernel_param *kp)
3722{
3723 int ret;
3724 struct pm8921_chg_chip *chip = the_chip;
3725
3726 ret = param_set_int(val, kp);
3727 if (ret) {
3728 pr_err("error setting value %d\n", ret);
3729 return ret;
3730 }
3731 pr_info("factory set disable param to %d\n", charging_disabled);
3732 if (chip) {
3733 pm_chg_auto_enable(chip, !charging_disabled);
3734 pm_chg_charge_dis(chip, charging_disabled);
3735 }
3736 return 0;
3737}
3738module_param_call(disabled, set_disable_status_param, param_get_uint,
3739 &charging_disabled, 0644);
3740
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003741static int rconn_mohm;
3742static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3743{
3744 int ret;
3745 struct pm8921_chg_chip *chip = the_chip;
3746
3747 ret = param_set_int(val, kp);
3748 if (ret) {
3749 pr_err("error setting value %d\n", ret);
3750 return ret;
3751 }
3752 if (chip)
3753 chip->rconn_mohm = rconn_mohm;
3754 return 0;
3755}
3756module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3757 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003758/**
3759 * set_thermal_mitigation_level -
3760 *
3761 * Internal function to control battery charging current to reduce
3762 * temperature
3763 */
3764static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3765{
3766 int ret;
3767 struct pm8921_chg_chip *chip = the_chip;
3768
3769 ret = param_set_int(val, kp);
3770 if (ret) {
3771 pr_err("error setting value %d\n", ret);
3772 return ret;
3773 }
3774
3775 if (!chip) {
3776 pr_err("called before init\n");
3777 return -EINVAL;
3778 }
3779
3780 if (!chip->thermal_mitigation) {
3781 pr_err("no thermal mitigation\n");
3782 return -EINVAL;
3783 }
3784
3785 if (thermal_mitigation < 0
3786 || thermal_mitigation >= chip->thermal_levels) {
3787 pr_err("out of bound level selected\n");
3788 return -EINVAL;
3789 }
3790
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003791 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003792 return ret;
3793}
3794module_param_call(thermal_mitigation, set_therm_mitigation_level,
3795 param_get_uint,
3796 &thermal_mitigation, 0644);
3797
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003798static int set_usb_max_current(const char *val, struct kernel_param *kp)
3799{
3800 int ret, mA;
3801 struct pm8921_chg_chip *chip = the_chip;
3802
3803 ret = param_set_int(val, kp);
3804 if (ret) {
3805 pr_err("error setting value %d\n", ret);
3806 return ret;
3807 }
3808 if (chip) {
3809 pr_warn("setting current max to %d\n", usb_max_current);
3810 pm_chg_iusbmax_get(chip, &mA);
3811 if (mA > usb_max_current)
3812 pm8921_charger_vbus_draw(usb_max_current);
3813 return 0;
3814 }
3815 return -EINVAL;
3816}
David Keitelacf57c82012-03-07 18:48:50 -08003817module_param_call(usb_max_current, set_usb_max_current,
3818 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003820static void free_irqs(struct pm8921_chg_chip *chip)
3821{
3822 int i;
3823
3824 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3825 if (chip->pmic_chg_irq[i]) {
3826 free_irq(chip->pmic_chg_irq[i], chip);
3827 chip->pmic_chg_irq[i] = 0;
3828 }
3829}
3830
David Keitel88e1b572012-01-11 11:57:14 -08003831/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003832static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3833{
3834 unsigned long flags;
3835 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003836 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003837
3838 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3839 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3840
3841 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003842 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003843 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003844 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003845 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847
3848 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3849 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3850 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003851 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003852 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3853 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003854 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003855 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3856 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003857 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858
3859 spin_lock_irqsave(&vbus_lock, flags);
3860 if (usb_chg_current) {
3861 /* reissue a vbus draw call */
3862 __pm8921_charger_vbus_draw(usb_chg_current);
3863 }
3864 spin_unlock_irqrestore(&vbus_lock, flags);
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003865 /*
3866 * The bootloader could have started charging, a fastchg interrupt
3867 * might not happen. Check the real time status and if it is fast
3868 * charging invoke the handler so that the eoc worker could be
3869 * started
3870 */
3871 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3872 if (is_fast_chg)
3873 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003874
3875 fsm_state = pm_chg_get_fsm_state(chip);
3876 if (is_battery_charging(fsm_state)) {
3877 chip->bms_notify.is_charging = 1;
3878 pm8921_bms_charging_began();
3879 }
3880
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003881 check_battery_valid(chip);
3882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3884 chip->usb_present,
3885 chip->dc_present,
3886 get_prop_batt_present(chip),
3887 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003888
3889 /* Determine which USB trim column to use */
3890 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3891 chip->usb_trim_table = usb_trim_8917_table;
3892 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3893 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003894}
3895
3896struct pm_chg_irq_init_data {
3897 unsigned int irq_id;
3898 char *name;
3899 unsigned long flags;
3900 irqreturn_t (*handler)(int, void *);
3901};
3902
3903#define CHG_IRQ(_id, _flags, _handler) \
3904{ \
3905 .irq_id = _id, \
3906 .name = #_id, \
3907 .flags = _flags, \
3908 .handler = _handler, \
3909}
3910struct pm_chg_irq_init_data chg_irq_data[] = {
3911 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3912 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003913 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3914 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003915 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3916 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3918 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3919 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3920 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3921 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3922 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3923 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3924 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003925 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3926 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003927 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3928 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3929 batt_removed_irq_handler),
3930 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3931 batttemp_hot_irq_handler),
3932 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3933 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3934 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003935 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3936 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003937 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3938 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003939 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3940 coarse_det_low_irq_handler),
3941 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3942 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3943 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3944 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3945 batfet_irq_handler),
3946 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3947 dcin_valid_irq_handler),
3948 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3949 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003950 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951};
3952
3953static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3954 struct platform_device *pdev)
3955{
3956 struct resource *res;
3957 int ret, i;
3958
3959 ret = 0;
3960 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3961
3962 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3963 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3964 chg_irq_data[i].name);
3965 if (res == NULL) {
3966 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3967 goto err_out;
3968 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003969 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 ret = request_irq(res->start, chg_irq_data[i].handler,
3971 chg_irq_data[i].flags,
3972 chg_irq_data[i].name, chip);
3973 if (ret < 0) {
3974 pr_err("couldn't request %d (%s) %d\n", res->start,
3975 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003976 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003977 goto err_out;
3978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003979 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3980 }
3981 return 0;
3982
3983err_out:
3984 free_irqs(chip);
3985 return -EINVAL;
3986}
3987
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003988#define VREF_BATT_THERM_FORCE_ON BIT(7)
3989static void detect_battery_removal(struct pm8921_chg_chip *chip)
3990{
3991 u8 temp;
3992
3993 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3994 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3995
3996 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3997 /*
3998 * batt therm force on bit is battery backed and is default 0
3999 * The charger sets this bit at init time. If this bit is found
4000 * 0 that means the battery was removed. Tell the bms about it
4001 */
4002 pm8921_bms_invalidate_shutdown_soc();
4003}
4004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004005#define ENUM_TIMER_STOP_BIT BIT(1)
4006#define BOOT_DONE_BIT BIT(6)
4007#define CHG_BATFET_ON_BIT BIT(3)
4008#define CHG_VCP_EN BIT(0)
4009#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4010#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004011#define PM_SUB_REV 0x001
4012#define MIN_CHARGE_CURRENT_MA 350
4013#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004014static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4015{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004016 u8 subrev;
4017 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004019 spin_lock_init(&lpm_lock);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08004020
4021 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4022 rc = __pm8921_apply_19p2mhz_kickstart(chip);
4023 if (rc) {
4024 pr_err("Failed to apply kickstart rc=%d\n", rc);
4025 return rc;
4026 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004027 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004028
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004029 detect_battery_removal(chip);
4030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004032 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 if (rc) {
4034 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4035 return rc;
4036 }
4037
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004038 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4039
4040 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4041 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4042
4043 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045 if (rc) {
4046 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004047 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048 return rc;
4049 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004050 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004051 chip->max_voltage_mv
4052 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053 if (rc) {
4054 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004055 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056 return rc;
4057 }
4058
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004059 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004060 if (rc) {
4061 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004062 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 return rc;
4064 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004065
4066 if (chip->safe_current_ma == 0)
4067 chip->safe_current_ma = SAFE_CURRENT_MA;
4068
4069 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070 if (rc) {
4071 pr_err("Failed to set max voltage to %d rc=%d\n",
4072 SAFE_CURRENT_MA, rc);
4073 return rc;
4074 }
4075
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004076 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 if (rc) {
4078 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4079 return rc;
4080 }
4081
4082 rc = pm_chg_iterm_set(chip, chip->term_current);
4083 if (rc) {
4084 pr_err("Failed to set term current to %d rc=%d\n",
4085 chip->term_current, rc);
4086 return rc;
4087 }
4088
4089 /* Disable the ENUM TIMER */
4090 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4091 ENUM_TIMER_STOP_BIT);
4092 if (rc) {
4093 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4094 return rc;
4095 }
4096
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004097 fcc_uah = pm8921_bms_get_fcc();
4098 if (fcc_uah > 0) {
4099 safety_time = div_s64((s64)fcc_uah * 60,
4100 1000 * MIN_CHARGE_CURRENT_MA);
4101 /* add 20 minutes of buffer time */
4102 safety_time += 20;
4103
4104 /* make sure we do not exceed the maximum programmable time */
4105 if (safety_time > PM8921_CHG_TCHG_MAX)
4106 safety_time = PM8921_CHG_TCHG_MAX;
4107 }
4108
4109 rc = pm_chg_tchg_max_set(chip, safety_time);
4110 if (rc) {
4111 pr_err("Failed to set max time to %d minutes rc=%d\n",
4112 safety_time, rc);
4113 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004114 }
4115
4116 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004117 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004118 if (rc) {
4119 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004120 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004121 return rc;
4122 }
4123 }
4124
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004125 if (chip->vin_min != 0) {
4126 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4127 if (rc) {
4128 pr_err("Failed to set vin min to %d mV rc=%d\n",
4129 chip->vin_min, rc);
4130 return rc;
4131 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004132 } else {
4133 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004134 }
4135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004136 rc = pm_chg_disable_wd(chip);
4137 if (rc) {
4138 pr_err("Failed to disable wd rc=%d\n", rc);
4139 return rc;
4140 }
4141
4142 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4143 CHG_BAT_TEMP_DIS_BIT, 0);
4144 if (rc) {
4145 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4146 return rc;
4147 }
4148 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004149 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4150 rc = pm_chg_write(chip,
4151 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4152 else
4153 rc = pm_chg_write(chip,
4154 CHG_BUCK_CLOCK_CTRL, 0x15);
4155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 if (rc) {
4157 pr_err("Failed to switch buck clk rc=%d\n", rc);
4158 return rc;
4159 }
4160
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004161 if (chip->trkl_voltage != 0) {
4162 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4163 if (rc) {
4164 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4165 chip->trkl_voltage, rc);
4166 return rc;
4167 }
4168 }
4169
4170 if (chip->weak_voltage != 0) {
4171 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4172 if (rc) {
4173 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4174 chip->weak_voltage, rc);
4175 return rc;
4176 }
4177 }
4178
4179 if (chip->trkl_current != 0) {
4180 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4181 if (rc) {
4182 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4183 chip->trkl_voltage, rc);
4184 return rc;
4185 }
4186 }
4187
4188 if (chip->weak_current != 0) {
4189 rc = pm_chg_iweak_set(chip, chip->weak_current);
4190 if (rc) {
4191 pr_err("Failed to set weak current to %dmA rc=%d\n",
4192 chip->weak_current, rc);
4193 return rc;
4194 }
4195 }
4196
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004197 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4198 if (rc) {
4199 pr_err("Failed to set cold config %d rc=%d\n",
4200 chip->cold_thr, rc);
4201 }
4202
4203 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4204 if (rc) {
4205 pr_err("Failed to set hot config %d rc=%d\n",
4206 chip->hot_thr, rc);
4207 }
4208
Jay Chokshid674a512012-03-15 14:06:04 -07004209 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4210 if (rc) {
4211 pr_err("Failed to set charger LED src config %d rc=%d\n",
4212 chip->led_src_config, rc);
4213 }
4214
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004215 /* Workarounds for die 3.0 */
4216 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4217 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4218 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4219 if (rc) {
4220 pr_err("read failed: addr=%03X, rc=%d\n",
4221 PM_SUB_REV, rc);
4222 return rc;
4223 }
4224 /* Check if die 3.0.1 is present */
4225 if (subrev & 0x1)
4226 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4227 else
4228 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004229 }
4230
David Keitel0789fc62012-06-07 17:43:27 -07004231 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004232 /* Set PM8917 USB_OVP debounce time to 15 ms */
4233 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4234 OVP_DEBOUNCE_TIME, 0x6);
4235 if (rc) {
4236 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4237 return rc;
4238 }
4239
4240 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004241 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004242 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004243 rc = pm_chg_uvd_threshold_set(chip,
4244 chip->uvd_voltage_mv);
4245 if (rc) {
4246 pr_err("Failed to set UVD threshold %drc=%d\n",
4247 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004248 return rc;
4249 }
David Keitel0789fc62012-06-07 17:43:27 -07004250 }
4251 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004252
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004253 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004254
David Keitela3c0d822011-11-03 14:18:52 -07004255 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004256 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004257
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004258 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4259 VREF_BATT_THERM_FORCE_ON);
4260 if (rc)
4261 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263 rc = pm_chg_charge_dis(chip, charging_disabled);
4264 if (rc) {
4265 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4266 return rc;
4267 }
4268
4269 rc = pm_chg_auto_enable(chip, !charging_disabled);
4270 if (rc) {
4271 pr_err("Failed to enable charging rc=%d\n", rc);
4272 return rc;
4273 }
4274
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004275 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4276 /* Clear kickstart */
4277 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4278 if (rc) {
4279 pr_err("Failed to clear kickstart rc=%d\n", rc);
4280 return rc;
4281 }
4282
4283 /* From here the lpm_workaround will be active */
4284 chip->lockup_lpm_wrkarnd = true;
4285
4286 /* Enable LPM */
4287 pm8921_chg_set_lpm(chip, 1);
4288 }
4289
4290 if (chip->lockup_lpm_wrkarnd) {
4291 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4292 if (IS_ERR(chip->vreg_xoadc))
4293 return -ENODEV;
4294
4295 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4296 if (rc < 0) {
4297 pr_err("Failed to set configure HPM rc=%d\n", rc);
4298 return rc;
4299 }
4300
4301 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4302 if (rc) {
4303 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4304 return rc;
4305 }
4306
4307 rc = regulator_enable(chip->vreg_xoadc);
4308 if (rc) {
4309 pr_err("Failed to enable L14 rc=%d\n", rc);
4310 return rc;
4311 }
4312 }
4313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004314 return 0;
4315}
4316
4317static int get_rt_status(void *data, u64 * val)
4318{
4319 int i = (int)data;
4320 int ret;
4321
4322 /* global irq number is passed in via data */
4323 ret = pm_chg_get_rt_status(the_chip, i);
4324 *val = ret;
4325 return 0;
4326}
4327DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4328
4329static int get_fsm_status(void *data, u64 * val)
4330{
4331 u8 temp;
4332
4333 temp = pm_chg_get_fsm_state(the_chip);
4334 *val = temp;
4335 return 0;
4336}
4337DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4338
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004339static int get_reg_loop(void *data, u64 * val)
4340{
4341 u8 temp;
4342
4343 if (!the_chip) {
4344 pr_err("%s called before init\n", __func__);
4345 return -EINVAL;
4346 }
4347 temp = pm_chg_get_regulation_loop(the_chip);
4348 *val = temp;
4349 return 0;
4350}
4351DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004353static int get_reg(void *data, u64 * val)
4354{
4355 int addr = (int)data;
4356 int ret;
4357 u8 temp;
4358
4359 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4360 if (ret) {
4361 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4362 addr, temp, ret);
4363 return -EAGAIN;
4364 }
4365 *val = temp;
4366 return 0;
4367}
4368
4369static int set_reg(void *data, u64 val)
4370{
4371 int addr = (int)data;
4372 int ret;
4373 u8 temp;
4374
4375 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004376 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004377 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004378 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004379 addr, temp, ret);
4380 return -EAGAIN;
4381 }
4382 return 0;
4383}
4384DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4385
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004386static int reg_loop;
4387#define MAX_REG_LOOP_CHAR 10
4388static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4389{
4390 u8 temp;
4391
4392 if (!the_chip) {
4393 pr_err("called before init\n");
4394 return -EINVAL;
4395 }
4396 temp = pm_chg_get_regulation_loop(the_chip);
4397 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4398}
4399module_param_call(reg_loop, NULL, get_reg_loop_param,
4400 &reg_loop, 0644);
4401
4402static int max_chg_ma;
4403#define MAX_MA_CHAR 10
4404static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4405{
4406 if (!the_chip) {
4407 pr_err("called before init\n");
4408 return -EINVAL;
4409 }
4410 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4411}
4412module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4413 &max_chg_ma, 0644);
4414static int ibatmax_ma;
4415static int set_ibat_max(const char *val, struct kernel_param *kp)
4416{
4417 int rc;
4418
4419 if (!the_chip) {
4420 pr_err("called before init\n");
4421 return -EINVAL;
4422 }
4423
4424 rc = param_set_int(val, kp);
4425 if (rc) {
4426 pr_err("error setting value %d\n", rc);
4427 return rc;
4428 }
4429
4430 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4431 <= the_chip->ibatmax_max_adj_ma) {
4432 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4433 if (rc) {
4434 pr_err("Failed to set ibatmax rc = %d\n", rc);
4435 return rc;
4436 }
4437 }
4438
4439 return 0;
4440}
4441static int get_ibat_max(char *buf, struct kernel_param *kp)
4442{
4443 int ibat_ma;
4444 int rc;
4445
4446 if (!the_chip) {
4447 pr_err("called before init\n");
4448 return -EINVAL;
4449 }
4450
4451 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4452 if (rc) {
4453 pr_err("ibatmax_get error = %d\n", rc);
4454 return rc;
4455 }
4456
4457 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4458}
4459module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4460 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004461enum {
4462 BAT_WARM_ZONE,
4463 BAT_COOL_ZONE,
4464};
4465static int get_warm_cool(void *data, u64 * val)
4466{
4467 if (!the_chip) {
4468 pr_err("%s called before init\n", __func__);
4469 return -EINVAL;
4470 }
4471 if ((int)data == BAT_WARM_ZONE)
4472 *val = the_chip->is_bat_warm;
4473 if ((int)data == BAT_COOL_ZONE)
4474 *val = the_chip->is_bat_cool;
4475 return 0;
4476}
4477DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004479static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4480{
4481 int i;
4482
4483 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4484
4485 if (IS_ERR(chip->dent)) {
4486 pr_err("pmic charger couldnt create debugfs dir\n");
4487 return;
4488 }
4489
4490 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4491 (void *)CHG_CNTRL, &reg_fops);
4492 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4493 (void *)CHG_CNTRL_2, &reg_fops);
4494 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4495 (void *)CHG_CNTRL_3, &reg_fops);
4496 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4497 (void *)PBL_ACCESS1, &reg_fops);
4498 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4499 (void *)PBL_ACCESS2, &reg_fops);
4500 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4501 (void *)SYS_CONFIG_1, &reg_fops);
4502 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4503 (void *)SYS_CONFIG_2, &reg_fops);
4504 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4505 (void *)CHG_VDD_MAX, &reg_fops);
4506 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4507 (void *)CHG_VDD_SAFE, &reg_fops);
4508 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4509 (void *)CHG_VBAT_DET, &reg_fops);
4510 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4511 (void *)CHG_IBAT_MAX, &reg_fops);
4512 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4513 (void *)CHG_IBAT_SAFE, &reg_fops);
4514 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4515 (void *)CHG_VIN_MIN, &reg_fops);
4516 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4517 (void *)CHG_VTRICKLE, &reg_fops);
4518 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4519 (void *)CHG_ITRICKLE, &reg_fops);
4520 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4521 (void *)CHG_ITERM, &reg_fops);
4522 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4523 (void *)CHG_TCHG_MAX, &reg_fops);
4524 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4525 (void *)CHG_TWDOG, &reg_fops);
4526 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4527 (void *)CHG_TEMP_THRESH, &reg_fops);
4528 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4529 (void *)CHG_COMP_OVR, &reg_fops);
4530 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4531 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4532 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4533 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4534 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4535 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4536 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4537 (void *)CHG_TEST, &reg_fops);
4538
4539 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4540 &fsm_fops);
4541
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004542 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4543 &reg_loop_fops);
4544
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004545 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4546 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4547 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4548 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4549
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004550 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4551 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4552 debugfs_create_file(chg_irq_data[i].name, 0444,
4553 chip->dent,
4554 (void *)chg_irq_data[i].irq_id,
4555 &rt_fops);
4556 }
4557}
4558
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004559static int pm8921_charger_suspend_noirq(struct device *dev)
4560{
4561 int rc;
4562 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4563
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004564 if (chip->lockup_lpm_wrkarnd) {
4565 rc = regulator_disable(chip->vreg_xoadc);
4566 if (rc)
4567 pr_err("Failed to disable L14 rc=%d\n", rc);
4568
4569 rc = pm8921_apply_19p2mhz_kickstart(chip);
4570 if (rc)
4571 pr_err("Failed to apply kickstart rc=%d\n", rc);
4572 }
4573
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004574 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4575 if (rc)
4576 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004577 return 0;
4578}
4579
4580static int pm8921_charger_resume_noirq(struct device *dev)
4581{
4582 int rc;
4583 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4584
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004585 if (chip->lockup_lpm_wrkarnd) {
4586 rc = regulator_enable(chip->vreg_xoadc);
4587 if (rc)
4588 pr_err("Failed to enable L14 rc=%d\n", rc);
4589
4590 rc = pm8921_apply_19p2mhz_kickstart(chip);
4591 if (rc)
4592 pr_err("Failed to apply kickstart rc=%d\n", rc);
4593 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004594
4595 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4596 VREF_BATT_THERM_FORCE_ON);
4597 if (rc)
4598 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4599 return 0;
4600}
4601
David Keitelf2226022011-12-13 15:55:50 -08004602static int pm8921_charger_resume(struct device *dev)
4603{
David Keitelf2226022011-12-13 15:55:50 -08004604 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4605
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004606 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4607 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4608 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4609 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004610
4611 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4612 is_usb_chg_plugged_in(the_chip)))
4613 schedule_delayed_work(&chip->btc_override_work, 0);
4614
David Keitelf2226022011-12-13 15:55:50 -08004615 return 0;
4616}
4617
4618static int pm8921_charger_suspend(struct device *dev)
4619{
David Keitelf2226022011-12-13 15:55:50 -08004620 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4621
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004622 if (chip->btc_override)
4623 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004624
4625 if (is_usb_chg_plugged_in(chip)) {
4626 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4627 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4628 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004629
David Keitelf2226022011-12-13 15:55:50 -08004630 return 0;
4631}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004632static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4633{
4634 int rc = 0;
4635 struct pm8921_chg_chip *chip;
4636 const struct pm8921_charger_platform_data *pdata
4637 = pdev->dev.platform_data;
4638
4639 if (!pdata) {
4640 pr_err("missing platform data\n");
4641 return -EINVAL;
4642 }
4643
4644 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4645 GFP_KERNEL);
4646 if (!chip) {
4647 pr_err("Cannot allocate pm_chg_chip\n");
4648 return -ENOMEM;
4649 }
4650
4651 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004652 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004653 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004654 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004655 chip->alarm_low_mv = pdata->alarm_low_mv;
4656 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004657 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004658 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004659 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004660 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004661 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004662 chip->term_current = pdata->term_current;
4663 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004664 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004665 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4666 chip->batt_id_min = pdata->batt_id_min;
4667 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004668 if (pdata->cool_temp != INT_MIN)
4669 chip->cool_temp_dc = pdata->cool_temp * 10;
4670 else
4671 chip->cool_temp_dc = INT_MIN;
4672
4673 if (pdata->warm_temp != INT_MIN)
4674 chip->warm_temp_dc = pdata->warm_temp * 10;
4675 else
4676 chip->warm_temp_dc = INT_MIN;
4677
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004678 chip->temp_check_period = pdata->temp_check_period;
4679 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004680 /* Assign to corresponding module parameter */
4681 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004682 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4683 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4684 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4685 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004686 chip->trkl_voltage = pdata->trkl_voltage;
4687 chip->weak_voltage = pdata->weak_voltage;
4688 chip->trkl_current = pdata->trkl_current;
4689 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004690 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004691 chip->thermal_mitigation = pdata->thermal_mitigation;
4692 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004693
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004694 chip->cold_thr = pdata->cold_thr;
4695 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004696 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004697 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004698 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004699 chip->battery_less_hardware = pdata->battery_less_hardware;
4700 chip->btc_override = pdata->btc_override;
4701 if (chip->btc_override) {
4702 chip->btc_delay_ms = pdata->btc_delay_ms;
4703 chip->btc_override_cold_decidegc
4704 = pdata->btc_override_cold_degc * 10;
4705 chip->btc_override_hot_decidegc
4706 = pdata->btc_override_hot_degc * 10;
4707 chip->btc_panic_if_cant_stop_chg
4708 = pdata->btc_panic_if_cant_stop_chg;
4709 }
4710
4711 if (chip->battery_less_hardware)
4712 charging_disabled = 1;
4713
4714 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4715 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004717 rc = pm8921_chg_hw_init(chip);
4718 if (rc) {
4719 pr_err("couldn't init hardware rc=%d\n", rc);
4720 goto free_chip;
4721 }
4722
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004723 if (chip->btc_override)
4724 pm8921_chg_btc_override_init(chip);
4725
4726 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
4727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728 chip->usb_psy.name = "usb",
4729 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB,
4730 chip->usb_psy.supplied_to = pm_power_supplied_to,
4731 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004732 chip->usb_psy.properties = pm_power_props_usb,
4733 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb),
4734 chip->usb_psy.get_property = pm_power_get_property_usb,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07004735 chip->usb_psy.set_property = pm_power_set_property_usb,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004736
David Keitel6ed71a52012-01-30 12:42:18 -08004737 chip->dc_psy.name = "pm8921-dc",
4738 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
4739 chip->dc_psy.supplied_to = pm_power_supplied_to,
4740 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08004741 chip->dc_psy.properties = pm_power_props_mains,
4742 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains),
4743 chip->dc_psy.get_property = pm_power_get_property_mains,
David Keitel6ed71a52012-01-30 12:42:18 -08004744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004745 chip->batt_psy.name = "battery",
4746 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
4747 chip->batt_psy.properties = msm_batt_power_props,
4748 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
4749 chip->batt_psy.get_property = pm_batt_power_get_property,
David Keitel88e1b572012-01-11 11:57:14 -08004750 chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004751 rc = power_supply_register(chip->dev, &chip->usb_psy);
4752 if (rc < 0) {
4753 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004754 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004755 }
4756
David Keitel6ed71a52012-01-30 12:42:18 -08004757 rc = power_supply_register(chip->dev, &chip->dc_psy);
4758 if (rc < 0) {
4759 pr_err("power_supply_register usb failed rc = %d\n", rc);
4760 goto unregister_usb;
4761 }
4762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004763 rc = power_supply_register(chip->dev, &chip->batt_psy);
4764 if (rc < 0) {
4765 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004766 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004767 }
4768
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004769 platform_set_drvdata(pdev, chip);
4770 the_chip = chip;
4771
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004772 /* set initial state of the USB charger type to UNKNOWN */
4773 power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
4774
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004775 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004776 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004777 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4778 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004779 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004780
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004781 INIT_WORK(&chip->bms_notify.work, bms_notify);
4782 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4783
4784 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4785 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4786
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004787 rc = request_irqs(chip, pdev);
4788 if (rc) {
4789 pr_err("couldn't register interrupts rc=%d\n", rc);
4790 goto unregister_batt;
4791 }
4792
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004793 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004794 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004795 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004796 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798 create_debugfs_entries(chip);
4799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004800 /* determine what state the charger is in */
4801 determine_initial_state(chip);
4802
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004803 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004804 schedule_delayed_work(&chip->update_heartbeat_work,
4805 round_jiffies_relative(msecs_to_jiffies
4806 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004807 return 0;
4808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004809unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004810 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004811 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004812unregister_dc:
4813 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004814unregister_usb:
4815 power_supply_unregister(&chip->usb_psy);
4816free_chip:
4817 kfree(chip);
4818 return rc;
4819}
4820
4821static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4822{
4823 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4824
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004825 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826 free_irqs(chip);
4827 platform_set_drvdata(pdev, NULL);
4828 the_chip = NULL;
4829 kfree(chip);
4830 return 0;
4831}
David Keitelf2226022011-12-13 15:55:50 -08004832static const struct dev_pm_ops pm8921_pm_ops = {
4833 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004834 .suspend_noirq = pm8921_charger_suspend_noirq,
4835 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004836 .resume = pm8921_charger_resume,
4837};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004839 .probe = pm8921_charger_probe,
4840 .remove = __devexit_p(pm8921_charger_remove),
4841 .driver = {
4842 .name = PM8921_CHARGER_DEV_NAME,
4843 .owner = THIS_MODULE,
4844 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004845 },
4846};
4847
4848static int __init pm8921_charger_init(void)
4849{
4850 return platform_driver_register(&pm8921_charger_driver);
4851}
4852
4853static void __exit pm8921_charger_exit(void)
4854{
4855 platform_driver_unregister(&pm8921_charger_driver);
4856}
4857
4858late_initcall(pm8921_charger_init);
4859module_exit(pm8921_charger_exit);
4860
4861MODULE_LICENSE("GPL v2");
4862MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4863MODULE_VERSION("1.0");
4864MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);