blob: e9cf973898714943561e0b02bb45afd4847dd927 [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;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200258 bool ext_charging;
259 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700260 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct work_struct battery_id_valid_work;
263 int64_t batt_id_min;
264 int64_t batt_id_max;
265 int trkl_voltage;
266 int weak_voltage;
267 int trkl_current;
268 int weak_current;
269 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800270 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700271 int thermal_levels;
272 struct delayed_work update_heartbeat_work;
273 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800274 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800275 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700276 struct delayed_work btc_override_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700277 struct wake_lock eoc_wake_lock;
278 enum pm8921_chg_cold_thr cold_thr;
279 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800280 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700281 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700282 bool host_mode;
David Keitelff4f9ce2012-08-24 15:11:23 -0700283 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700284 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700285 int recent_reported_soc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700286 int battery_less_hardware;
287 int ibatmax_max_adj_ma;
288 int btc_override;
289 int btc_override_cold_decidegc;
290 int btc_override_hot_decidegc;
291 int btc_delay_ms;
292 bool btc_panic_if_cant_stop_chg;
293 int stop_chg_upon_expiry;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -0800294 bool disable_aicl;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +0530295 int usb_type;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +0530296 bool disable_chg_rmvl_wrkarnd;
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 -0700312#define LPM_ENABLE_BIT BIT(2)
313static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
314{
315 int rc;
316 u8 reg;
317
318 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
319 if (rc) {
320 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
321 CHG_CNTRL, rc);
322 return rc;
323 }
324 reg &= ~LPM_ENABLE_BIT;
325 reg |= (enable ? LPM_ENABLE_BIT : 0);
326
327 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
328 if (rc) {
329 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
330 CHG_CNTRL, rc);
331 return rc;
332 }
333
334 return rc;
335}
336
337static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
338{
339 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700340
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -0800341 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
342 if (rc)
343 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700344
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700345 return rc;
346}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
349 u8 mask, u8 val)
350{
351 int rc;
352 u8 reg;
353
354 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
355 if (rc) {
356 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
357 return rc;
358 }
359 reg &= ~mask;
360 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700361 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700363 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 return rc;
365 }
366 return 0;
367}
368
David Keitelcf867232012-01-27 18:40:12 -0800369static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
370{
371 return pm8xxx_read_irq_stat(chip->dev->parent,
372 chip->pmic_chg_irq[irq_id]);
373}
374
375/* Treat OverVoltage/UnderVoltage as source missing */
376static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
377{
378 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
379}
380
381/* Treat OverVoltage/UnderVoltage as source missing */
382static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
383{
384 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
385}
386
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700387static int is_batfet_closed(struct pm8921_chg_chip *chip)
388{
389 return pm_chg_get_rt_status(chip, BATFET_IRQ);
390}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391#define CAPTURE_FSM_STATE_CMD 0xC2
392#define READ_BANK_7 0x70
393#define READ_BANK_4 0x40
394static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
395{
396 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800397 int err = 0, ret = 0;
398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800400 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 if (err) {
402 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800403 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 }
405
406 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800407 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 if (err) {
409 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800410 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 }
412
413 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
414 if (err) {
415 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800416 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 }
418 /* get the lower 4 bits */
419 ret = temp & 0xF;
420
421 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800422 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 if (err) {
424 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800425 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 }
427
428 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
429 if (err) {
430 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800431 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 }
433 /* get the upper 1 bit */
434 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800435
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800436err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800437 if (err)
438 return err;
439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 return ret;
441}
442
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700443#define READ_BANK_6 0x60
444static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
445{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800446 u8 temp, data;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800447 int err = 0;
448
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700449 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800450 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700451 if (err) {
452 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800453 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700454 }
455
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800456 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700457 if (err) {
458 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800459 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700460 }
461
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800462err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800463 if (err)
464 return err;
465
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700466 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800467 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700468}
469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470#define CHG_USB_SUSPEND_BIT BIT(2)
471static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
472{
473 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
474 enable ? CHG_USB_SUSPEND_BIT : 0);
475}
476
477#define CHG_EN_BIT BIT(7)
478static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
479{
480 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
481 enable ? CHG_EN_BIT : 0);
482}
483
David Keitel753ec8d2011-11-02 10:56:37 -0700484#define CHG_FAILED_CLEAR BIT(0)
485#define ATC_FAILED_CLEAR BIT(1)
486static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
487{
488 int rc;
489
490 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
491 clear ? ATC_FAILED_CLEAR : 0);
492 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
493 clear ? CHG_FAILED_CLEAR : 0);
494 return rc;
495}
496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497#define CHG_CHARGE_DIS_BIT BIT(1)
498static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
499{
500 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
501 disable ? CHG_CHARGE_DIS_BIT : 0);
502}
503
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800504static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
505{
506 u8 temp;
507
508 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
509 return temp & CHG_CHARGE_DIS_BIT;
510}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511#define PM8921_CHG_V_MIN_MV 3240
512#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800513#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514#define PM8921_CHG_VDDMAX_MAX 4500
515#define PM8921_CHG_VDDMAX_MIN 3400
516#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800517static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800519 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800520 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800522 if (voltage < PM8921_CHG_VDDMAX_MIN
523 || voltage > PM8921_CHG_VDDMAX_MAX) {
524 pr_err("bad mV=%d asked to set\n", voltage);
525 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 }
David Keitelcf867232012-01-27 18:40:12 -0800527
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800528 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
529
530 remainder = voltage % 20;
531 if (remainder >= 10) {
532 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
533 }
534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700536 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537}
538
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700539static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
540{
541 u8 temp;
542 int rc;
543
544 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
545 if (rc) {
546 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700547 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700548 return rc;
549 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800550 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
551 + PM8921_CHG_V_MIN_MV;
552 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
553 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700554 return 0;
555}
556
David Keitelcf867232012-01-27 18:40:12 -0800557static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
558{
559 int current_mv, ret, steps, i;
560 bool increase;
561
562 ret = 0;
563
564 if (voltage < PM8921_CHG_VDDMAX_MIN
565 || voltage > PM8921_CHG_VDDMAX_MAX) {
566 pr_err("bad mV=%d asked to set\n", voltage);
567 return -EINVAL;
568 }
569
570 ret = pm_chg_vddmax_get(chip, &current_mv);
571 if (ret) {
572 pr_err("Failed to read vddmax rc=%d\n", ret);
573 return -EINVAL;
574 }
575 if (current_mv == voltage)
576 return 0;
577
578 /* Only change in increments when USB is present */
579 if (is_usb_chg_plugged_in(chip)) {
580 if (current_mv < voltage) {
581 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
582 increase = true;
583 } else {
584 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
585 increase = false;
586 }
587 for (i = 0; i < steps; i++) {
588 if (increase)
589 current_mv += PM8921_CHG_V_STEP_MV;
590 else
591 current_mv -= PM8921_CHG_V_STEP_MV;
592 ret |= __pm_chg_vddmax_set(chip, current_mv);
593 }
594 }
595 ret |= __pm_chg_vddmax_set(chip, voltage);
596 return ret;
597}
598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599#define PM8921_CHG_VDDSAFE_MIN 3400
600#define PM8921_CHG_VDDSAFE_MAX 4500
601static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
602{
603 u8 temp;
604
605 if (voltage < PM8921_CHG_VDDSAFE_MIN
606 || voltage > PM8921_CHG_VDDSAFE_MAX) {
607 pr_err("bad mV=%d asked to set\n", voltage);
608 return -EINVAL;
609 }
610 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
611 pr_debug("voltage=%d setting %02x\n", voltage, temp);
612 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
613}
614
615#define PM8921_CHG_VBATDET_MIN 3240
616#define PM8921_CHG_VBATDET_MAX 5780
617static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
618{
619 u8 temp;
620
621 if (voltage < PM8921_CHG_VBATDET_MIN
622 || voltage > PM8921_CHG_VBATDET_MAX) {
623 pr_err("bad mV=%d asked to set\n", voltage);
624 return -EINVAL;
625 }
626 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
627 pr_debug("voltage=%d setting %02x\n", voltage, temp);
628 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
629}
630
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700631#define PM8921_CHG_VINMIN_MIN_MV 3800
632#define PM8921_CHG_VINMIN_STEP_MV 100
633#define PM8921_CHG_VINMIN_USABLE_MAX 6500
634#define PM8921_CHG_VINMIN_USABLE_MIN 4300
635#define PM8921_CHG_VINMIN_MASK 0x1F
636static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
637{
638 u8 temp;
639
640 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
641 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
642 pr_err("bad mV=%d asked to set\n", voltage);
643 return -EINVAL;
644 }
645 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
646 pr_debug("voltage=%d setting %02x\n", voltage, temp);
647 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
648 temp);
649}
650
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800651static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
652{
653 u8 temp;
654 int rc, voltage_mv;
655
656 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
657 temp &= PM8921_CHG_VINMIN_MASK;
658
659 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
660 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
661
662 return voltage_mv;
663}
664
David Keitel0789fc62012-06-07 17:43:27 -0700665#define PM8917_USB_UVD_MIN_MV 3850
666#define PM8917_USB_UVD_MAX_MV 4350
667#define PM8917_USB_UVD_STEP_MV 100
668#define PM8917_USB_UVD_MASK 0x7
669static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
670{
671 u8 temp;
672
673 if (thresh_mv < PM8917_USB_UVD_MIN_MV
674 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
675 pr_err("bad mV=%d asked to set\n", thresh_mv);
676 return -EINVAL;
677 }
678 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
679 return pm_chg_masked_write(chip, OVP_USB_UVD,
680 PM8917_USB_UVD_MASK, temp);
681}
682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700684#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685#define PM8921_CHG_I_MIN_MA 225
686#define PM8921_CHG_I_STEP_MA 50
687#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700688static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
689{
690 u8 temp;
691 int rc;
692
693 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
694 if (rc) {
695 pr_err("rc = %d while reading ibat max\n", rc);
696 *ibat_ma = 0;
697 return rc;
698 }
699 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
700 + PM8921_CHG_I_MIN_MA;
701 return 0;
702}
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
705{
706 u8 temp;
707
708 if (chg_current < PM8921_CHG_IBATMAX_MIN
709 || chg_current > PM8921_CHG_IBATMAX_MAX) {
710 pr_err("bad mA=%d asked to set\n", chg_current);
711 return -EINVAL;
712 }
713 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
714 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
715}
716
717#define PM8921_CHG_IBATSAFE_MIN 225
718#define PM8921_CHG_IBATSAFE_MAX 3375
719static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
720{
721 u8 temp;
722
723 if (chg_current < PM8921_CHG_IBATSAFE_MIN
724 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
725 pr_err("bad mA=%d asked to set\n", chg_current);
726 return -EINVAL;
727 }
728 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
729 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
730 PM8921_CHG_I_MASK, temp);
731}
732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700734#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735#define PM8921_CHG_ITERM_STEP_MA 10
736#define PM8921_CHG_ITERM_MASK 0xF
737static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
738{
739 u8 temp;
740
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700741 if (chg_current < PM8921_CHG_ITERM_MIN_MA
742 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 pr_err("bad mA=%d asked to set\n", chg_current);
744 return -EINVAL;
745 }
746
747 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
748 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700749 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 temp);
751}
752
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700753static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
754{
755 u8 temp;
756 int rc;
757
758 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
759 if (rc) {
760 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700761 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700762 return rc;
763 }
764 temp &= PM8921_CHG_ITERM_MASK;
765 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
766 + PM8921_CHG_ITERM_MIN_MA;
767 return 0;
768}
769
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800770struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700771 int usb_ma;
772 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800773};
774
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700775/* USB Trim tables */
776static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
777 0x0,
778 0x0,
779 -0x9,
780 0x0,
781 -0xD,
782 0x0,
783 -0x10,
784 -0x11,
785 0x0,
786 0x0,
787 -0x25,
788 0x0,
789 -0x28,
790 0x0,
791 -0x32,
792 0x0
793};
794
795static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
796 0x0,
797 0x0,
798 0xA,
799 0xC,
800 0x10,
801 0x10,
802 0x13,
803 0x14,
804 0x13,
805 0x3,
806 0x1A,
807 0x1D,
808 0x1D,
809 0x21,
810 0x24,
811 0x26
812};
813
814/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800815static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700816 {100, 0x0},
817 {200, 0x1},
818 {500, 0x2},
819 {600, 0x3},
820 {700, 0x4},
821 {800, 0x5},
822 {850, 0x6},
823 {900, 0x8},
824 {950, 0x7},
825 {1000, 0x9},
826 {1100, 0xA},
827 {1200, 0xB},
828 {1300, 0xC},
829 {1400, 0xD},
830 {1500, 0xE},
831 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800832};
833
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700834#define REG_SBI_CONFIG 0x04F
835#define PAGE3_ENABLE_MASK 0x6
836#define USB_OVP_TRIM_MASK 0x3F
837#define USB_OVP_TRIM_PM8917_MASK 0x7F
838#define USB_OVP_TRIM_MIN 0x00
839#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
840#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
841#define REG_USB_OVP_TRIM_PM8917 0x2B5
842#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
843static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
844{
845 u8 temp, sbi_config, msb, lsb, mask;
846 s8 trim;
847 int rc = 0;
848 static u8 usb_trim_reg_orig = 0xFF;
849
850 /* No trim data for PM8921 */
851 if (!chip->usb_trim_table)
852 return 0;
853
854 if (usb_trim_reg_orig == 0xFF) {
855 rc = pm8xxx_readb(chip->dev->parent,
856 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
857 if (rc) {
858 pr_err("error = %d reading sbi config reg\n", rc);
859 return rc;
860 }
861
862 rc = pm8xxx_readb(chip->dev->parent,
863 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
864 if (rc) {
865 pr_err("error = %d reading sbi config reg\n", rc);
866 return rc;
867 }
868
869 msb = msb >> 5;
870 lsb = lsb >> 5;
871 usb_trim_reg_orig = msb << 3 | lsb;
872
873 if (pm8xxx_get_version(chip->dev->parent)
874 == PM8XXX_VERSION_8917) {
875 rc = pm8xxx_readb(chip->dev->parent,
876 REG_USB_OVP_TRIM_PM8917, &msb);
877 if (rc) {
878 pr_err("error = %d reading config reg\n", rc);
879 return rc;
880 }
881
882 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
883 usb_trim_reg_orig |= msb << 6;
884 }
885 }
886
887 /* use the original trim value */
888 trim = usb_trim_reg_orig;
889
890 trim += chip->usb_trim_table[index];
891 if (trim < 0)
892 trim = 0;
893
894 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
895 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
896
897 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
898 if (rc) {
899 pr_err("error = %d reading sbi config reg\n", rc);
900 return rc;
901 }
902
903 temp = sbi_config | PAGE3_ENABLE_MASK;
904 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
905 if (rc) {
906 pr_err("error = %d writing sbi config reg\n", rc);
907 return rc;
908 }
909
910 mask = USB_OVP_TRIM_MASK;
911
912 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
913 mask = USB_OVP_TRIM_PM8917_MASK;
914
915 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
916 if (rc) {
917 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
918 return rc;
919 }
920
921 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
922 if (rc) {
923 pr_err("error = %d writing sbi config reg\n", rc);
924 return rc;
925 }
926 return rc;
927}
928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700930#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931#define PM8921_CHG_IUSB_MAX 7
932#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700933#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700934static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700936 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700937 int rc;
938
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700939 reg_val = usb_ma_table[index].value >> 1;
940 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700942 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
943 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 return -EINVAL;
945 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700946 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
947
948 /* IUSB_FINE_RES */
949 if (chip->iusb_fine_res) {
950 /* Clear IUSB_FINE_RES bit to avoid overshoot */
951 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
952 PM8917_IUSB_FINE_RES, 0);
953
954 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
955 PM8921_CHG_IUSB_MASK, temp);
956
957 if (rc) {
958 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
959 return rc;
960 }
961
962 if (fineres) {
963 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
964 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700965 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700966 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
967 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700968 return rc;
969 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700970 }
971 } else {
972 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
973 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700974 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700975 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700976 return rc;
977 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700978 }
979
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700980 rc = pm_chg_usb_trim(chip, index);
981 if (rc)
982 pr_err("unable to set usb trim rc = %d\n", rc);
983
David Keitel38bdd4f2012-04-19 15:39:13 -0700984 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985}
986
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800987static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
988{
David Keitel38bdd4f2012-04-19 15:39:13 -0700989 u8 temp, fineres;
990 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800991
David Keitel38bdd4f2012-04-19 15:39:13 -0700992 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800993 *mA = 0;
994 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
995 if (rc) {
996 pr_err("err=%d reading PBL_ACCESS2\n", rc);
997 return rc;
998 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700999
1000 if (chip->iusb_fine_res) {
1001 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1002 if (rc) {
1003 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1004 return rc;
1005 }
1006 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001007 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001008 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1009
1010 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1011 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1012 if (usb_ma_table[i].value == temp)
1013 break;
1014 }
1015
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001016 if (i < 0) {
1017 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1018 i = 0;
1019 }
1020
David Keitel38bdd4f2012-04-19 15:39:13 -07001021 *mA = usb_ma_table[i].usb_ma;
1022
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001023 return rc;
1024}
1025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026#define PM8921_CHG_WD_MASK 0x1F
1027static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1028{
1029 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001030 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1031}
1032
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001033#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001034#define PM8921_CHG_TCHG_MIN 4
1035#define PM8921_CHG_TCHG_MAX 512
1036#define PM8921_CHG_TCHG_STEP 4
1037static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1038{
1039 u8 temp;
1040
1041 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1042 pr_err("bad max minutes =%d asked to set\n", minutes);
1043 return -EINVAL;
1044 }
1045
1046 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1047 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1048 temp);
1049}
1050
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001051#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001052#define PM8921_CHG_TTRKL_MIN 1
1053#define PM8921_CHG_TTRKL_MAX 64
1054static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1055{
1056 u8 temp;
1057
1058 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1059 pr_err("bad max minutes =%d asked to set\n", minutes);
1060 return -EINVAL;
1061 }
1062
1063 temp = minutes - 1;
1064 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1065 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066}
1067
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001068#define PM8921_CHG_VTRKL_MIN_MV 2050
1069#define PM8921_CHG_VTRKL_MAX_MV 2800
1070#define PM8921_CHG_VTRKL_STEP_MV 50
1071#define PM8921_CHG_VTRKL_SHIFT 4
1072#define PM8921_CHG_VTRKL_MASK 0xF0
1073static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1074{
1075 u8 temp;
1076
1077 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1078 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1079 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1080 return -EINVAL;
1081 }
1082
1083 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1084 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1085 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1086 temp);
1087}
1088
1089#define PM8921_CHG_VWEAK_MIN_MV 2100
1090#define PM8921_CHG_VWEAK_MAX_MV 3600
1091#define PM8921_CHG_VWEAK_STEP_MV 100
1092#define PM8921_CHG_VWEAK_MASK 0x0F
1093static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1094{
1095 u8 temp;
1096
1097 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1098 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1099 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1100 return -EINVAL;
1101 }
1102
1103 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1104 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1105 temp);
1106}
1107
1108#define PM8921_CHG_ITRKL_MIN_MA 50
1109#define PM8921_CHG_ITRKL_MAX_MA 200
1110#define PM8921_CHG_ITRKL_MASK 0x0F
1111#define PM8921_CHG_ITRKL_STEP_MA 10
1112static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1113{
1114 u8 temp;
1115
1116 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1117 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1118 pr_err("bad current = %dmA asked to set\n", milliamps);
1119 return -EINVAL;
1120 }
1121
1122 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1123
1124 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1125 temp);
1126}
1127
1128#define PM8921_CHG_IWEAK_MIN_MA 325
1129#define PM8921_CHG_IWEAK_MAX_MA 525
1130#define PM8921_CHG_IWEAK_SHIFT 7
1131#define PM8921_CHG_IWEAK_MASK 0x80
1132static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1133{
1134 u8 temp;
1135
1136 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1137 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1138 pr_err("bad current = %dmA asked to set\n", milliamps);
1139 return -EINVAL;
1140 }
1141
1142 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1143 temp = 0;
1144 else
1145 temp = 1;
1146
1147 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1148 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1149 temp);
1150}
1151
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001152#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1153#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1154static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1155 enum pm8921_chg_cold_thr cold_thr)
1156{
1157 u8 temp;
1158
1159 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1160 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1161 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1162 PM8921_CHG_BATT_TEMP_THR_COLD,
1163 temp);
1164}
1165
1166#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1167#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1168static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1169 enum pm8921_chg_hot_thr hot_thr)
1170{
1171 u8 temp;
1172
1173 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1174 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1175 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1176 PM8921_CHG_BATT_TEMP_THR_HOT,
1177 temp);
1178}
1179
Jay Chokshid674a512012-03-15 14:06:04 -07001180#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1181#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1182static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1183 enum pm8921_chg_led_src_config led_src_config)
1184{
1185 u8 temp;
1186
1187 if (led_src_config < LED_SRC_GND ||
1188 led_src_config > LED_SRC_BYPASS)
1189 return -EINVAL;
1190
1191 if (led_src_config == LED_SRC_BYPASS)
1192 return 0;
1193
1194 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1195
1196 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1197 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1198}
1199
David Keitel8c5201a2012-02-24 16:08:54 -08001200
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001201static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1202{
1203 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001204 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001205
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001206 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001207 if (rc) {
1208 pr_err("error reading batt id channel = %d, rc = %d\n",
1209 chip->vbat_channel, rc);
1210 return rc;
1211 }
1212 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1213 result.measurement);
1214 return result.physical;
1215}
1216
1217static int is_battery_valid(struct pm8921_chg_chip *chip)
1218{
1219 int64_t rc;
1220
1221 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1222 return 1;
1223
1224 rc = read_battery_id(chip);
1225 if (rc < 0) {
1226 pr_err("error reading batt id channel = %d, rc = %lld\n",
1227 chip->vbat_channel, rc);
1228 /* assume battery id is valid when adc error happens */
1229 return 1;
1230 }
1231
1232 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1233 pr_err("batt_id phy =%lld is not valid\n", rc);
1234 return 0;
1235 }
1236 return 1;
1237}
1238
1239static void check_battery_valid(struct pm8921_chg_chip *chip)
1240{
1241 if (is_battery_valid(chip) == 0) {
1242 pr_err("batt_id not valid, disbling charging\n");
1243 pm_chg_auto_enable(chip, 0);
1244 } else {
1245 pm_chg_auto_enable(chip, !charging_disabled);
1246 }
1247}
1248
1249static void battery_id_valid(struct work_struct *work)
1250{
1251 struct pm8921_chg_chip *chip = container_of(work,
1252 struct pm8921_chg_chip, battery_id_valid_work);
1253
1254 check_battery_valid(chip);
1255}
1256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1258{
1259 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1260 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1261 enable_irq(chip->pmic_chg_irq[interrupt]);
1262 }
1263}
1264
1265static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1266{
1267 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1268 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1269 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1270 }
1271}
1272
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001273static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1274{
1275 return test_bit(interrupt, chip->enabled_irqs);
1276}
1277
Amir Samuelovd31ef502011-10-26 14:41:36 +02001278static bool is_ext_charging(struct pm8921_chg_chip *chip)
1279{
David Keitel88e1b572012-01-11 11:57:14 -08001280 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001281
David Keitel88e1b572012-01-11 11:57:14 -08001282 if (!chip->ext_psy)
1283 return false;
1284 if (chip->ext_psy->get_property(chip->ext_psy,
1285 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1286 return false;
1287 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1288 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001289
1290 return false;
1291}
1292
1293static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1294{
David Keitel88e1b572012-01-11 11:57:14 -08001295 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001296
David Keitel88e1b572012-01-11 11:57:14 -08001297 if (!chip->ext_psy)
1298 return false;
1299 if (chip->ext_psy->get_property(chip->ext_psy,
1300 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1301 return false;
1302 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001303 return true;
1304
1305 return false;
1306}
1307
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308static int is_battery_charging(int fsm_state)
1309{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001310 if (is_ext_charging(the_chip))
1311 return 1;
1312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 switch (fsm_state) {
1314 case FSM_STATE_ATC_2A:
1315 case FSM_STATE_ATC_2B:
1316 case FSM_STATE_ON_CHG_AND_BAT_6:
1317 case FSM_STATE_FAST_CHG_7:
1318 case FSM_STATE_TRKL_CHG_8:
1319 return 1;
1320 }
1321 return 0;
1322}
1323
1324static void bms_notify(struct work_struct *work)
1325{
1326 struct bms_notify *n = container_of(work, struct bms_notify, work);
1327
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001328 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001330 } else {
1331 pm8921_bms_charging_end(n->is_battery_full);
1332 n->is_battery_full = 0;
1333 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334}
1335
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001336static void bms_notify_check(struct pm8921_chg_chip *chip)
1337{
1338 int fsm_state, new_is_charging;
1339
1340 fsm_state = pm_chg_get_fsm_state(chip);
1341 new_is_charging = is_battery_charging(fsm_state);
1342
1343 if (chip->bms_notify.is_charging ^ new_is_charging) {
1344 chip->bms_notify.is_charging = new_is_charging;
1345 schedule_work(&(chip->bms_notify.work));
1346 }
1347}
1348
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001349static enum power_supply_property pm_power_props_usb[] = {
1350 POWER_SUPPLY_PROP_PRESENT,
1351 POWER_SUPPLY_PROP_ONLINE,
1352 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001353 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001354 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001355};
1356
1357static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001359 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360};
1361
1362static char *pm_power_supplied_to[] = {
1363 "battery",
1364};
1365
David Keitel6ed71a52012-01-30 12:42:18 -08001366#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001367static int pm_power_get_property_mains(struct power_supply *psy,
1368 enum power_supply_property psp,
1369 union power_supply_propval *val)
1370{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001371 int type;
1372
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001373 /* Check if called before init */
1374 if (!the_chip)
1375 return -EINVAL;
1376
1377 switch (psp) {
1378 case POWER_SUPPLY_PROP_PRESENT:
1379 case POWER_SUPPLY_PROP_ONLINE:
1380 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001381
1382 if (the_chip->has_dc_supply) {
1383 val->intval = 1;
1384 return 0;
1385 }
1386
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001387 if (the_chip->dc_present) {
1388 val->intval = 1;
1389 return 0;
1390 }
1391
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301392 type = the_chip->usb_type;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001393 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1394 type == POWER_SUPPLY_TYPE_USB_ACA ||
1395 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001396 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001397
1398 break;
1399 default:
1400 return -EINVAL;
1401 }
1402 return 0;
1403}
1404
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001405static int disable_aicl(int disable)
1406{
1407 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1408 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1409 pr_err("called with invalid param :%d\n", disable);
1410 return -EINVAL;
1411 }
1412
1413 if (!the_chip) {
1414 pr_err("%s called before init\n", __func__);
1415 return -EINVAL;
1416 }
1417
1418 pr_debug("Disable AICL = %d\n", disable);
1419 the_chip->disable_aicl = disable;
1420 return 0;
1421}
1422
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001423static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1424{
1425 int rc;
1426
1427 if (!chip->host_mode)
1428 return 0;
1429
1430 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001431 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001432 if (rc < 0) {
1433 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1434 return rc;
1435 }
1436
1437 chip->host_mode = 0;
1438
1439 return 0;
1440}
1441
1442static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1443{
1444 int rc;
1445
1446 if (chip->host_mode)
1447 return 0;
1448
1449 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001450 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001451 if (rc < 0) {
1452 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1453 return rc;
1454 }
1455
1456 chip->host_mode = 1;
1457
1458 return 0;
1459}
1460
1461static int pm_power_set_property_usb(struct power_supply *psy,
1462 enum power_supply_property psp,
1463 const union power_supply_propval *val)
1464{
1465 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001466 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001467 return -EINVAL;
1468
1469 switch (psp) {
1470 case POWER_SUPPLY_PROP_SCOPE:
1471 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001472 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001473 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001474 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001475 else
1476 return -EINVAL;
1477 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001478 case POWER_SUPPLY_PROP_TYPE:
1479 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001480 case POWER_SUPPLY_PROP_HEALTH:
1481 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1482 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001483 default:
1484 return -EINVAL;
1485 }
1486 return 0;
1487}
1488
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001489static int usb_property_is_writeable(struct power_supply *psy,
1490 enum power_supply_property psp)
1491{
1492 switch (psp) {
1493 case POWER_SUPPLY_PROP_HEALTH:
1494 return 1;
1495 default:
1496 break;
1497 }
1498
1499 return 0;
1500}
1501
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001502static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 enum power_supply_property psp,
1504 union power_supply_propval *val)
1505{
David Keitel6ed71a52012-01-30 12:42:18 -08001506 int current_max;
1507
1508 /* Check if called before init */
1509 if (!the_chip)
1510 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511
1512 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001513 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001514 if (pm_is_chg_charge_dis(the_chip)) {
1515 val->intval = 0;
1516 } else {
1517 pm_chg_iusbmax_get(the_chip, &current_max);
1518 val->intval = current_max;
1519 }
David Keitel6ed71a52012-01-30 12:42:18 -08001520 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001522 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001523 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001524
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301525 if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001526 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001529
1530 case POWER_SUPPLY_PROP_SCOPE:
1531 if (the_chip->host_mode)
1532 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1533 else
1534 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1535 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001536 case POWER_SUPPLY_PROP_HEALTH:
1537 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1538 val->intval = the_chip->disable_aicl;
1539 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 default:
1541 return -EINVAL;
1542 }
1543 return 0;
1544}
1545
1546static enum power_supply_property msm_batt_power_props[] = {
1547 POWER_SUPPLY_PROP_STATUS,
1548 POWER_SUPPLY_PROP_CHARGE_TYPE,
1549 POWER_SUPPLY_PROP_HEALTH,
1550 POWER_SUPPLY_PROP_PRESENT,
1551 POWER_SUPPLY_PROP_TECHNOLOGY,
1552 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1553 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1554 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1555 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001556 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001557 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001558 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001559 POWER_SUPPLY_PROP_CHARGE_FULL,
1560 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561};
1562
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001563static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564{
1565 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001566 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001568 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 if (rc) {
1570 pr_err("error reading adc channel = %d, rc = %d\n",
1571 chip->vbat_channel, rc);
1572 return rc;
1573 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001574 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 result.measurement);
1576 return (int)result.physical;
1577}
1578
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301579static int voltage_based_capacity(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001580{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301581 int current_voltage_uv = get_prop_battery_uvolts(chip);
1582 int current_voltage_mv = current_voltage_uv / 1000;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001583 unsigned int low_voltage = chip->min_voltage_mv;
1584 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001585
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301586 if (current_voltage_uv < 0) {
1587 pr_err("Error reading current voltage\n");
1588 return -EIO;
1589 }
1590
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001591 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001592 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001593 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001594 return 100;
1595 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001596 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001597 / (high_voltage - low_voltage);
1598}
1599
David Keitel4f9397b2012-04-16 11:46:16 -07001600static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1601{
1602 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1603}
1604
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001605static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1606{
1607 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1608 int fsm_state = pm_chg_get_fsm_state(chip);
1609 int i;
1610
1611 if (chip->ext_psy) {
1612 if (chip->ext_charge_done)
1613 return POWER_SUPPLY_STATUS_FULL;
1614 if (chip->ext_charging)
1615 return POWER_SUPPLY_STATUS_CHARGING;
1616 }
1617
1618 for (i = 0; i < ARRAY_SIZE(map); i++)
1619 if (map[i].fsm_state == fsm_state)
1620 batt_state = map[i].batt_state;
1621
1622 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1623 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1624 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1625 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1626 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1627
1628 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1629 }
1630 return batt_state;
1631}
1632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1634{
David Keitel4f9397b2012-04-16 11:46:16 -07001635 int percent_soc;
1636
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001637 if (chip->battery_less_hardware)
1638 return 100;
1639
David Keitel4f9397b2012-04-16 11:46:16 -07001640 if (!get_prop_batt_present(chip))
1641 percent_soc = voltage_based_capacity(chip);
1642 else
1643 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001644
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001645 if (percent_soc == -ENXIO)
1646 percent_soc = voltage_based_capacity(chip);
1647
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301648 if (percent_soc < 0) {
1649 pr_err("Unable to read battery voltage\n");
1650 goto fail_voltage;
1651 }
1652
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001653 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001654 pr_warn_ratelimited("low battery charge = %d%%\n",
1655 percent_soc);
1656
1657 if (percent_soc <= chip->resume_charge_percent
1658 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1659 pr_debug("soc fell below %d. charging enabled.\n",
1660 chip->resume_charge_percent);
1661 if (chip->is_bat_warm)
1662 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1663 chip->is_bat_warm,
1664 chip->resume_charge_percent);
1665 else if (chip->is_bat_cool)
1666 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1667 chip->is_bat_cool,
1668 chip->resume_charge_percent);
1669 else
1670 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1671 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001672
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301673fail_voltage:
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001674 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001675 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676}
1677
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301678static int get_prop_batt_current_max(struct pm8921_chg_chip *chip, int *curr)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001679{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301680 *curr = 0;
1681 *curr = pm8921_bms_get_current_max();
1682 if (*curr == -EINVAL)
1683 return -EINVAL;
1684
1685 return 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001686}
1687
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301688static int get_prop_batt_current(struct pm8921_chg_chip *chip, int *curr)
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001689{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301690 int rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001691
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301692 *curr = 0;
1693 rc = pm8921_bms_get_battery_current(curr);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001694 if (rc == -ENXIO) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301695 rc = pm8xxx_ccadc_get_battery_current(curr);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001696 }
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301697 if (rc)
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001698 pr_err("unable to get batt current rc = %d\n", rc);
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301699
1700 return rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001701}
1702
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001703static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1704{
1705 int rc;
1706
1707 rc = pm8921_bms_get_fcc();
1708 if (rc < 0)
1709 pr_err("unable to get batt fcc rc = %d\n", rc);
1710 return rc;
1711}
1712
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301713static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip, int *cc_uah)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001714{
1715 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001716
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301717 *cc_uah = 0;
1718 rc = pm8921_bms_cc_uah(cc_uah);
1719 if (rc)
1720 pr_err("unable to get batt fcc rc = %d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001721
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001722 return rc;
1723}
1724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1726{
1727 int temp;
1728
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001729 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1730 if (temp)
1731 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001733 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1734 if (temp)
1735 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001737 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738}
1739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1741{
1742 int temp;
1743
Amir Samuelovd31ef502011-10-26 14:41:36 +02001744 if (!get_prop_batt_present(chip))
1745 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1746
1747 if (is_ext_trickle_charging(chip))
1748 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1749
1750 if (is_ext_charging(chip))
1751 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1754 if (temp)
1755 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1756
1757 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1758 if (temp)
1759 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1760
1761 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1762}
1763
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001764#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301765static int get_prop_batt_temp(struct pm8921_chg_chip *chip, int *temp)
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001766{
1767 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001768 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001769
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301770 if (chip->battery_less_hardware) {
1771 *temp = 300;
1772 return 0;
1773 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001774
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001775 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001776 if (rc) {
1777 pr_err("error reading adc channel = %d, rc = %d\n",
1778 chip->vbat_channel, rc);
1779 return rc;
1780 }
1781 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1782 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001783 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1784 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1785 (int) result.physical);
1786
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301787 *temp = (int)result.physical;
1788
1789 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001790}
1791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792static int pm_batt_power_get_property(struct power_supply *psy,
1793 enum power_supply_property psp,
1794 union power_supply_propval *val)
1795{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301796 int rc = 0;
1797 int value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001798 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1799 batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 switch (psp) {
1801 case POWER_SUPPLY_PROP_STATUS:
1802 val->intval = get_prop_batt_status(chip);
1803 break;
1804 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1805 val->intval = get_prop_charge_type(chip);
1806 break;
1807 case POWER_SUPPLY_PROP_HEALTH:
1808 val->intval = get_prop_batt_health(chip);
1809 break;
1810 case POWER_SUPPLY_PROP_PRESENT:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301811 rc = get_prop_batt_present(chip);
1812 if (rc >= 0) {
1813 val->intval = rc;
1814 rc = 0;
1815 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001816 break;
1817 case POWER_SUPPLY_PROP_TECHNOLOGY:
1818 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1819 break;
1820 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001821 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001822 break;
1823 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001824 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 break;
1826 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301827 rc = get_prop_battery_uvolts(chip);
1828 if (rc >= 0) {
1829 val->intval = rc;
1830 rc = 0;
1831 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 break;
1833 case POWER_SUPPLY_PROP_CAPACITY:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301834 rc = get_prop_batt_capacity(chip);
1835 if (rc >= 0) {
1836 val->intval = rc;
1837 rc = 0;
1838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001840 case POWER_SUPPLY_PROP_CURRENT_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301841 rc = get_prop_batt_current(chip, &value);
1842 if (!rc)
1843 val->intval = value;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001844 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001845 case POWER_SUPPLY_PROP_CURRENT_MAX:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301846 rc = get_prop_batt_current_max(chip, &value);
1847 if (!rc)
1848 val->intval = value;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001849 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001850 case POWER_SUPPLY_PROP_TEMP:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301851 rc = get_prop_batt_temp(chip, &value);
1852 if (!rc)
1853 val->intval = value;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001854 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001855 case POWER_SUPPLY_PROP_CHARGE_FULL:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301856 rc = get_prop_batt_fcc(chip);
1857 if (rc >= 0) {
1858 val->intval = rc;
1859 rc = 0;
1860 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001861 break;
1862 case POWER_SUPPLY_PROP_CHARGE_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301863 rc = get_prop_batt_charge_now(chip, &value);
1864 if (!rc) {
1865 val->intval = value;
1866 rc = 0;
1867 }
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001868 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 default:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301870 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 }
1872
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301873 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874}
1875
1876static void (*notify_vbus_state_func_ptr)(int);
1877static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878
1879int pm8921_charger_register_vbus_sn(void (*callback)(int))
1880{
1881 pr_debug("%p\n", callback);
1882 notify_vbus_state_func_ptr = callback;
1883 return 0;
1884}
1885EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1886
1887/* this is passed to the hsusb via platform_data msm_otg_pdata */
1888void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1889{
1890 pr_debug("%p\n", callback);
1891 notify_vbus_state_func_ptr = NULL;
1892}
1893EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1894
1895static void notify_usb_of_the_plugin_event(int plugin)
1896{
1897 plugin = !!plugin;
1898 if (notify_vbus_state_func_ptr) {
1899 pr_debug("notifying plugin\n");
1900 (*notify_vbus_state_func_ptr) (plugin);
1901 } else {
1902 pr_debug("unable to notify plugin\n");
1903 }
1904}
1905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906static void __pm8921_charger_vbus_draw(unsigned int mA)
1907{
1908 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001909 if (!the_chip) {
1910 pr_err("called before init\n");
1911 return;
1912 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001914 if (usb_max_current && mA > usb_max_current) {
1915 pr_debug("restricting usb current to %d instead of %d\n",
1916 usb_max_current, mA);
1917 mA = usb_max_current;
1918 }
1919
1920 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001922 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001924 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 }
1926 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1927 if (rc)
1928 pr_err("fail to set suspend bit rc=%d\n", rc);
1929 } else {
1930 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1931 if (rc)
1932 pr_err("fail to reset suspend bit rc=%d\n", rc);
1933 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1934 if (usb_ma_table[i].usb_ma <= mA)
1935 break;
1936 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001937
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001938 if (i < 0) {
1939 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1940 mA);
1941 i = 0;
1942 }
1943
David Keitel38bdd4f2012-04-19 15:39:13 -07001944 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001945 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001946 && !the_chip->iusb_fine_res)
1947 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 if (i < 0)
1949 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001950 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001951 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001952 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 }
1954}
1955
1956/* USB calls these to tell us how much max usb current the system can draw */
1957void pm8921_charger_vbus_draw(unsigned int mA)
1958{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001959 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001960
1961 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001962
David Keitel62c6a4b2012-05-17 12:54:59 -07001963 /*
1964 * Reject VBUS requests if USB connection is the only available
1965 * power source. This makes sure that if booting without
1966 * battery the iusb_max value is not decreased avoiding potential
1967 * brown_outs.
1968 *
1969 * This would also apply when the battery has been
1970 * removed from the running system.
1971 */
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001972 if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07001973 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001974 if (!the_chip->has_dc_supply) {
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001975 pr_err("rejected: no other power source mA = %d\n", mA);
David Keitelff4f9ce2012-08-24 15:11:23 -07001976 return;
1977 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001978 }
1979
David Keitelacf57c82012-03-07 18:48:50 -08001980 if (usb_max_current && mA > usb_max_current) {
1981 pr_warn("restricting usb current to %d instead of %d\n",
1982 usb_max_current, mA);
1983 mA = usb_max_current;
1984 }
Devin Kim2073afb2012-09-05 13:01:51 -07001985 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1986 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001987
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301988 if (usb_target_ma)
1989 usb_target_ma = mA;
1990
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001991
1992 if (mA > USB_WALL_THRESHOLD_MA)
1993 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
1994 else
1995 set_usb_now_ma = mA;
1996
1997 if (the_chip && the_chip->disable_aicl)
1998 set_usb_now_ma = mA;
1999
2000 if (the_chip)
2001 __pm8921_charger_vbus_draw(set_usb_now_ma);
2002 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 /*
2004 * called before pmic initialized,
2005 * save this value and use it at probe
2006 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002007 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008}
2009EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
2010
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002011int pm8921_is_usb_chg_plugged_in(void)
2012{
2013 if (!the_chip) {
2014 pr_err("called before init\n");
2015 return -EINVAL;
2016 }
2017 return is_usb_chg_plugged_in(the_chip);
2018}
2019EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
2020
2021int pm8921_is_dc_chg_plugged_in(void)
2022{
2023 if (!the_chip) {
2024 pr_err("called before init\n");
2025 return -EINVAL;
2026 }
2027 return is_dc_chg_plugged_in(the_chip);
2028}
2029EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
2030
2031int pm8921_is_battery_present(void)
2032{
2033 if (!the_chip) {
2034 pr_err("called before init\n");
2035 return -EINVAL;
2036 }
2037 return get_prop_batt_present(the_chip);
2038}
2039EXPORT_SYMBOL(pm8921_is_battery_present);
2040
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002041int pm8921_is_batfet_closed(void)
2042{
2043 if (!the_chip) {
2044 pr_err("called before init\n");
2045 return -EINVAL;
2046 }
2047 return is_batfet_closed(the_chip);
2048}
2049EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002050/*
2051 * Disabling the charge current limit causes current
2052 * current limits to have no monitoring. An adequate charger
2053 * capable of supplying high current while sustaining VIN_MIN
2054 * is required if the limiting is disabled.
2055 */
2056int pm8921_disable_input_current_limit(bool disable)
2057{
2058 if (!the_chip) {
2059 pr_err("called before init\n");
2060 return -EINVAL;
2061 }
2062 if (disable) {
2063 pr_warn("Disabling input current limit!\n");
2064
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002065 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002066 }
2067 return 0;
2068}
2069EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2070
David Keitel0789fc62012-06-07 17:43:27 -07002071int pm8917_set_under_voltage_detection_threshold(int mv)
2072{
2073 if (!the_chip) {
2074 pr_err("called before init\n");
2075 return -EINVAL;
2076 }
2077 return pm_chg_uvd_threshold_set(the_chip, mv);
2078}
2079EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2080
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002081int pm8921_set_max_battery_charge_current(int ma)
2082{
2083 if (!the_chip) {
2084 pr_err("called before init\n");
2085 return -EINVAL;
2086 }
2087 return pm_chg_ibatmax_set(the_chip, ma);
2088}
2089EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2090
2091int pm8921_disable_source_current(bool disable)
2092{
2093 if (!the_chip) {
2094 pr_err("called before init\n");
2095 return -EINVAL;
2096 }
2097 if (disable)
2098 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002099
2100 pm_chg_usb_suspend_enable(the_chip, disable);
2101
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002102 return pm_chg_charge_dis(the_chip, disable);
2103}
2104EXPORT_SYMBOL(pm8921_disable_source_current);
2105
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002106int pm8921_regulate_input_voltage(int voltage)
2107{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002108 int rc;
2109
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002110 if (!the_chip) {
2111 pr_err("called before init\n");
2112 return -EINVAL;
2113 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002114 rc = pm_chg_vinmin_set(the_chip, voltage);
2115
2116 if (rc == 0)
2117 the_chip->vin_min = voltage;
2118
2119 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002120}
2121
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002122#define USB_OV_THRESHOLD_MASK 0x60
2123#define USB_OV_THRESHOLD_SHIFT 5
2124int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2125{
2126 u8 temp;
2127
2128 if (!the_chip) {
2129 pr_err("called before init\n");
2130 return -EINVAL;
2131 }
2132
2133 if (ov > PM_USB_OV_7V) {
2134 pr_err("limiting to over voltage threshold to 7volts\n");
2135 ov = PM_USB_OV_7V;
2136 }
2137
2138 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2139
2140 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2141 USB_OV_THRESHOLD_MASK, temp);
2142}
2143EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2144
2145#define USB_DEBOUNCE_TIME_MASK 0x06
2146#define USB_DEBOUNCE_TIME_SHIFT 1
2147int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2148{
2149 u8 temp;
2150
2151 if (!the_chip) {
2152 pr_err("called before init\n");
2153 return -EINVAL;
2154 }
2155
2156 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2157 pr_err("limiting debounce to 80.5ms\n");
2158 ms = PM_USB_DEBOUNCE_80P5MS;
2159 }
2160
2161 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2162
2163 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2164 USB_DEBOUNCE_TIME_MASK, temp);
2165}
2166EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2167
2168#define USB_OVP_DISABLE_MASK 0x80
2169int pm8921_usb_ovp_disable(int disable)
2170{
2171 u8 temp = 0;
2172
2173 if (!the_chip) {
2174 pr_err("called before init\n");
2175 return -EINVAL;
2176 }
2177
2178 if (disable)
2179 temp = USB_OVP_DISABLE_MASK;
2180
2181 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2182 USB_OVP_DISABLE_MASK, temp);
2183}
2184
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002185bool pm8921_is_battery_charging(int *source)
2186{
2187 int fsm_state, is_charging, dc_present, usb_present;
2188
2189 if (!the_chip) {
2190 pr_err("called before init\n");
2191 return -EINVAL;
2192 }
2193 fsm_state = pm_chg_get_fsm_state(the_chip);
2194 is_charging = is_battery_charging(fsm_state);
2195 if (is_charging == 0) {
2196 *source = PM8921_CHG_SRC_NONE;
2197 return is_charging;
2198 }
2199
2200 if (source == NULL)
2201 return is_charging;
2202
2203 /* the battery is charging, the source is requested, find it */
2204 dc_present = is_dc_chg_plugged_in(the_chip);
2205 usb_present = is_usb_chg_plugged_in(the_chip);
2206
2207 if (dc_present && !usb_present)
2208 *source = PM8921_CHG_SRC_DC;
2209
2210 if (usb_present && !dc_present)
2211 *source = PM8921_CHG_SRC_USB;
2212
2213 if (usb_present && dc_present)
2214 /*
2215 * The system always chooses dc for charging since it has
2216 * higher priority.
2217 */
2218 *source = PM8921_CHG_SRC_DC;
2219
2220 return is_charging;
2221}
2222EXPORT_SYMBOL(pm8921_is_battery_charging);
2223
David Keitel86034022012-04-18 12:33:58 -07002224int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2225{
2226 if (!the_chip) {
2227 pr_err("called before init\n");
2228 return -EINVAL;
2229 }
2230
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002231 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002232 return -EINVAL;
2233
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05302234 the_chip->usb_type = type;
David Keitel86034022012-04-18 12:33:58 -07002235 power_supply_changed(&the_chip->usb_psy);
2236 power_supply_changed(&the_chip->dc_psy);
2237 return 0;
2238}
2239EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2240
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002241int pm8921_batt_temperature(void)
2242{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302243 int temp = 0, rc = 0;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002244 if (!the_chip) {
2245 pr_err("called before init\n");
2246 return -EINVAL;
2247 }
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302248 rc = get_prop_batt_temp(the_chip, &temp);
2249 if (rc) {
2250 pr_err("Unable to read temperature");
2251 return rc;
2252 }
2253 return temp;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002254}
2255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2257{
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08002258 int usb_present;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002260 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 usb_present = is_usb_chg_plugged_in(chip);
2262 if (chip->usb_present ^ usb_present) {
2263 notify_usb_of_the_plugin_event(usb_present);
2264 chip->usb_present = usb_present;
2265 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002266 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002267 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002269 if (usb_present) {
2270 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002271 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002272 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2273 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002274 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002275 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002276 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002277 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002278 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279}
2280
Amir Samuelovd31ef502011-10-26 14:41:36 +02002281static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2282{
David Keitel88e1b572012-01-11 11:57:14 -08002283 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002284 pr_debug("external charger not registered.\n");
2285 return;
2286 }
2287
2288 if (!chip->ext_charging) {
2289 pr_debug("already not charging.\n");
2290 return;
2291 }
2292
David Keitel88e1b572012-01-11 11:57:14 -08002293 power_supply_set_charge_type(chip->ext_psy,
2294 POWER_SUPPLY_CHARGE_TYPE_NONE);
2295 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002296 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002297 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002298 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002299 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002300 /* Update battery charging LEDs and user space battery info */
2301 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002302}
2303
2304static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2305{
2306 int dc_present;
2307 int batt_present;
2308 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002309 unsigned long delay =
2310 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2311
David Keitel88e1b572012-01-11 11:57:14 -08002312 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002313 pr_debug("external charger not registered.\n");
2314 return;
2315 }
2316
2317 if (chip->ext_charging) {
2318 pr_debug("already charging.\n");
2319 return;
2320 }
2321
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002322 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002323 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2324 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002325
2326 if (!dc_present) {
2327 pr_warn("%s. dc not present.\n", __func__);
2328 return;
2329 }
2330 if (!batt_present) {
2331 pr_warn("%s. battery not present.\n", __func__);
2332 return;
2333 }
2334 if (!batt_temp_ok) {
2335 pr_warn("%s. battery temperature not ok.\n", __func__);
2336 return;
2337 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002338
2339 /* Force BATFET=ON */
2340 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002341
David Keitel6ccbf132012-05-30 14:21:24 -07002342 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002343 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002344
David Keitel63f71662012-02-08 20:30:00 -08002345 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002346 power_supply_set_charge_type(chip->ext_psy,
2347 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002348 chip->ext_charging = true;
2349 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002350 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002351 /*
2352 * since we wont get a fastchg irq from external charger
2353 * use eoc worker to detect end of charging
2354 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002355 schedule_delayed_work(&chip->eoc_work, delay);
2356 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002357 if (chip->btc_override)
2358 schedule_delayed_work(&chip->btc_override_work,
2359 round_jiffies_relative(msecs_to_jiffies
2360 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002361 /* Update battery charging LEDs and user space battery info */
2362 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002363}
2364
David Keitel6ccbf132012-05-30 14:21:24 -07002365static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002366{
2367 u8 temp;
2368 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002369
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002370 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002371 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002372 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002373 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002374 }
David Keitel6ccbf132012-05-30 14:21:24 -07002375 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002376 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002377 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002378 return;
2379 }
2380 /* set ovp fet disable bit and the write bit */
2381 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002382 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002383 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002384 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002385 return;
2386 }
2387}
2388
David Keitel6ccbf132012-05-30 14:21:24 -07002389static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002390{
2391 u8 temp;
2392 int rc;
2393
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002394 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002395 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002396 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002397 return;
2398 }
David Keitel6ccbf132012-05-30 14:21:24 -07002399 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002400 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002401 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002402 return;
2403 }
2404 /* unset ovp fet disable bit and set the write bit */
2405 temp &= 0xFE;
2406 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002407 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002408 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002409 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002410 temp, rc);
2411 return;
2412 }
2413}
2414
2415static int param_open_ovp_counter = 10;
2416module_param(param_open_ovp_counter, int, 0644);
2417
David Keitel6ccbf132012-05-30 14:21:24 -07002418#define USB_ACTIVE_BIT BIT(5)
2419#define DC_ACTIVE_BIT BIT(6)
2420static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2421 u8 active_chg_mask)
2422{
2423 if (active_chg_mask & USB_ACTIVE_BIT)
2424 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2425 else if (active_chg_mask & DC_ACTIVE_BIT)
2426 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2427 else
2428 return 0;
2429}
2430
David Keitel8c5201a2012-02-24 16:08:54 -08002431#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002432#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002433static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002434{
David Keitel6ccbf132012-05-30 14:21:24 -07002435 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002436 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002437 u8 active_mask = 0;
2438 u16 ovpreg, ovptestreg;
2439
2440 if (is_usb_chg_plugged_in(chip) &&
2441 (chip->active_path & USB_ACTIVE_BIT)) {
2442 ovpreg = USB_OVP_CONTROL;
2443 ovptestreg = USB_OVP_TEST;
2444 active_mask = USB_ACTIVE_BIT;
2445 } else if (is_dc_chg_plugged_in(chip) &&
2446 (chip->active_path & DC_ACTIVE_BIT)) {
2447 ovpreg = DC_OVP_CONTROL;
2448 ovptestreg = DC_OVP_TEST;
2449 active_mask = DC_ACTIVE_BIT;
2450 } else {
2451 return;
2452 }
David Keitel8c5201a2012-02-24 16:08:54 -08002453
2454 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002455 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002456 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002457 active_chg_plugged_in
2458 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002459 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002460 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2461 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002462
2463 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002464 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002465 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002466 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002467
2468 msleep(20);
2469
David Keitel6ccbf132012-05-30 14:21:24 -07002470 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002471 } else {
David Keitel712782e2012-03-29 14:11:47 -07002472 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002473 }
2474 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002475 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2476 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2477 else
2478 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2479
David Keitel6ccbf132012-05-30 14:21:24 -07002480 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2481 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002482 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002483}
David Keitelacf57c82012-03-07 18:48:50 -08002484
2485static int find_usb_ma_value(int value)
2486{
2487 int i;
2488
2489 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2490 if (value >= usb_ma_table[i].usb_ma)
2491 break;
2492 }
2493
2494 return i;
2495}
2496
2497static void decrease_usb_ma_value(int *value)
2498{
2499 int i;
2500
2501 if (value) {
2502 i = find_usb_ma_value(*value);
2503 if (i > 0)
2504 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002505 while (!the_chip->iusb_fine_res && i > 0
2506 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2507 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002508
2509 if (i < 0) {
2510 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2511 *value);
2512 i = 0;
2513 }
2514
David Keitelacf57c82012-03-07 18:48:50 -08002515 *value = usb_ma_table[i].usb_ma;
2516 }
2517}
2518
2519static void increase_usb_ma_value(int *value)
2520{
2521 int i;
2522
2523 if (value) {
2524 i = find_usb_ma_value(*value);
2525
2526 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2527 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002528 /* Get next correct entry if IUSB_FINE_RES is not available */
2529 while (!the_chip->iusb_fine_res
2530 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2531 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2532 i++;
2533
David Keitelacf57c82012-03-07 18:48:50 -08002534 *value = usb_ma_table[i].usb_ma;
2535 }
2536}
2537
2538static void vin_collapse_check_worker(struct work_struct *work)
2539{
2540 struct delayed_work *dwork = to_delayed_work(work);
2541 struct pm8921_chg_chip *chip = container_of(dwork,
2542 struct pm8921_chg_chip, vin_collapse_check_work);
2543
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002544 /*
2545 * AICL only for wall-chargers. If the charger appears to be plugged
2546 * back in now, the corresponding unplug must have been because of we
2547 * were trying to draw more current than the charger can support. In
2548 * such a case reset usb current to 500mA and decrease the target.
2549 * The AICL algorithm will step up the current from 500mA to target
2550 */
2551 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002552 && usb_target_ma > USB_WALL_THRESHOLD_MA
2553 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002554 /* decrease usb_target_ma */
2555 decrease_usb_ma_value(&usb_target_ma);
2556 /* reset here, increase in unplug_check_worker */
2557 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2558 pr_debug("usb_now=%d, usb_target = %d\n",
2559 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002560 if (!delayed_work_pending(&chip->unplug_check_work))
2561 schedule_delayed_work(&chip->unplug_check_work,
2562 msecs_to_jiffies
2563 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002564 } else {
2565 handle_usb_insertion_removal(chip);
2566 }
2567}
2568
2569#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002570static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2571{
David Keitelacf57c82012-03-07 18:48:50 -08002572 if (usb_target_ma)
2573 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2574 round_jiffies_relative(msecs_to_jiffies
2575 (VIN_MIN_COLLAPSE_CHECK_MS)));
2576 else
2577 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578 return IRQ_HANDLED;
2579}
2580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2582{
2583 struct pm8921_chg_chip *chip = data;
2584 int status;
2585
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002586 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2587 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002588 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589 pr_debug("battery present=%d", status);
2590 power_supply_changed(&chip->batt_psy);
2591 return IRQ_HANDLED;
2592}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002593
2594/*
2595 * this interrupt used to restart charging a battery.
2596 *
2597 * Note: When DC-inserted the VBAT can't go low.
2598 * VPH_PWR is provided by the ext-charger.
2599 * After End-Of-Charging from DC, charging can be resumed only
2600 * if DC is removed and then inserted after the battery was in use.
2601 * Therefore the handle_start_ext_chg() is not called.
2602 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2604{
2605 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002606 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002608 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002609
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002610 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002611 /* enable auto charging */
2612 pm_chg_auto_enable(chip, !charging_disabled);
2613 pr_info("batt fell below resume voltage %s\n",
2614 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002615 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002616 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 power_supply_changed(&chip->batt_psy);
2619 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002620 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 return IRQ_HANDLED;
2623}
2624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2626{
2627 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2628 return IRQ_HANDLED;
2629}
2630
2631static irqreturn_t vcp_irq_handler(int irq, void *data)
2632{
David Keitel8c5201a2012-02-24 16:08:54 -08002633 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002634 return IRQ_HANDLED;
2635}
2636
2637static irqreturn_t atcdone_irq_handler(int irq, void *data)
2638{
2639 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2640 return IRQ_HANDLED;
2641}
2642
2643static irqreturn_t atcfail_irq_handler(int irq, void *data)
2644{
2645 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2646 return IRQ_HANDLED;
2647}
2648
2649static irqreturn_t chgdone_irq_handler(int irq, void *data)
2650{
2651 struct pm8921_chg_chip *chip = data;
2652
2653 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002654
2655 handle_stop_ext_chg(chip);
2656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657 power_supply_changed(&chip->batt_psy);
2658 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002659 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002660
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002661 bms_notify_check(chip);
2662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 return IRQ_HANDLED;
2664}
2665
2666static irqreturn_t chgfail_irq_handler(int irq, void *data)
2667{
2668 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002669 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002671 if (!chip->stop_chg_upon_expiry) {
2672 ret = pm_chg_failed_clear(chip, 1);
2673 if (ret)
2674 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2675 }
David Keitel753ec8d2011-11-02 10:56:37 -07002676
2677 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2678 get_prop_batt_present(chip),
2679 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2680 pm_chg_get_fsm_state(data));
2681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682 power_supply_changed(&chip->batt_psy);
2683 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002684 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002685 return IRQ_HANDLED;
2686}
2687
2688static irqreturn_t chgstate_irq_handler(int irq, void *data)
2689{
2690 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691
2692 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2693 power_supply_changed(&chip->batt_psy);
2694 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002695 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002697 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 return IRQ_HANDLED;
2700}
2701
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002702enum {
2703 PON_TIME_25NS = 0x04,
2704 PON_TIME_50NS = 0x08,
2705 PON_TIME_100NS = 0x0C,
2706};
David Keitel8c5201a2012-02-24 16:08:54 -08002707
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002708static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002709{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002710 u8 temp;
2711 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002712
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002713 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2714 if (rc) {
2715 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2716 return;
2717 }
2718 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2719 if (rc) {
2720 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2721 return;
2722 }
2723 /* clear the min pon time select bit */
2724 temp &= 0xF3;
2725 /* set the pon time */
2726 temp |= (u8)pon_time_ns;
2727 /* write enable bank 4 */
2728 temp |= 0x80;
2729 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2730 if (rc) {
2731 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2732 return;
2733 }
2734}
David Keitel8c5201a2012-02-24 16:08:54 -08002735
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002736static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2737{
2738 pr_debug("Start\n");
2739 set_min_pon_time(chip, PON_TIME_100NS);
2740 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2741 msleep(250);
2742 pm_chg_vinmin_set(chip, chip->vin_min);
2743 set_min_pon_time(chip, PON_TIME_25NS);
2744 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002745}
2746
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002747#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002748#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2749#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002750static void unplug_check_worker(struct work_struct *work)
2751{
2752 struct delayed_work *dwork = to_delayed_work(work);
2753 struct pm8921_chg_chip *chip = container_of(dwork,
2754 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002755 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002756 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002757 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002758 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002759
2760 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2761 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002762 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2763 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002764 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002765
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002766 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002767 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002768 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2769 active_path, active_chg_plugged_in);
2770 if (active_path & USB_ACTIVE_BIT) {
2771 pr_debug("USB charger active\n");
2772
2773 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002774
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002775 if (usb_ma <= 100) {
2776 pr_debug(
2777 "Unenumerated or suspended usb_ma = %d skip\n",
2778 usb_ma);
2779 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002780 }
2781 } else if (active_path & DC_ACTIVE_BIT) {
2782 pr_debug("DC charger active\n");
2783 } else {
2784 /* No charger active */
2785 if (!(is_usb_chg_plugged_in(chip)
2786 && !(is_dc_chg_plugged_in(chip)))) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302787 get_prop_batt_current(chip, &ibat);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002788 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002789 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2790 pm_chg_get_regulation_loop(chip),
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302791 pm_chg_get_fsm_state(chip), ibat);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002792 return;
2793 } else {
2794 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002795 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002796 }
David Keitel8c5201a2012-02-24 16:08:54 -08002797
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002798 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002799 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
2800 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07002801 reg_loop = pm_chg_get_regulation_loop(chip);
2802 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2803 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002804 (usb_ma > USB_WALL_THRESHOLD_MA)
2805 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002806 decrease_usb_ma_value(&usb_ma);
2807 usb_target_ma = usb_ma;
2808 /* end AICL here */
2809 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002810 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002811 usb_ma, usb_target_ma);
2812 }
David Keitelacf57c82012-03-07 18:48:50 -08002813 }
2814
2815 reg_loop = pm_chg_get_regulation_loop(chip);
2816 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2817
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302818 rc = get_prop_batt_current(chip, &ibat);
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302819 if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302820 if (ibat > 0 && !rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002821 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2822 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2823 attempt_reverse_boost_fix(chip);
2824 /* after reverse boost fix check if the active
2825 * charger was detected as removed */
2826 active_chg_plugged_in
2827 = is_active_chg_plugged_in(chip,
2828 active_path);
2829 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2830 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002831 }
2832 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002833
2834 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002835 pr_debug("active_path = 0x%x, active_chg = %d\n",
2836 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002837 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2838
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302839 if (chg_gone == 1 && active_chg_plugged_in == 1 &&
2840 !chip->disable_chg_rmvl_wrkarnd) {
David Keitel6ccbf132012-05-30 14:21:24 -07002841 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2842 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002843 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002844 }
2845
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002846 /* AICL only for usb wall charger */
2847 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2848 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002849 && !charging_disabled
2850 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002851 /* only increase iusb_max if vin loop not active */
2852 if (usb_ma < usb_target_ma) {
2853 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302854 if (usb_ma > usb_target_ma)
2855 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002856 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002857 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002858 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002859 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002860 } else {
2861 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002862 }
2863 }
Devin Kim2073afb2012-09-05 13:01:51 -07002864check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002865 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002866 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002867 if (ramp)
2868 schedule_delayed_work(&chip->unplug_check_work,
2869 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2870 else
2871 schedule_delayed_work(&chip->unplug_check_work,
2872 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002873}
2874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875static irqreturn_t loop_change_irq_handler(int irq, void *data)
2876{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002877 struct pm8921_chg_chip *chip = data;
2878
2879 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2880 pm_chg_get_fsm_state(data),
2881 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002882 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883 return IRQ_HANDLED;
2884}
2885
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002886struct ibatmax_max_adj_entry {
2887 int ibat_max_ma;
2888 int max_adj_ma;
2889};
2890
2891static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2892 {975, 300},
2893 {1475, 150},
2894 {1975, 200},
2895 {2475, 250},
2896};
2897
2898static int find_ibat_max_adj_ma(int ibat_target_ma)
2899{
2900 int i = 0;
2901
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002902 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2903 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002904 break;
2905 }
2906
Willie Ruaneeee0aa2013-03-04 21:54:10 -08002907 if (i > 0)
2908 i--;
2909
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002910 return ibatmax_adj_table[i].max_adj_ma;
2911}
2912
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913static irqreturn_t fastchg_irq_handler(int irq, void *data)
2914{
2915 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002916 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002918 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2919 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2920 wake_lock(&chip->eoc_wake_lock);
2921 schedule_delayed_work(&chip->eoc_work,
2922 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002923 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002924 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002925 if (high_transition
2926 && chip->btc_override
2927 && !delayed_work_pending(&chip->btc_override_work)) {
2928 schedule_delayed_work(&chip->btc_override_work,
2929 round_jiffies_relative(msecs_to_jiffies
2930 (chip->btc_delay_ms)));
2931 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002932 power_supply_changed(&chip->batt_psy);
2933 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 return IRQ_HANDLED;
2935}
2936
2937static irqreturn_t trklchg_irq_handler(int irq, void *data)
2938{
2939 struct pm8921_chg_chip *chip = data;
2940
2941 power_supply_changed(&chip->batt_psy);
2942 return IRQ_HANDLED;
2943}
2944
2945static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2946{
2947 struct pm8921_chg_chip *chip = data;
2948 int status;
2949
2950 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2951 pr_debug("battery present=%d state=%d", !status,
2952 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002953 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002954 power_supply_changed(&chip->batt_psy);
2955 return IRQ_HANDLED;
2956}
2957
2958static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2959{
2960 struct pm8921_chg_chip *chip = data;
2961
Amir Samuelovd31ef502011-10-26 14:41:36 +02002962 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 power_supply_changed(&chip->batt_psy);
2964 return IRQ_HANDLED;
2965}
2966
2967static irqreturn_t chghot_irq_handler(int irq, void *data)
2968{
2969 struct pm8921_chg_chip *chip = data;
2970
2971 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2972 power_supply_changed(&chip->batt_psy);
2973 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002974 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975 return IRQ_HANDLED;
2976}
2977
2978static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2979{
2980 struct pm8921_chg_chip *chip = data;
2981
2982 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002983 handle_stop_ext_chg(chip);
2984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985 power_supply_changed(&chip->batt_psy);
2986 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002987 return IRQ_HANDLED;
2988}
2989
2990static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2991{
2992 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002993 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002994
2995 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2996 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2997
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002998 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2999 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003001 power_supply_changed(&chip->batt_psy);
3002 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 return IRQ_HANDLED;
3004}
David Keitel52fda532011-11-10 10:43:44 -08003005/*
3006 *
3007 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3008 * fire for two cases:
3009 *
3010 * If the interrupt line switches to high temperature is okay
3011 * and thus charging begins.
3012 * If bat_temp_ok is low this means the temperature is now
3013 * too hot or cold, so charging is stopped.
3014 *
3015 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003016static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3017{
David Keitel52fda532011-11-10 10:43:44 -08003018 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 struct pm8921_chg_chip *chip = data;
3020
David Keitel52fda532011-11-10 10:43:44 -08003021 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3022
3023 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3024 bat_temp_ok, pm_chg_get_fsm_state(data));
3025
3026 if (bat_temp_ok)
3027 handle_start_ext_chg(chip);
3028 else
3029 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 power_supply_changed(&chip->batt_psy);
3032 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003033 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003034 return IRQ_HANDLED;
3035}
3036
3037static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3038{
3039 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3040 return IRQ_HANDLED;
3041}
3042
3043static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3044{
3045 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3046 return IRQ_HANDLED;
3047}
3048
3049static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3050{
3051 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3052 return IRQ_HANDLED;
3053}
3054
3055static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3056{
3057 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3058 return IRQ_HANDLED;
3059}
3060
3061static irqreturn_t batfet_irq_handler(int irq, void *data)
3062{
3063 struct pm8921_chg_chip *chip = data;
3064
3065 pr_debug("vreg ov\n");
3066 power_supply_changed(&chip->batt_psy);
3067 return IRQ_HANDLED;
3068}
3069
3070static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3071{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003072 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003073 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003074
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003075 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003076 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003077
3078 if (chip->dc_present ^ dc_present)
3079 pm8921_bms_calibrate_hkadc();
3080
David Keitel88e1b572012-01-11 11:57:14 -08003081 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003082 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003083 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003084 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3085
3086 chip->dc_present = dc_present;
3087
3088 if (chip->ext_psy) {
3089 if (dc_present)
3090 handle_start_ext_chg(chip);
3091 else
3092 handle_stop_ext_chg(chip);
3093 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003094 if (dc_present)
3095 schedule_delayed_work(&chip->unplug_check_work,
3096 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3097 power_supply_changed(&chip->dc_psy);
3098 }
3099
3100 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 return IRQ_HANDLED;
3102}
3103
3104static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3105{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003106 struct pm8921_chg_chip *chip = data;
3107
Amir Samuelovd31ef502011-10-26 14:41:36 +02003108 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003109 return IRQ_HANDLED;
3110}
3111
3112static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3113{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003114 struct pm8921_chg_chip *chip = data;
3115
Amir Samuelovd31ef502011-10-26 14:41:36 +02003116 handle_stop_ext_chg(chip);
3117
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003118 return IRQ_HANDLED;
3119}
3120
David Keitel88e1b572012-01-11 11:57:14 -08003121static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3122{
3123 struct power_supply *psy = &the_chip->batt_psy;
3124 struct power_supply *epsy = dev_get_drvdata(dev);
3125 int i, dcin_irq;
3126
3127 /* Only search for external supply if none is registered */
3128 if (!the_chip->ext_psy) {
3129 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3130 for (i = 0; i < epsy->num_supplicants; i++) {
3131 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3132 if (!strncmp(epsy->name, "dc", 2)) {
3133 the_chip->ext_psy = epsy;
3134 dcin_valid_irq_handler(dcin_irq,
3135 the_chip);
3136 }
3137 }
3138 }
3139 }
3140 return 0;
3141}
3142
3143static void pm_batt_external_power_changed(struct power_supply *psy)
3144{
Anirudh Ghayal34c9b852013-03-21 15:50:34 +05303145 if (!the_chip)
3146 return;
3147
David Keitel88e1b572012-01-11 11:57:14 -08003148 /* Only look for an external supply if it hasn't been registered */
3149 if (!the_chip->ext_psy)
3150 class_for_each_device(power_supply_class, NULL, psy,
3151 __pm_batt_external_power_changed_work);
3152}
3153
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003154/**
3155 * update_heartbeat - internal function to update userspace
3156 * per update_time minutes
3157 *
3158 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003159#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003160static void update_heartbeat(struct work_struct *work)
3161{
3162 struct delayed_work *dwork = to_delayed_work(work);
3163 struct pm8921_chg_chip *chip = container_of(dwork,
3164 struct pm8921_chg_chip, update_heartbeat_work);
3165
3166 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003167 if (chip->recent_reported_soc <= 20)
3168 schedule_delayed_work(&chip->update_heartbeat_work,
3169 round_jiffies_relative(msecs_to_jiffies
3170 (LOW_SOC_HEARTBEAT_MS)));
3171 else
3172 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003173 round_jiffies_relative(msecs_to_jiffies
3174 (chip->update_time)));
3175}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003176#define VDD_LOOP_ACTIVE_BIT BIT(3)
3177#define VDD_MAX_INCREASE_MV 400
3178static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3179module_param(vdd_max_increase_mv, int, 0644);
3180
3181static int ichg_threshold_ua = -400000;
3182module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003183
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003184#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX 13
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003185#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003186static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3187 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003188{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003189 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003190 int vbat_batt_terminal_mv;
3191 int reg_loop;
3192 int delta_mv = 0;
3193
3194 if (chip->rconn_mohm == 0) {
3195 pr_debug("Exiting as rconn_mohm is 0\n");
3196 return;
3197 }
3198 /* adjust vdd_max only in normal temperature zone */
3199 if (chip->is_bat_cool || chip->is_bat_warm) {
3200 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3201 chip->is_bat_cool, chip->is_bat_warm);
3202 return;
3203 }
3204
3205 reg_loop = pm_chg_get_regulation_loop(chip);
3206 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3207 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3208 reg_loop);
3209 return;
3210 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003211 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3212 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3213
3214 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3215
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003216 if (delta_mv > 0) /* meaning we want to increase the vddmax */ {
3217 if (delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
3218 pr_debug("vterm = %d is not low enough to inc vdd\n",
3219 vbat_batt_terminal_mv);
3220 return;
3221 }
3222 }
3223
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003224 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3225 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3226 delta_mv,
3227 programmed_vdd_max,
3228 adj_vdd_max_mv);
3229
3230 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3231 pr_debug("adj vdd_max lower than default max voltage\n");
3232 return;
3233 }
3234
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003235 adj_vdd_max_mv = (adj_vdd_max_mv / PM8921_CHG_VDDMAX_RES_MV)
3236 * PM8921_CHG_VDDMAX_RES_MV;
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003237
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003238 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3239 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003240 pr_debug("adjusting vdd_max_mv to %d to make "
3241 "vbat_batt_termial_uv = %d to %d\n",
3242 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3243 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3244}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003245
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003246static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3247{
3248 if (chip->is_bat_cool)
3249 pm_chg_vbatdet_set(the_chip,
3250 the_chip->cool_bat_voltage
3251 - the_chip->resume_voltage_delta);
3252 else if (chip->is_bat_warm)
3253 pm_chg_vbatdet_set(the_chip,
3254 the_chip->warm_bat_voltage
3255 - the_chip->resume_voltage_delta);
3256 else
3257 pm_chg_vbatdet_set(the_chip,
3258 the_chip->max_voltage_mv
3259 - the_chip->resume_voltage_delta);
3260}
3261
3262static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3263{
3264 unsigned int chg_current = chip->max_bat_chg_current;
3265
3266 if (chip->is_bat_cool)
3267 chg_current = min(chg_current, chip->cool_bat_chg_current);
3268
3269 if (chip->is_bat_warm)
3270 chg_current = min(chg_current, chip->warm_bat_chg_current);
3271
3272 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3273 chg_current = min(chg_current,
3274 chip->thermal_mitigation[thermal_mitigation]);
3275
3276 pm_chg_ibatmax_set(the_chip, chg_current);
3277}
3278
3279#define TEMP_HYSTERISIS_DECIDEGC 20
3280static void battery_cool(bool enter)
3281{
3282 pr_debug("enter = %d\n", enter);
3283 if (enter == the_chip->is_bat_cool)
3284 return;
3285 the_chip->is_bat_cool = enter;
3286 if (enter)
3287 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3288 else
3289 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3290 set_appropriate_battery_current(the_chip);
3291 set_appropriate_vbatdet(the_chip);
3292}
3293
3294static void battery_warm(bool enter)
3295{
3296 pr_debug("enter = %d\n", enter);
3297 if (enter == the_chip->is_bat_warm)
3298 return;
3299 the_chip->is_bat_warm = enter;
3300 if (enter)
3301 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3302 else
3303 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3304
3305 set_appropriate_battery_current(the_chip);
3306 set_appropriate_vbatdet(the_chip);
3307}
3308
3309static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3310{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303311 int temp = 0, rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003312
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303313 rc = get_prop_batt_temp(chip, &temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003314 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3315 temp, chip->warm_temp_dc,
3316 chip->cool_temp_dc);
3317
3318 if (chip->warm_temp_dc != INT_MIN) {
3319 if (chip->is_bat_warm
3320 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3321 battery_warm(false);
3322 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3323 battery_warm(true);
3324 }
3325
3326 if (chip->cool_temp_dc != INT_MIN) {
3327 if (chip->is_bat_cool
3328 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3329 battery_cool(false);
3330 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3331 battery_cool(true);
3332 }
3333}
3334
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003335enum {
3336 CHG_IN_PROGRESS,
3337 CHG_NOT_IN_PROGRESS,
3338 CHG_FINISHED,
3339};
3340
3341#define VBAT_TOLERANCE_MV 70
3342#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003343static int is_charging_finished(struct pm8921_chg_chip *chip,
3344 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003345{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003346 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003347 int regulation_loop, fast_chg, vcp;
3348 int rc;
3349 static int last_vbat_programmed = -EINVAL;
3350
3351 if (!is_ext_charging(chip)) {
3352 /* return if the battery is not being fastcharged */
3353 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3354 pr_debug("fast_chg = %d\n", fast_chg);
3355 if (fast_chg == 0)
3356 return CHG_NOT_IN_PROGRESS;
3357
3358 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3359 pr_debug("vcp = %d\n", vcp);
3360 if (vcp == 1)
3361 return CHG_IN_PROGRESS;
3362
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003363 /* reset count if battery is hot/cold */
3364 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3365 pr_debug("batt_temp_ok = %d\n", rc);
3366 if (rc == 0)
3367 return CHG_IN_PROGRESS;
3368
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003369 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3370 if (rc) {
3371 pr_err("couldnt read vddmax rc = %d\n", rc);
3372 return CHG_IN_PROGRESS;
3373 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003374 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3375 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003376
3377 if (last_vbat_programmed == -EINVAL)
3378 last_vbat_programmed = vbat_programmed;
3379 if (last_vbat_programmed != vbat_programmed) {
3380 /* vddmax changed, reset and check again */
3381 pr_debug("vddmax = %d last_vdd_max=%d\n",
3382 vbat_programmed, last_vbat_programmed);
3383 last_vbat_programmed = vbat_programmed;
3384 return CHG_IN_PROGRESS;
3385 }
3386
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003387 if (chip->is_bat_cool)
3388 vbat_intended = chip->cool_bat_voltage;
3389 else if (chip->is_bat_warm)
3390 vbat_intended = chip->warm_bat_voltage;
3391 else
3392 vbat_intended = chip->max_voltage_mv;
3393
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003394 if (vbat_batt_terminal_uv / 1000
3395 < vbat_intended - MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
3396 pr_debug("terminal_uv:%d < vbat_intended:%d-hyst:%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003397 vbat_batt_terminal_uv,
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003398 vbat_intended,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003399 vbat_intended);
3400 return CHG_IN_PROGRESS;
3401 }
3402
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003403 regulation_loop = pm_chg_get_regulation_loop(chip);
3404 if (regulation_loop < 0) {
3405 pr_err("couldnt read the regulation loop err=%d\n",
3406 regulation_loop);
3407 return CHG_IN_PROGRESS;
3408 }
3409 pr_debug("regulation_loop=%d\n", regulation_loop);
3410
3411 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3412 return CHG_IN_PROGRESS;
3413 } /* !is_ext_charging */
3414
3415 /* reset count if battery chg current is more than iterm */
3416 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3417 if (rc) {
3418 pr_err("couldnt read iterm rc = %d\n", rc);
3419 return CHG_IN_PROGRESS;
3420 }
3421
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003422 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3423 iterm_programmed, ichg_meas_ma);
3424 /*
3425 * ichg_meas_ma < 0 means battery is drawing current
3426 * ichg_meas_ma > 0 means battery is providing current
3427 */
3428 if (ichg_meas_ma > 0)
3429 return CHG_IN_PROGRESS;
3430
3431 if (ichg_meas_ma * -1 > iterm_programmed)
3432 return CHG_IN_PROGRESS;
3433
3434 return CHG_FINISHED;
3435}
3436
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003437#define COMP_OVERRIDE_HOT_BANK 6
3438#define COMP_OVERRIDE_COLD_BANK 7
3439#define COMP_OVERRIDE_BIT BIT(1)
3440static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3441{
3442 u8 val;
3443 int rc = 0;
3444
3445 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3446
3447 if (flag)
3448 val |= 0x01;
3449
3450 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3451 if (rc < 0)
3452 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3453
3454 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3455 return rc;
3456}
3457
3458static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3459{
3460 u8 val;
3461 int rc = 0;
3462
3463 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3464
3465 if (flag)
3466 val |= 0x01;
3467
3468 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3469 if (rc < 0)
3470 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3471
3472 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3473 return rc;
3474}
3475
3476static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3477{
3478 int rc = 0;
3479 u8 reg;
3480 u8 val;
3481
3482 val = COMP_OVERRIDE_HOT_BANK << 2;
3483 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3484 if (rc < 0) {
3485 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3486 goto cold_init;
3487 }
3488 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3489 if (rc < 0) {
3490 pr_err("Could not read bank %d of override rc = %d\n",
3491 COMP_OVERRIDE_HOT_BANK, rc);
3492 goto cold_init;
3493 }
3494 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3495 /* for now override it as not hot */
3496 rc = pm_chg_override_hot(chip, 0);
3497 if (rc < 0)
3498 pr_err("Could not override hot rc = %d\n", rc);
3499 }
3500
3501cold_init:
3502 val = COMP_OVERRIDE_COLD_BANK << 2;
3503 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3504 if (rc < 0) {
3505 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3506 return;
3507 }
3508 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3509 if (rc < 0) {
3510 pr_err("Could not read bank %d of override rc = %d\n",
3511 COMP_OVERRIDE_COLD_BANK, rc);
3512 return;
3513 }
3514 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3515 /* for now override it as not cold */
3516 rc = pm_chg_override_cold(chip, 0);
3517 if (rc < 0)
3518 pr_err("Could not override cold rc = %d\n", rc);
3519 }
3520}
3521
3522static void btc_override_worker(struct work_struct *work)
3523{
3524 int decidegc;
3525 int temp;
3526 int rc = 0;
3527 struct delayed_work *dwork = to_delayed_work(work);
3528 struct pm8921_chg_chip *chip = container_of(dwork,
3529 struct pm8921_chg_chip, btc_override_work);
3530
3531 if (!chip->btc_override) {
3532 pr_err("called when not enabled\n");
3533 return;
3534 }
3535
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303536 rc = get_prop_batt_temp(chip, &decidegc);
3537 if (rc) {
3538 pr_info("Failed to read temperature\n");
3539 goto fail_btc_temp;
3540 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003541
3542 pr_debug("temp=%d\n", decidegc);
3543
3544 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3545 if (temp) {
3546 if (decidegc < chip->btc_override_hot_decidegc)
3547 /* stop forcing batt hot */
3548 rc = pm_chg_override_hot(chip, 0);
3549 if (rc)
3550 pr_err("Couldnt write 0 to hot comp\n");
3551 } else {
3552 if (decidegc >= chip->btc_override_hot_decidegc)
3553 /* start forcing batt hot */
3554 rc = pm_chg_override_hot(chip, 1);
3555 if (rc && chip->btc_panic_if_cant_stop_chg)
3556 panic("Couldnt override comps to stop chg\n");
3557 }
3558
3559 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3560 if (temp) {
3561 if (decidegc > chip->btc_override_cold_decidegc)
3562 /* stop forcing batt cold */
3563 rc = pm_chg_override_cold(chip, 0);
3564 if (rc)
3565 pr_err("Couldnt write 0 to cold comp\n");
3566 } else {
3567 if (decidegc <= chip->btc_override_cold_decidegc)
3568 /* start forcing batt cold */
3569 rc = pm_chg_override_cold(chip, 1);
3570 if (rc && chip->btc_panic_if_cant_stop_chg)
3571 panic("Couldnt override comps to stop chg\n");
3572 }
3573
3574 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3575 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3576 schedule_delayed_work(&chip->btc_override_work,
3577 round_jiffies_relative(msecs_to_jiffies
3578 (chip->btc_delay_ms)));
3579 return;
3580 }
3581
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303582fail_btc_temp:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003583 rc = pm_chg_override_hot(chip, 0);
3584 if (rc)
3585 pr_err("Couldnt write 0 to hot comp\n");
3586 rc = pm_chg_override_cold(chip, 0);
3587 if (rc)
3588 pr_err("Couldnt write 0 to cold comp\n");
3589}
3590
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003591/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003592 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003593 * has happened
3594 *
3595 * If all conditions favouring, if the charge current is
3596 * less than the term current for three consecutive times
3597 * an EOC has happened.
3598 * The wakelock is released if there is no need to reshedule
3599 * - this happens when the battery is removed or EOC has
3600 * happened
3601 */
3602#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003603static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003604{
3605 struct delayed_work *dwork = to_delayed_work(work);
3606 struct pm8921_chg_chip *chip = container_of(dwork,
3607 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003608 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003609 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003610 int vbat_meas_uv, vbat_meas_mv;
3611 int ichg_meas_ua, ichg_meas_ma;
3612 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003613
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003614 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3615 &ichg_meas_ua, &vbat_meas_uv);
3616 vbat_meas_mv = vbat_meas_uv / 1000;
3617 /* rconn_mohm is in milliOhms */
3618 ichg_meas_ma = ichg_meas_ua / 1000;
3619 vbat_batt_terminal_uv = vbat_meas_uv
3620 + ichg_meas_ma
3621 * the_chip->rconn_mohm;
3622
3623 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003624
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003625 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003626 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003627 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003628 }
3629
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003630 if (end == CHG_FINISHED) {
3631 count++;
3632 } else {
3633 count = 0;
3634 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003635
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003636 if (count == CONSECUTIVE_COUNT) {
3637 count = 0;
3638 pr_info("End of Charging\n");
3639
3640 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003641
Amir Samuelovd31ef502011-10-26 14:41:36 +02003642 if (is_ext_charging(chip))
3643 chip->ext_charge_done = true;
3644
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003645 if (chip->is_bat_warm || chip->is_bat_cool)
3646 chip->bms_notify.is_battery_full = 0;
3647 else
3648 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003649 /* declare end of charging by invoking chgdone interrupt */
3650 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003651 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003652 check_temp_thresholds(chip);
3653 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003654 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003655 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003656 round_jiffies_relative(msecs_to_jiffies
3657 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003658 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003659 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003660
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003661eoc_worker_stop:
3662 wake_unlock(&chip->eoc_wake_lock);
3663 /* set the vbatdet back, in case it was changed to trigger charging */
3664 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003665}
3666
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003667/**
3668 * set_disable_status_param -
3669 *
3670 * Internal function to disable battery charging and also disable drawing
3671 * any current from the source. The device is forced to run on a battery
3672 * after this.
3673 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003674static int set_disable_status_param(const char *val, struct kernel_param *kp)
3675{
3676 int ret;
3677 struct pm8921_chg_chip *chip = the_chip;
3678
3679 ret = param_set_int(val, kp);
3680 if (ret) {
3681 pr_err("error setting value %d\n", ret);
3682 return ret;
3683 }
3684 pr_info("factory set disable param to %d\n", charging_disabled);
3685 if (chip) {
3686 pm_chg_auto_enable(chip, !charging_disabled);
3687 pm_chg_charge_dis(chip, charging_disabled);
3688 }
3689 return 0;
3690}
3691module_param_call(disabled, set_disable_status_param, param_get_uint,
3692 &charging_disabled, 0644);
3693
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003694static int rconn_mohm;
3695static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3696{
3697 int ret;
3698 struct pm8921_chg_chip *chip = the_chip;
3699
3700 ret = param_set_int(val, kp);
3701 if (ret) {
3702 pr_err("error setting value %d\n", ret);
3703 return ret;
3704 }
3705 if (chip)
3706 chip->rconn_mohm = rconn_mohm;
3707 return 0;
3708}
3709module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3710 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003711/**
3712 * set_thermal_mitigation_level -
3713 *
3714 * Internal function to control battery charging current to reduce
3715 * temperature
3716 */
3717static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3718{
3719 int ret;
3720 struct pm8921_chg_chip *chip = the_chip;
3721
3722 ret = param_set_int(val, kp);
3723 if (ret) {
3724 pr_err("error setting value %d\n", ret);
3725 return ret;
3726 }
3727
3728 if (!chip) {
3729 pr_err("called before init\n");
3730 return -EINVAL;
3731 }
3732
3733 if (!chip->thermal_mitigation) {
3734 pr_err("no thermal mitigation\n");
3735 return -EINVAL;
3736 }
3737
3738 if (thermal_mitigation < 0
3739 || thermal_mitigation >= chip->thermal_levels) {
3740 pr_err("out of bound level selected\n");
3741 return -EINVAL;
3742 }
3743
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003744 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003745 return ret;
3746}
3747module_param_call(thermal_mitigation, set_therm_mitigation_level,
3748 param_get_uint,
3749 &thermal_mitigation, 0644);
3750
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003751static int set_usb_max_current(const char *val, struct kernel_param *kp)
3752{
3753 int ret, mA;
3754 struct pm8921_chg_chip *chip = the_chip;
3755
3756 ret = param_set_int(val, kp);
3757 if (ret) {
3758 pr_err("error setting value %d\n", ret);
3759 return ret;
3760 }
3761 if (chip) {
3762 pr_warn("setting current max to %d\n", usb_max_current);
3763 pm_chg_iusbmax_get(chip, &mA);
3764 if (mA > usb_max_current)
3765 pm8921_charger_vbus_draw(usb_max_current);
3766 return 0;
3767 }
3768 return -EINVAL;
3769}
David Keitelacf57c82012-03-07 18:48:50 -08003770module_param_call(usb_max_current, set_usb_max_current,
3771 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773static void free_irqs(struct pm8921_chg_chip *chip)
3774{
3775 int i;
3776
3777 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3778 if (chip->pmic_chg_irq[i]) {
3779 free_irq(chip->pmic_chg_irq[i], chip);
3780 chip->pmic_chg_irq[i] = 0;
3781 }
3782}
3783
David Keitel88e1b572012-01-11 11:57:14 -08003784/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3786{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003788 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789
3790 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3791 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3792
3793 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003794 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003795 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003796 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003797 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003798 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799
3800 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3801 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3802 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003803 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003804 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3805 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003806 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003807 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3808 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003809 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003811 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3812 if (usb_chg_current)
3813 /*
3814 * Reissue a vbus draw call only if a battery
3815 * or DC is present. We don't want to brown out the
3816 * device if usb is its only source
3817 */
3818 __pm8921_charger_vbus_draw(usb_chg_current);
3819 usb_chg_current = 0;
3820
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003821 /*
3822 * The bootloader could have started charging, a fastchg interrupt
3823 * might not happen. Check the real time status and if it is fast
3824 * charging invoke the handler so that the eoc worker could be
3825 * started
3826 */
3827 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3828 if (is_fast_chg)
3829 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830
3831 fsm_state = pm_chg_get_fsm_state(chip);
3832 if (is_battery_charging(fsm_state)) {
3833 chip->bms_notify.is_charging = 1;
3834 pm8921_bms_charging_began();
3835 }
3836
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003837 check_battery_valid(chip);
3838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3840 chip->usb_present,
3841 chip->dc_present,
3842 get_prop_batt_present(chip),
3843 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003844
3845 /* Determine which USB trim column to use */
3846 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3847 chip->usb_trim_table = usb_trim_8917_table;
3848 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3849 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003850}
3851
3852struct pm_chg_irq_init_data {
3853 unsigned int irq_id;
3854 char *name;
3855 unsigned long flags;
3856 irqreturn_t (*handler)(int, void *);
3857};
3858
3859#define CHG_IRQ(_id, _flags, _handler) \
3860{ \
3861 .irq_id = _id, \
3862 .name = #_id, \
3863 .flags = _flags, \
3864 .handler = _handler, \
3865}
3866struct pm_chg_irq_init_data chg_irq_data[] = {
3867 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3868 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3870 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003871 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3872 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003873 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3874 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3875 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3876 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3877 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3878 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3879 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3880 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003881 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3882 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003883 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3884 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3885 batt_removed_irq_handler),
3886 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3887 batttemp_hot_irq_handler),
3888 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3889 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3890 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003891 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3892 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003893 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3894 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003895 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3896 coarse_det_low_irq_handler),
3897 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3898 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3899 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3900 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3901 batfet_irq_handler),
3902 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3903 dcin_valid_irq_handler),
3904 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3905 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003906 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907};
3908
3909static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3910 struct platform_device *pdev)
3911{
3912 struct resource *res;
3913 int ret, i;
3914
3915 ret = 0;
3916 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3917
3918 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3919 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3920 chg_irq_data[i].name);
3921 if (res == NULL) {
3922 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3923 goto err_out;
3924 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003925 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 ret = request_irq(res->start, chg_irq_data[i].handler,
3927 chg_irq_data[i].flags,
3928 chg_irq_data[i].name, chip);
3929 if (ret < 0) {
3930 pr_err("couldn't request %d (%s) %d\n", res->start,
3931 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003932 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 goto err_out;
3934 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3936 }
3937 return 0;
3938
3939err_out:
3940 free_irqs(chip);
3941 return -EINVAL;
3942}
3943
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003944static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3945{
3946 int err;
3947 u8 temp;
3948
3949 temp = 0xD1;
3950 err = pm_chg_write(chip, CHG_TEST, temp);
3951 if (err) {
3952 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3953 return;
3954 }
3955
3956 temp = 0xD3;
3957 err = pm_chg_write(chip, CHG_TEST, temp);
3958 if (err) {
3959 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3960 return;
3961 }
3962
3963 temp = 0xD1;
3964 err = pm_chg_write(chip, CHG_TEST, temp);
3965 if (err) {
3966 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3967 return;
3968 }
3969
3970 temp = 0xD5;
3971 err = pm_chg_write(chip, CHG_TEST, temp);
3972 if (err) {
3973 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3974 return;
3975 }
3976
3977 udelay(183);
3978
3979 temp = 0xD1;
3980 err = pm_chg_write(chip, CHG_TEST, temp);
3981 if (err) {
3982 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3983 return;
3984 }
3985
3986 temp = 0xD0;
3987 err = pm_chg_write(chip, CHG_TEST, temp);
3988 if (err) {
3989 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3990 return;
3991 }
3992 udelay(32);
3993
3994 temp = 0xD1;
3995 err = pm_chg_write(chip, CHG_TEST, temp);
3996 if (err) {
3997 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3998 return;
3999 }
4000
4001 temp = 0xD3;
4002 err = pm_chg_write(chip, CHG_TEST, temp);
4003 if (err) {
4004 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4005 return;
4006 }
4007}
4008
4009static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
4010{
4011 int err;
4012 u8 temp;
4013
4014 temp = 0xD1;
4015 err = pm_chg_write(chip, CHG_TEST, temp);
4016 if (err) {
4017 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4018 return;
4019 }
4020
4021 temp = 0xD0;
4022 err = pm_chg_write(chip, CHG_TEST, temp);
4023 if (err) {
4024 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4025 return;
4026 }
4027}
4028
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004029#define VREF_BATT_THERM_FORCE_ON BIT(7)
4030static void detect_battery_removal(struct pm8921_chg_chip *chip)
4031{
4032 u8 temp;
4033
4034 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4035 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4036
4037 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4038 /*
4039 * batt therm force on bit is battery backed and is default 0
4040 * The charger sets this bit at init time. If this bit is found
4041 * 0 that means the battery was removed. Tell the bms about it
4042 */
4043 pm8921_bms_invalidate_shutdown_soc();
4044}
4045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004046#define ENUM_TIMER_STOP_BIT BIT(1)
4047#define BOOT_DONE_BIT BIT(6)
4048#define CHG_BATFET_ON_BIT BIT(3)
4049#define CHG_VCP_EN BIT(0)
4050#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4051#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004052#define PM_SUB_REV 0x001
4053#define MIN_CHARGE_CURRENT_MA 350
4054#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004055static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4056{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004057 u8 subrev;
4058 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004060 /* forcing 19p2mhz before accessing any charger registers */
4061 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004062
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004063 detect_battery_removal(chip);
4064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004066 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 if (rc) {
4068 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4069 return rc;
4070 }
4071
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004072 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4073
4074 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4075 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4076
4077 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004079 if (rc) {
4080 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004081 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 return rc;
4083 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004084 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004085 chip->max_voltage_mv
4086 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 if (rc) {
4088 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004089 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 return rc;
4091 }
4092
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004093 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 if (rc) {
4095 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004096 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 return rc;
4098 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004099
4100 if (chip->safe_current_ma == 0)
4101 chip->safe_current_ma = SAFE_CURRENT_MA;
4102
4103 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104 if (rc) {
4105 pr_err("Failed to set max voltage to %d rc=%d\n",
4106 SAFE_CURRENT_MA, rc);
4107 return rc;
4108 }
4109
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004110 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 if (rc) {
4112 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4113 return rc;
4114 }
4115
4116 rc = pm_chg_iterm_set(chip, chip->term_current);
4117 if (rc) {
4118 pr_err("Failed to set term current to %d rc=%d\n",
4119 chip->term_current, rc);
4120 return rc;
4121 }
4122
4123 /* Disable the ENUM TIMER */
4124 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4125 ENUM_TIMER_STOP_BIT);
4126 if (rc) {
4127 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4128 return rc;
4129 }
4130
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004131 fcc_uah = pm8921_bms_get_fcc();
4132 if (fcc_uah > 0) {
4133 safety_time = div_s64((s64)fcc_uah * 60,
4134 1000 * MIN_CHARGE_CURRENT_MA);
4135 /* add 20 minutes of buffer time */
4136 safety_time += 20;
4137
4138 /* make sure we do not exceed the maximum programmable time */
4139 if (safety_time > PM8921_CHG_TCHG_MAX)
4140 safety_time = PM8921_CHG_TCHG_MAX;
4141 }
4142
4143 rc = pm_chg_tchg_max_set(chip, safety_time);
4144 if (rc) {
4145 pr_err("Failed to set max time to %d minutes rc=%d\n",
4146 safety_time, rc);
4147 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004148 }
4149
4150 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004151 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004152 if (rc) {
4153 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004154 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004155 return rc;
4156 }
4157 }
4158
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004159 if (chip->vin_min != 0) {
4160 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4161 if (rc) {
4162 pr_err("Failed to set vin min to %d mV rc=%d\n",
4163 chip->vin_min, rc);
4164 return rc;
4165 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004166 } else {
4167 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004168 }
4169
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004170 rc = pm_chg_disable_wd(chip);
4171 if (rc) {
4172 pr_err("Failed to disable wd rc=%d\n", rc);
4173 return rc;
4174 }
4175
4176 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4177 CHG_BAT_TEMP_DIS_BIT, 0);
4178 if (rc) {
4179 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4180 return rc;
4181 }
4182 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004183 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4184 rc = pm_chg_write(chip,
4185 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4186 else
4187 rc = pm_chg_write(chip,
4188 CHG_BUCK_CLOCK_CTRL, 0x15);
4189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004190 if (rc) {
4191 pr_err("Failed to switch buck clk rc=%d\n", rc);
4192 return rc;
4193 }
4194
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004195 if (chip->trkl_voltage != 0) {
4196 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4197 if (rc) {
4198 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4199 chip->trkl_voltage, rc);
4200 return rc;
4201 }
4202 }
4203
4204 if (chip->weak_voltage != 0) {
4205 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4206 if (rc) {
4207 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4208 chip->weak_voltage, rc);
4209 return rc;
4210 }
4211 }
4212
4213 if (chip->trkl_current != 0) {
4214 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4215 if (rc) {
4216 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4217 chip->trkl_voltage, rc);
4218 return rc;
4219 }
4220 }
4221
4222 if (chip->weak_current != 0) {
4223 rc = pm_chg_iweak_set(chip, chip->weak_current);
4224 if (rc) {
4225 pr_err("Failed to set weak current to %dmA rc=%d\n",
4226 chip->weak_current, rc);
4227 return rc;
4228 }
4229 }
4230
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004231 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4232 if (rc) {
4233 pr_err("Failed to set cold config %d rc=%d\n",
4234 chip->cold_thr, rc);
4235 }
4236
4237 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4238 if (rc) {
4239 pr_err("Failed to set hot config %d rc=%d\n",
4240 chip->hot_thr, rc);
4241 }
4242
Jay Chokshid674a512012-03-15 14:06:04 -07004243 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4244 if (rc) {
4245 pr_err("Failed to set charger LED src config %d rc=%d\n",
4246 chip->led_src_config, rc);
4247 }
4248
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004249 /* Workarounds for die 3.0 */
4250 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4251 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4252 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4253 if (rc) {
4254 pr_err("read failed: addr=%03X, rc=%d\n",
4255 PM_SUB_REV, rc);
4256 return rc;
4257 }
4258 /* Check if die 3.0.1 is present */
4259 if (subrev & 0x1)
4260 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4261 else
4262 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004263 }
4264
David Keitel0789fc62012-06-07 17:43:27 -07004265 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004266 /* Set PM8917 USB_OVP debounce time to 15 ms */
4267 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4268 OVP_DEBOUNCE_TIME, 0x6);
4269 if (rc) {
4270 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4271 return rc;
4272 }
4273
4274 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004275 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004276 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004277 rc = pm_chg_uvd_threshold_set(chip,
4278 chip->uvd_voltage_mv);
4279 if (rc) {
4280 pr_err("Failed to set UVD threshold %drc=%d\n",
4281 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004282 return rc;
4283 }
David Keitel0789fc62012-06-07 17:43:27 -07004284 }
4285 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004286
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004287 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004288
David Keitela3c0d822011-11-03 14:18:52 -07004289 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004290 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004291
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004292 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4293 VREF_BATT_THERM_FORCE_ON);
4294 if (rc)
4295 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004297 rc = pm_chg_charge_dis(chip, charging_disabled);
4298 if (rc) {
4299 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4300 return rc;
4301 }
4302
4303 rc = pm_chg_auto_enable(chip, !charging_disabled);
4304 if (rc) {
4305 pr_err("Failed to enable charging rc=%d\n", rc);
4306 return rc;
4307 }
4308
4309 return 0;
4310}
4311
4312static int get_rt_status(void *data, u64 * val)
4313{
4314 int i = (int)data;
4315 int ret;
4316
4317 /* global irq number is passed in via data */
4318 ret = pm_chg_get_rt_status(the_chip, i);
4319 *val = ret;
4320 return 0;
4321}
4322DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4323
4324static int get_fsm_status(void *data, u64 * val)
4325{
4326 u8 temp;
4327
4328 temp = pm_chg_get_fsm_state(the_chip);
4329 *val = temp;
4330 return 0;
4331}
4332DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4333
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004334static int get_reg_loop(void *data, u64 * val)
4335{
4336 u8 temp;
4337
4338 if (!the_chip) {
4339 pr_err("%s called before init\n", __func__);
4340 return -EINVAL;
4341 }
4342 temp = pm_chg_get_regulation_loop(the_chip);
4343 *val = temp;
4344 return 0;
4345}
4346DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004348static int get_reg(void *data, u64 * val)
4349{
4350 int addr = (int)data;
4351 int ret;
4352 u8 temp;
4353
4354 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4355 if (ret) {
4356 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4357 addr, temp, ret);
4358 return -EAGAIN;
4359 }
4360 *val = temp;
4361 return 0;
4362}
4363
4364static int set_reg(void *data, u64 val)
4365{
4366 int addr = (int)data;
4367 int ret;
4368 u8 temp;
4369
4370 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004371 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004372 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004373 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374 addr, temp, ret);
4375 return -EAGAIN;
4376 }
4377 return 0;
4378}
4379DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4380
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004381static int reg_loop;
4382#define MAX_REG_LOOP_CHAR 10
4383static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4384{
4385 u8 temp;
4386
4387 if (!the_chip) {
4388 pr_err("called before init\n");
4389 return -EINVAL;
4390 }
4391 temp = pm_chg_get_regulation_loop(the_chip);
4392 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4393}
4394module_param_call(reg_loop, NULL, get_reg_loop_param,
4395 &reg_loop, 0644);
4396
4397static int max_chg_ma;
4398#define MAX_MA_CHAR 10
4399static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4400{
4401 if (!the_chip) {
4402 pr_err("called before init\n");
4403 return -EINVAL;
4404 }
4405 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4406}
4407module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4408 &max_chg_ma, 0644);
4409static int ibatmax_ma;
4410static int set_ibat_max(const char *val, struct kernel_param *kp)
4411{
4412 int rc;
4413
4414 if (!the_chip) {
4415 pr_err("called before init\n");
4416 return -EINVAL;
4417 }
4418
4419 rc = param_set_int(val, kp);
4420 if (rc) {
4421 pr_err("error setting value %d\n", rc);
4422 return rc;
4423 }
4424
4425 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4426 <= the_chip->ibatmax_max_adj_ma) {
4427 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4428 if (rc) {
4429 pr_err("Failed to set ibatmax rc = %d\n", rc);
4430 return rc;
4431 }
4432 }
4433
4434 return 0;
4435}
4436static int get_ibat_max(char *buf, struct kernel_param *kp)
4437{
4438 int ibat_ma;
4439 int rc;
4440
4441 if (!the_chip) {
4442 pr_err("called before init\n");
4443 return -EINVAL;
4444 }
4445
4446 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4447 if (rc) {
4448 pr_err("ibatmax_get error = %d\n", rc);
4449 return rc;
4450 }
4451
4452 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4453}
4454module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4455 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004456enum {
4457 BAT_WARM_ZONE,
4458 BAT_COOL_ZONE,
4459};
4460static int get_warm_cool(void *data, u64 * val)
4461{
4462 if (!the_chip) {
4463 pr_err("%s called before init\n", __func__);
4464 return -EINVAL;
4465 }
4466 if ((int)data == BAT_WARM_ZONE)
4467 *val = the_chip->is_bat_warm;
4468 if ((int)data == BAT_COOL_ZONE)
4469 *val = the_chip->is_bat_cool;
4470 return 0;
4471}
4472DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004474static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4475{
4476 int i;
4477
4478 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4479
4480 if (IS_ERR(chip->dent)) {
4481 pr_err("pmic charger couldnt create debugfs dir\n");
4482 return;
4483 }
4484
4485 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4486 (void *)CHG_CNTRL, &reg_fops);
4487 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4488 (void *)CHG_CNTRL_2, &reg_fops);
4489 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4490 (void *)CHG_CNTRL_3, &reg_fops);
4491 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4492 (void *)PBL_ACCESS1, &reg_fops);
4493 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4494 (void *)PBL_ACCESS2, &reg_fops);
4495 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4496 (void *)SYS_CONFIG_1, &reg_fops);
4497 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4498 (void *)SYS_CONFIG_2, &reg_fops);
4499 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4500 (void *)CHG_VDD_MAX, &reg_fops);
4501 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4502 (void *)CHG_VDD_SAFE, &reg_fops);
4503 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4504 (void *)CHG_VBAT_DET, &reg_fops);
4505 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4506 (void *)CHG_IBAT_MAX, &reg_fops);
4507 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4508 (void *)CHG_IBAT_SAFE, &reg_fops);
4509 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4510 (void *)CHG_VIN_MIN, &reg_fops);
4511 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4512 (void *)CHG_VTRICKLE, &reg_fops);
4513 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4514 (void *)CHG_ITRICKLE, &reg_fops);
4515 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4516 (void *)CHG_ITERM, &reg_fops);
4517 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4518 (void *)CHG_TCHG_MAX, &reg_fops);
4519 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4520 (void *)CHG_TWDOG, &reg_fops);
4521 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4522 (void *)CHG_TEMP_THRESH, &reg_fops);
4523 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4524 (void *)CHG_COMP_OVR, &reg_fops);
4525 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4526 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4527 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4528 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4529 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4530 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4531 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4532 (void *)CHG_TEST, &reg_fops);
4533
4534 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4535 &fsm_fops);
4536
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004537 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4538 &reg_loop_fops);
4539
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004540 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4541 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4542 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4543 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004545 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4546 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4547 debugfs_create_file(chg_irq_data[i].name, 0444,
4548 chip->dent,
4549 (void *)chg_irq_data[i].irq_id,
4550 &rt_fops);
4551 }
4552}
4553
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004554static int pm8921_charger_suspend_noirq(struct device *dev)
4555{
4556 int rc;
4557 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4558
4559 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4560 if (rc)
4561 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004562
4563 rc = pm8921_chg_set_lpm(chip, 1);
4564 if (rc)
4565 pr_err("Failed to set lpm rc=%d\n", rc);
4566
4567 pm8921_chg_set_hw_clk_switching(chip);
4568
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004569 return 0;
4570}
4571
4572static int pm8921_charger_resume_noirq(struct device *dev)
4573{
4574 int rc;
4575 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4576
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004577 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004578
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004579 rc = pm8921_chg_set_lpm(chip, 0);
4580 if (rc)
4581 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004582
4583 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4584 VREF_BATT_THERM_FORCE_ON);
4585 if (rc)
4586 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4587 return 0;
4588}
4589
David Keitelf2226022011-12-13 15:55:50 -08004590static int pm8921_charger_resume(struct device *dev)
4591{
David Keitelf2226022011-12-13 15:55:50 -08004592 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4593
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004594 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4595 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4596 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4597 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004598
4599 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4600 is_usb_chg_plugged_in(the_chip)))
4601 schedule_delayed_work(&chip->btc_override_work, 0);
4602
David Keitelf2226022011-12-13 15:55:50 -08004603 return 0;
4604}
4605
4606static int pm8921_charger_suspend(struct device *dev)
4607{
David Keitelf2226022011-12-13 15:55:50 -08004608 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4609
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004610 if (chip->btc_override)
4611 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004612
4613 if (is_usb_chg_plugged_in(chip)) {
4614 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4615 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4616 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004617
David Keitelf2226022011-12-13 15:55:50 -08004618 return 0;
4619}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004620static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4621{
4622 int rc = 0;
4623 struct pm8921_chg_chip *chip;
4624 const struct pm8921_charger_platform_data *pdata
4625 = pdev->dev.platform_data;
4626
4627 if (!pdata) {
4628 pr_err("missing platform data\n");
4629 return -EINVAL;
4630 }
4631
4632 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4633 GFP_KERNEL);
4634 if (!chip) {
4635 pr_err("Cannot allocate pm_chg_chip\n");
4636 return -ENOMEM;
4637 }
4638
4639 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004640 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004641 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004642 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004643 chip->alarm_low_mv = pdata->alarm_low_mv;
4644 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004645 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004646 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004647 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004648 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004649 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004650 chip->term_current = pdata->term_current;
4651 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004652 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004653 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4654 chip->batt_id_min = pdata->batt_id_min;
4655 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004656 if (pdata->cool_temp != INT_MIN)
4657 chip->cool_temp_dc = pdata->cool_temp * 10;
4658 else
4659 chip->cool_temp_dc = INT_MIN;
4660
4661 if (pdata->warm_temp != INT_MIN)
4662 chip->warm_temp_dc = pdata->warm_temp * 10;
4663 else
4664 chip->warm_temp_dc = INT_MIN;
4665
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004666 chip->temp_check_period = pdata->temp_check_period;
4667 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004668 /* Assign to corresponding module parameter */
4669 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004670 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4671 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4672 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4673 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004674 chip->trkl_voltage = pdata->trkl_voltage;
4675 chip->weak_voltage = pdata->weak_voltage;
4676 chip->trkl_current = pdata->trkl_current;
4677 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004678 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004679 chip->thermal_mitigation = pdata->thermal_mitigation;
4680 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304681 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004682
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004683 chip->cold_thr = pdata->cold_thr;
4684 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004685 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004686 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004687 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004688 chip->battery_less_hardware = pdata->battery_less_hardware;
4689 chip->btc_override = pdata->btc_override;
4690 if (chip->btc_override) {
4691 chip->btc_delay_ms = pdata->btc_delay_ms;
4692 chip->btc_override_cold_decidegc
4693 = pdata->btc_override_cold_degc * 10;
4694 chip->btc_override_hot_decidegc
4695 = pdata->btc_override_hot_degc * 10;
4696 chip->btc_panic_if_cant_stop_chg
4697 = pdata->btc_panic_if_cant_stop_chg;
4698 }
4699
4700 if (chip->battery_less_hardware)
4701 charging_disabled = 1;
4702
4703 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4704 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004706 rc = pm8921_chg_hw_init(chip);
4707 if (rc) {
4708 pr_err("couldn't init hardware rc=%d\n", rc);
4709 goto free_chip;
4710 }
4711
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004712 if (chip->btc_override)
4713 pm8921_chg_btc_override_init(chip);
4714
4715 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304716 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004717
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004718 chip->usb_psy.name = "usb";
4719 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4720 chip->usb_psy.supplied_to = pm_power_supplied_to;
4721 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4722 chip->usb_psy.properties = pm_power_props_usb;
4723 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4724 chip->usb_psy.get_property = pm_power_get_property_usb;
4725 chip->usb_psy.set_property = pm_power_set_property_usb;
4726 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004727
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004728 chip->dc_psy.name = "pm8921-dc";
4729 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4730 chip->dc_psy.supplied_to = pm_power_supplied_to;
4731 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4732 chip->dc_psy.properties = pm_power_props_mains;
4733 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4734 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004735
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004736 chip->batt_psy.name = "battery";
4737 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4738 chip->batt_psy.properties = msm_batt_power_props;
4739 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4740 chip->batt_psy.get_property = pm_batt_power_get_property;
4741 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 rc = power_supply_register(chip->dev, &chip->usb_psy);
4743 if (rc < 0) {
4744 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004745 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004746 }
4747
David Keitel6ed71a52012-01-30 12:42:18 -08004748 rc = power_supply_register(chip->dev, &chip->dc_psy);
4749 if (rc < 0) {
4750 pr_err("power_supply_register usb failed rc = %d\n", rc);
4751 goto unregister_usb;
4752 }
4753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 rc = power_supply_register(chip->dev, &chip->batt_psy);
4755 if (rc < 0) {
4756 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004757 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 }
4759
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004760 platform_set_drvdata(pdev, chip);
4761 the_chip = chip;
4762
4763 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004764 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004765 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4766 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004767 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004768
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004769 INIT_WORK(&chip->bms_notify.work, bms_notify);
4770 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4771
4772 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4773 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 rc = request_irqs(chip, pdev);
4776 if (rc) {
4777 pr_err("couldn't register interrupts rc=%d\n", rc);
4778 goto unregister_batt;
4779 }
4780
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004781 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004782 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004783 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004784 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004786 create_debugfs_entries(chip);
4787
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788 /* determine what state the charger is in */
4789 determine_initial_state(chip);
4790
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004791 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004792 schedule_delayed_work(&chip->update_heartbeat_work,
4793 round_jiffies_relative(msecs_to_jiffies
4794 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004795 return 0;
4796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004798 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004799 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004800unregister_dc:
4801 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004802unregister_usb:
4803 power_supply_unregister(&chip->usb_psy);
4804free_chip:
4805 kfree(chip);
4806 return rc;
4807}
4808
4809static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4810{
4811 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4812
4813 free_irqs(chip);
4814 platform_set_drvdata(pdev, NULL);
4815 the_chip = NULL;
4816 kfree(chip);
4817 return 0;
4818}
David Keitelf2226022011-12-13 15:55:50 -08004819static const struct dev_pm_ops pm8921_pm_ops = {
4820 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004821 .suspend_noirq = pm8921_charger_suspend_noirq,
4822 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004823 .resume = pm8921_charger_resume,
4824};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004825static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004826 .probe = pm8921_charger_probe,
4827 .remove = __devexit_p(pm8921_charger_remove),
4828 .driver = {
4829 .name = PM8921_CHARGER_DEV_NAME,
4830 .owner = THIS_MODULE,
4831 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004832 },
4833};
4834
4835static int __init pm8921_charger_init(void)
4836{
4837 return platform_driver_register(&pm8921_charger_driver);
4838}
4839
4840static void __exit pm8921_charger_exit(void)
4841{
4842 platform_driver_unregister(&pm8921_charger_driver);
4843}
4844
4845late_initcall(pm8921_charger_init);
4846module_exit(pm8921_charger_exit);
4847
4848MODULE_LICENSE("GPL v2");
4849MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4850MODULE_VERSION("1.0");
4851MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);