blob: 5136fdf376c1dfcb546399349f9f2354ad6b2d98 [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
3184#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003185static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3186 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003187{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003188 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003189 int vbat_batt_terminal_mv;
3190 int reg_loop;
3191 int delta_mv = 0;
3192
3193 if (chip->rconn_mohm == 0) {
3194 pr_debug("Exiting as rconn_mohm is 0\n");
3195 return;
3196 }
3197 /* adjust vdd_max only in normal temperature zone */
3198 if (chip->is_bat_cool || chip->is_bat_warm) {
3199 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3200 chip->is_bat_cool, chip->is_bat_warm);
3201 return;
3202 }
3203
3204 reg_loop = pm_chg_get_regulation_loop(chip);
3205 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3206 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3207 reg_loop);
3208 return;
3209 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003210 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3211 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3212
3213 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3214
3215 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3216 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3217 delta_mv,
3218 programmed_vdd_max,
3219 adj_vdd_max_mv);
3220
3221 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3222 pr_debug("adj vdd_max lower than default max voltage\n");
3223 return;
3224 }
3225
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003226 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3227 * PM8921_CHG_VDDMAX_RES_MV;
3228
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003229 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3230 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003231 pr_debug("adjusting vdd_max_mv to %d to make "
3232 "vbat_batt_termial_uv = %d to %d\n",
3233 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3234 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3235}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003236
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003237static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3238{
3239 if (chip->is_bat_cool)
3240 pm_chg_vbatdet_set(the_chip,
3241 the_chip->cool_bat_voltage
3242 - the_chip->resume_voltage_delta);
3243 else if (chip->is_bat_warm)
3244 pm_chg_vbatdet_set(the_chip,
3245 the_chip->warm_bat_voltage
3246 - the_chip->resume_voltage_delta);
3247 else
3248 pm_chg_vbatdet_set(the_chip,
3249 the_chip->max_voltage_mv
3250 - the_chip->resume_voltage_delta);
3251}
3252
3253static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3254{
3255 unsigned int chg_current = chip->max_bat_chg_current;
3256
3257 if (chip->is_bat_cool)
3258 chg_current = min(chg_current, chip->cool_bat_chg_current);
3259
3260 if (chip->is_bat_warm)
3261 chg_current = min(chg_current, chip->warm_bat_chg_current);
3262
3263 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3264 chg_current = min(chg_current,
3265 chip->thermal_mitigation[thermal_mitigation]);
3266
3267 pm_chg_ibatmax_set(the_chip, chg_current);
3268}
3269
3270#define TEMP_HYSTERISIS_DECIDEGC 20
3271static void battery_cool(bool enter)
3272{
3273 pr_debug("enter = %d\n", enter);
3274 if (enter == the_chip->is_bat_cool)
3275 return;
3276 the_chip->is_bat_cool = enter;
3277 if (enter)
3278 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3279 else
3280 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3281 set_appropriate_battery_current(the_chip);
3282 set_appropriate_vbatdet(the_chip);
3283}
3284
3285static void battery_warm(bool enter)
3286{
3287 pr_debug("enter = %d\n", enter);
3288 if (enter == the_chip->is_bat_warm)
3289 return;
3290 the_chip->is_bat_warm = enter;
3291 if (enter)
3292 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3293 else
3294 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3295
3296 set_appropriate_battery_current(the_chip);
3297 set_appropriate_vbatdet(the_chip);
3298}
3299
3300static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3301{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303302 int temp = 0, rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003303
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303304 rc = get_prop_batt_temp(chip, &temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003305 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3306 temp, chip->warm_temp_dc,
3307 chip->cool_temp_dc);
3308
3309 if (chip->warm_temp_dc != INT_MIN) {
3310 if (chip->is_bat_warm
3311 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3312 battery_warm(false);
3313 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3314 battery_warm(true);
3315 }
3316
3317 if (chip->cool_temp_dc != INT_MIN) {
3318 if (chip->is_bat_cool
3319 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3320 battery_cool(false);
3321 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3322 battery_cool(true);
3323 }
3324}
3325
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003326enum {
3327 CHG_IN_PROGRESS,
3328 CHG_NOT_IN_PROGRESS,
3329 CHG_FINISHED,
3330};
3331
3332#define VBAT_TOLERANCE_MV 70
3333#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003334static int is_charging_finished(struct pm8921_chg_chip *chip,
3335 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003336{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003337 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003338 int regulation_loop, fast_chg, vcp;
3339 int rc;
3340 static int last_vbat_programmed = -EINVAL;
3341
3342 if (!is_ext_charging(chip)) {
3343 /* return if the battery is not being fastcharged */
3344 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3345 pr_debug("fast_chg = %d\n", fast_chg);
3346 if (fast_chg == 0)
3347 return CHG_NOT_IN_PROGRESS;
3348
3349 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3350 pr_debug("vcp = %d\n", vcp);
3351 if (vcp == 1)
3352 return CHG_IN_PROGRESS;
3353
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003354 /* reset count if battery is hot/cold */
3355 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3356 pr_debug("batt_temp_ok = %d\n", rc);
3357 if (rc == 0)
3358 return CHG_IN_PROGRESS;
3359
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003360 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3361 if (rc) {
3362 pr_err("couldnt read vddmax rc = %d\n", rc);
3363 return CHG_IN_PROGRESS;
3364 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003365 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3366 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003367
3368 if (last_vbat_programmed == -EINVAL)
3369 last_vbat_programmed = vbat_programmed;
3370 if (last_vbat_programmed != vbat_programmed) {
3371 /* vddmax changed, reset and check again */
3372 pr_debug("vddmax = %d last_vdd_max=%d\n",
3373 vbat_programmed, last_vbat_programmed);
3374 last_vbat_programmed = vbat_programmed;
3375 return CHG_IN_PROGRESS;
3376 }
3377
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003378 if (chip->is_bat_cool)
3379 vbat_intended = chip->cool_bat_voltage;
3380 else if (chip->is_bat_warm)
3381 vbat_intended = chip->warm_bat_voltage;
3382 else
3383 vbat_intended = chip->max_voltage_mv;
3384
3385 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3386 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3387 vbat_batt_terminal_uv,
3388 vbat_intended);
3389 return CHG_IN_PROGRESS;
3390 }
3391
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003392 regulation_loop = pm_chg_get_regulation_loop(chip);
3393 if (regulation_loop < 0) {
3394 pr_err("couldnt read the regulation loop err=%d\n",
3395 regulation_loop);
3396 return CHG_IN_PROGRESS;
3397 }
3398 pr_debug("regulation_loop=%d\n", regulation_loop);
3399
3400 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3401 return CHG_IN_PROGRESS;
3402 } /* !is_ext_charging */
3403
3404 /* reset count if battery chg current is more than iterm */
3405 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3406 if (rc) {
3407 pr_err("couldnt read iterm rc = %d\n", rc);
3408 return CHG_IN_PROGRESS;
3409 }
3410
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003411 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3412 iterm_programmed, ichg_meas_ma);
3413 /*
3414 * ichg_meas_ma < 0 means battery is drawing current
3415 * ichg_meas_ma > 0 means battery is providing current
3416 */
3417 if (ichg_meas_ma > 0)
3418 return CHG_IN_PROGRESS;
3419
3420 if (ichg_meas_ma * -1 > iterm_programmed)
3421 return CHG_IN_PROGRESS;
3422
3423 return CHG_FINISHED;
3424}
3425
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003426#define COMP_OVERRIDE_HOT_BANK 6
3427#define COMP_OVERRIDE_COLD_BANK 7
3428#define COMP_OVERRIDE_BIT BIT(1)
3429static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3430{
3431 u8 val;
3432 int rc = 0;
3433
3434 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3435
3436 if (flag)
3437 val |= 0x01;
3438
3439 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3440 if (rc < 0)
3441 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3442
3443 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3444 return rc;
3445}
3446
3447static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3448{
3449 u8 val;
3450 int rc = 0;
3451
3452 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3453
3454 if (flag)
3455 val |= 0x01;
3456
3457 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3458 if (rc < 0)
3459 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3460
3461 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3462 return rc;
3463}
3464
3465static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3466{
3467 int rc = 0;
3468 u8 reg;
3469 u8 val;
3470
3471 val = COMP_OVERRIDE_HOT_BANK << 2;
3472 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3473 if (rc < 0) {
3474 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3475 goto cold_init;
3476 }
3477 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3478 if (rc < 0) {
3479 pr_err("Could not read bank %d of override rc = %d\n",
3480 COMP_OVERRIDE_HOT_BANK, rc);
3481 goto cold_init;
3482 }
3483 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3484 /* for now override it as not hot */
3485 rc = pm_chg_override_hot(chip, 0);
3486 if (rc < 0)
3487 pr_err("Could not override hot rc = %d\n", rc);
3488 }
3489
3490cold_init:
3491 val = COMP_OVERRIDE_COLD_BANK << 2;
3492 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3493 if (rc < 0) {
3494 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3495 return;
3496 }
3497 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3498 if (rc < 0) {
3499 pr_err("Could not read bank %d of override rc = %d\n",
3500 COMP_OVERRIDE_COLD_BANK, rc);
3501 return;
3502 }
3503 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3504 /* for now override it as not cold */
3505 rc = pm_chg_override_cold(chip, 0);
3506 if (rc < 0)
3507 pr_err("Could not override cold rc = %d\n", rc);
3508 }
3509}
3510
3511static void btc_override_worker(struct work_struct *work)
3512{
3513 int decidegc;
3514 int temp;
3515 int rc = 0;
3516 struct delayed_work *dwork = to_delayed_work(work);
3517 struct pm8921_chg_chip *chip = container_of(dwork,
3518 struct pm8921_chg_chip, btc_override_work);
3519
3520 if (!chip->btc_override) {
3521 pr_err("called when not enabled\n");
3522 return;
3523 }
3524
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303525 rc = get_prop_batt_temp(chip, &decidegc);
3526 if (rc) {
3527 pr_info("Failed to read temperature\n");
3528 goto fail_btc_temp;
3529 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003530
3531 pr_debug("temp=%d\n", decidegc);
3532
3533 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3534 if (temp) {
3535 if (decidegc < chip->btc_override_hot_decidegc)
3536 /* stop forcing batt hot */
3537 rc = pm_chg_override_hot(chip, 0);
3538 if (rc)
3539 pr_err("Couldnt write 0 to hot comp\n");
3540 } else {
3541 if (decidegc >= chip->btc_override_hot_decidegc)
3542 /* start forcing batt hot */
3543 rc = pm_chg_override_hot(chip, 1);
3544 if (rc && chip->btc_panic_if_cant_stop_chg)
3545 panic("Couldnt override comps to stop chg\n");
3546 }
3547
3548 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3549 if (temp) {
3550 if (decidegc > chip->btc_override_cold_decidegc)
3551 /* stop forcing batt cold */
3552 rc = pm_chg_override_cold(chip, 0);
3553 if (rc)
3554 pr_err("Couldnt write 0 to cold comp\n");
3555 } else {
3556 if (decidegc <= chip->btc_override_cold_decidegc)
3557 /* start forcing batt cold */
3558 rc = pm_chg_override_cold(chip, 1);
3559 if (rc && chip->btc_panic_if_cant_stop_chg)
3560 panic("Couldnt override comps to stop chg\n");
3561 }
3562
3563 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3564 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3565 schedule_delayed_work(&chip->btc_override_work,
3566 round_jiffies_relative(msecs_to_jiffies
3567 (chip->btc_delay_ms)));
3568 return;
3569 }
3570
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303571fail_btc_temp:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003572 rc = pm_chg_override_hot(chip, 0);
3573 if (rc)
3574 pr_err("Couldnt write 0 to hot comp\n");
3575 rc = pm_chg_override_cold(chip, 0);
3576 if (rc)
3577 pr_err("Couldnt write 0 to cold comp\n");
3578}
3579
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003580/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003581 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003582 * has happened
3583 *
3584 * If all conditions favouring, if the charge current is
3585 * less than the term current for three consecutive times
3586 * an EOC has happened.
3587 * The wakelock is released if there is no need to reshedule
3588 * - this happens when the battery is removed or EOC has
3589 * happened
3590 */
3591#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003592static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003593{
3594 struct delayed_work *dwork = to_delayed_work(work);
3595 struct pm8921_chg_chip *chip = container_of(dwork,
3596 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003597 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003598 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003599 int vbat_meas_uv, vbat_meas_mv;
3600 int ichg_meas_ua, ichg_meas_ma;
3601 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003602
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003603 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3604 &ichg_meas_ua, &vbat_meas_uv);
3605 vbat_meas_mv = vbat_meas_uv / 1000;
3606 /* rconn_mohm is in milliOhms */
3607 ichg_meas_ma = ichg_meas_ua / 1000;
3608 vbat_batt_terminal_uv = vbat_meas_uv
3609 + ichg_meas_ma
3610 * the_chip->rconn_mohm;
3611
3612 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003613
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003614 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003615 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003616 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003617 }
3618
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003619 if (end == CHG_FINISHED) {
3620 count++;
3621 } else {
3622 count = 0;
3623 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003624
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003625 if (count == CONSECUTIVE_COUNT) {
3626 count = 0;
3627 pr_info("End of Charging\n");
3628
3629 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003630
Amir Samuelovd31ef502011-10-26 14:41:36 +02003631 if (is_ext_charging(chip))
3632 chip->ext_charge_done = true;
3633
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003634 if (chip->is_bat_warm || chip->is_bat_cool)
3635 chip->bms_notify.is_battery_full = 0;
3636 else
3637 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003638 /* declare end of charging by invoking chgdone interrupt */
3639 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003640 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003641 check_temp_thresholds(chip);
3642 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003643 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003644 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003645 round_jiffies_relative(msecs_to_jiffies
3646 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003647 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003648 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003649
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003650eoc_worker_stop:
3651 wake_unlock(&chip->eoc_wake_lock);
3652 /* set the vbatdet back, in case it was changed to trigger charging */
3653 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003654}
3655
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003656/**
3657 * set_disable_status_param -
3658 *
3659 * Internal function to disable battery charging and also disable drawing
3660 * any current from the source. The device is forced to run on a battery
3661 * after this.
3662 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663static int set_disable_status_param(const char *val, struct kernel_param *kp)
3664{
3665 int ret;
3666 struct pm8921_chg_chip *chip = the_chip;
3667
3668 ret = param_set_int(val, kp);
3669 if (ret) {
3670 pr_err("error setting value %d\n", ret);
3671 return ret;
3672 }
3673 pr_info("factory set disable param to %d\n", charging_disabled);
3674 if (chip) {
3675 pm_chg_auto_enable(chip, !charging_disabled);
3676 pm_chg_charge_dis(chip, charging_disabled);
3677 }
3678 return 0;
3679}
3680module_param_call(disabled, set_disable_status_param, param_get_uint,
3681 &charging_disabled, 0644);
3682
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003683static int rconn_mohm;
3684static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3685{
3686 int ret;
3687 struct pm8921_chg_chip *chip = the_chip;
3688
3689 ret = param_set_int(val, kp);
3690 if (ret) {
3691 pr_err("error setting value %d\n", ret);
3692 return ret;
3693 }
3694 if (chip)
3695 chip->rconn_mohm = rconn_mohm;
3696 return 0;
3697}
3698module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3699 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003700/**
3701 * set_thermal_mitigation_level -
3702 *
3703 * Internal function to control battery charging current to reduce
3704 * temperature
3705 */
3706static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3707{
3708 int ret;
3709 struct pm8921_chg_chip *chip = the_chip;
3710
3711 ret = param_set_int(val, kp);
3712 if (ret) {
3713 pr_err("error setting value %d\n", ret);
3714 return ret;
3715 }
3716
3717 if (!chip) {
3718 pr_err("called before init\n");
3719 return -EINVAL;
3720 }
3721
3722 if (!chip->thermal_mitigation) {
3723 pr_err("no thermal mitigation\n");
3724 return -EINVAL;
3725 }
3726
3727 if (thermal_mitigation < 0
3728 || thermal_mitigation >= chip->thermal_levels) {
3729 pr_err("out of bound level selected\n");
3730 return -EINVAL;
3731 }
3732
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003733 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003734 return ret;
3735}
3736module_param_call(thermal_mitigation, set_therm_mitigation_level,
3737 param_get_uint,
3738 &thermal_mitigation, 0644);
3739
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003740static int set_usb_max_current(const char *val, struct kernel_param *kp)
3741{
3742 int ret, mA;
3743 struct pm8921_chg_chip *chip = the_chip;
3744
3745 ret = param_set_int(val, kp);
3746 if (ret) {
3747 pr_err("error setting value %d\n", ret);
3748 return ret;
3749 }
3750 if (chip) {
3751 pr_warn("setting current max to %d\n", usb_max_current);
3752 pm_chg_iusbmax_get(chip, &mA);
3753 if (mA > usb_max_current)
3754 pm8921_charger_vbus_draw(usb_max_current);
3755 return 0;
3756 }
3757 return -EINVAL;
3758}
David Keitelacf57c82012-03-07 18:48:50 -08003759module_param_call(usb_max_current, set_usb_max_current,
3760 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762static void free_irqs(struct pm8921_chg_chip *chip)
3763{
3764 int i;
3765
3766 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3767 if (chip->pmic_chg_irq[i]) {
3768 free_irq(chip->pmic_chg_irq[i], chip);
3769 chip->pmic_chg_irq[i] = 0;
3770 }
3771}
3772
David Keitel88e1b572012-01-11 11:57:14 -08003773/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003774static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3775{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003776 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003777 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778
3779 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3780 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3781
3782 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003783 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003784 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003785 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003786 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003787 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003788
3789 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3790 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3791 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003792 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003793 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3794 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003795 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003796 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3797 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003798 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003799
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003800 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3801 if (usb_chg_current)
3802 /*
3803 * Reissue a vbus draw call only if a battery
3804 * or DC is present. We don't want to brown out the
3805 * device if usb is its only source
3806 */
3807 __pm8921_charger_vbus_draw(usb_chg_current);
3808 usb_chg_current = 0;
3809
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003810 /*
3811 * The bootloader could have started charging, a fastchg interrupt
3812 * might not happen. Check the real time status and if it is fast
3813 * charging invoke the handler so that the eoc worker could be
3814 * started
3815 */
3816 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3817 if (is_fast_chg)
3818 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819
3820 fsm_state = pm_chg_get_fsm_state(chip);
3821 if (is_battery_charging(fsm_state)) {
3822 chip->bms_notify.is_charging = 1;
3823 pm8921_bms_charging_began();
3824 }
3825
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003826 check_battery_valid(chip);
3827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003828 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3829 chip->usb_present,
3830 chip->dc_present,
3831 get_prop_batt_present(chip),
3832 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003833
3834 /* Determine which USB trim column to use */
3835 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3836 chip->usb_trim_table = usb_trim_8917_table;
3837 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3838 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839}
3840
3841struct pm_chg_irq_init_data {
3842 unsigned int irq_id;
3843 char *name;
3844 unsigned long flags;
3845 irqreturn_t (*handler)(int, void *);
3846};
3847
3848#define CHG_IRQ(_id, _flags, _handler) \
3849{ \
3850 .irq_id = _id, \
3851 .name = #_id, \
3852 .flags = _flags, \
3853 .handler = _handler, \
3854}
3855struct pm_chg_irq_init_data chg_irq_data[] = {
3856 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3857 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003858 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3859 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003860 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3861 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003862 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3863 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3864 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3865 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3866 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3867 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3868 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3869 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003870 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3871 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003872 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3873 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3874 batt_removed_irq_handler),
3875 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3876 batttemp_hot_irq_handler),
3877 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3878 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3879 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003880 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3881 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003882 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3883 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003884 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3885 coarse_det_low_irq_handler),
3886 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3887 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3888 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3889 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3890 batfet_irq_handler),
3891 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3892 dcin_valid_irq_handler),
3893 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3894 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003895 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896};
3897
3898static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3899 struct platform_device *pdev)
3900{
3901 struct resource *res;
3902 int ret, i;
3903
3904 ret = 0;
3905 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3906
3907 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3908 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3909 chg_irq_data[i].name);
3910 if (res == NULL) {
3911 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3912 goto err_out;
3913 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003914 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003915 ret = request_irq(res->start, chg_irq_data[i].handler,
3916 chg_irq_data[i].flags,
3917 chg_irq_data[i].name, chip);
3918 if (ret < 0) {
3919 pr_err("couldn't request %d (%s) %d\n", res->start,
3920 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003921 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003922 goto err_out;
3923 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003924 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3925 }
3926 return 0;
3927
3928err_out:
3929 free_irqs(chip);
3930 return -EINVAL;
3931}
3932
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003933static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3934{
3935 int err;
3936 u8 temp;
3937
3938 temp = 0xD1;
3939 err = pm_chg_write(chip, CHG_TEST, temp);
3940 if (err) {
3941 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3942 return;
3943 }
3944
3945 temp = 0xD3;
3946 err = pm_chg_write(chip, CHG_TEST, temp);
3947 if (err) {
3948 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3949 return;
3950 }
3951
3952 temp = 0xD1;
3953 err = pm_chg_write(chip, CHG_TEST, temp);
3954 if (err) {
3955 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3956 return;
3957 }
3958
3959 temp = 0xD5;
3960 err = pm_chg_write(chip, CHG_TEST, temp);
3961 if (err) {
3962 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3963 return;
3964 }
3965
3966 udelay(183);
3967
3968 temp = 0xD1;
3969 err = pm_chg_write(chip, CHG_TEST, temp);
3970 if (err) {
3971 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3972 return;
3973 }
3974
3975 temp = 0xD0;
3976 err = pm_chg_write(chip, CHG_TEST, temp);
3977 if (err) {
3978 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3979 return;
3980 }
3981 udelay(32);
3982
3983 temp = 0xD1;
3984 err = pm_chg_write(chip, CHG_TEST, temp);
3985 if (err) {
3986 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3987 return;
3988 }
3989
3990 temp = 0xD3;
3991 err = pm_chg_write(chip, CHG_TEST, temp);
3992 if (err) {
3993 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3994 return;
3995 }
3996}
3997
3998static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3999{
4000 int err;
4001 u8 temp;
4002
4003 temp = 0xD1;
4004 err = pm_chg_write(chip, CHG_TEST, temp);
4005 if (err) {
4006 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4007 return;
4008 }
4009
4010 temp = 0xD0;
4011 err = pm_chg_write(chip, CHG_TEST, temp);
4012 if (err) {
4013 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4014 return;
4015 }
4016}
4017
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004018#define VREF_BATT_THERM_FORCE_ON BIT(7)
4019static void detect_battery_removal(struct pm8921_chg_chip *chip)
4020{
4021 u8 temp;
4022
4023 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4024 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4025
4026 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4027 /*
4028 * batt therm force on bit is battery backed and is default 0
4029 * The charger sets this bit at init time. If this bit is found
4030 * 0 that means the battery was removed. Tell the bms about it
4031 */
4032 pm8921_bms_invalidate_shutdown_soc();
4033}
4034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004035#define ENUM_TIMER_STOP_BIT BIT(1)
4036#define BOOT_DONE_BIT BIT(6)
4037#define CHG_BATFET_ON_BIT BIT(3)
4038#define CHG_VCP_EN BIT(0)
4039#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4040#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004041#define PM_SUB_REV 0x001
4042#define MIN_CHARGE_CURRENT_MA 350
4043#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4045{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004046 u8 subrev;
4047 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004049 /* forcing 19p2mhz before accessing any charger registers */
4050 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004051
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004052 detect_battery_removal(chip);
4053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004054 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004055 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004056 if (rc) {
4057 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4058 return rc;
4059 }
4060
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004061 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4062
4063 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4064 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4065
4066 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 if (rc) {
4069 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004070 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 return rc;
4072 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004073 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004074 chip->max_voltage_mv
4075 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076 if (rc) {
4077 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004078 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004079 return rc;
4080 }
4081
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004082 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083 if (rc) {
4084 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004085 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 return rc;
4087 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004088
4089 if (chip->safe_current_ma == 0)
4090 chip->safe_current_ma = SAFE_CURRENT_MA;
4091
4092 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004093 if (rc) {
4094 pr_err("Failed to set max voltage to %d rc=%d\n",
4095 SAFE_CURRENT_MA, rc);
4096 return rc;
4097 }
4098
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004099 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004100 if (rc) {
4101 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4102 return rc;
4103 }
4104
4105 rc = pm_chg_iterm_set(chip, chip->term_current);
4106 if (rc) {
4107 pr_err("Failed to set term current to %d rc=%d\n",
4108 chip->term_current, rc);
4109 return rc;
4110 }
4111
4112 /* Disable the ENUM TIMER */
4113 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4114 ENUM_TIMER_STOP_BIT);
4115 if (rc) {
4116 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4117 return rc;
4118 }
4119
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004120 fcc_uah = pm8921_bms_get_fcc();
4121 if (fcc_uah > 0) {
4122 safety_time = div_s64((s64)fcc_uah * 60,
4123 1000 * MIN_CHARGE_CURRENT_MA);
4124 /* add 20 minutes of buffer time */
4125 safety_time += 20;
4126
4127 /* make sure we do not exceed the maximum programmable time */
4128 if (safety_time > PM8921_CHG_TCHG_MAX)
4129 safety_time = PM8921_CHG_TCHG_MAX;
4130 }
4131
4132 rc = pm_chg_tchg_max_set(chip, safety_time);
4133 if (rc) {
4134 pr_err("Failed to set max time to %d minutes rc=%d\n",
4135 safety_time, rc);
4136 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004137 }
4138
4139 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004140 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004141 if (rc) {
4142 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004143 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004144 return rc;
4145 }
4146 }
4147
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004148 if (chip->vin_min != 0) {
4149 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4150 if (rc) {
4151 pr_err("Failed to set vin min to %d mV rc=%d\n",
4152 chip->vin_min, rc);
4153 return rc;
4154 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004155 } else {
4156 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004157 }
4158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 rc = pm_chg_disable_wd(chip);
4160 if (rc) {
4161 pr_err("Failed to disable wd rc=%d\n", rc);
4162 return rc;
4163 }
4164
4165 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4166 CHG_BAT_TEMP_DIS_BIT, 0);
4167 if (rc) {
4168 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4169 return rc;
4170 }
4171 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004172 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4173 rc = pm_chg_write(chip,
4174 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4175 else
4176 rc = pm_chg_write(chip,
4177 CHG_BUCK_CLOCK_CTRL, 0x15);
4178
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004179 if (rc) {
4180 pr_err("Failed to switch buck clk rc=%d\n", rc);
4181 return rc;
4182 }
4183
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004184 if (chip->trkl_voltage != 0) {
4185 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4186 if (rc) {
4187 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4188 chip->trkl_voltage, rc);
4189 return rc;
4190 }
4191 }
4192
4193 if (chip->weak_voltage != 0) {
4194 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4195 if (rc) {
4196 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4197 chip->weak_voltage, rc);
4198 return rc;
4199 }
4200 }
4201
4202 if (chip->trkl_current != 0) {
4203 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4204 if (rc) {
4205 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4206 chip->trkl_voltage, rc);
4207 return rc;
4208 }
4209 }
4210
4211 if (chip->weak_current != 0) {
4212 rc = pm_chg_iweak_set(chip, chip->weak_current);
4213 if (rc) {
4214 pr_err("Failed to set weak current to %dmA rc=%d\n",
4215 chip->weak_current, rc);
4216 return rc;
4217 }
4218 }
4219
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004220 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4221 if (rc) {
4222 pr_err("Failed to set cold config %d rc=%d\n",
4223 chip->cold_thr, rc);
4224 }
4225
4226 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4227 if (rc) {
4228 pr_err("Failed to set hot config %d rc=%d\n",
4229 chip->hot_thr, rc);
4230 }
4231
Jay Chokshid674a512012-03-15 14:06:04 -07004232 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4233 if (rc) {
4234 pr_err("Failed to set charger LED src config %d rc=%d\n",
4235 chip->led_src_config, rc);
4236 }
4237
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004238 /* Workarounds for die 3.0 */
4239 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4240 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4241 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4242 if (rc) {
4243 pr_err("read failed: addr=%03X, rc=%d\n",
4244 PM_SUB_REV, rc);
4245 return rc;
4246 }
4247 /* Check if die 3.0.1 is present */
4248 if (subrev & 0x1)
4249 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4250 else
4251 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 }
4253
David Keitel0789fc62012-06-07 17:43:27 -07004254 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004255 /* Set PM8917 USB_OVP debounce time to 15 ms */
4256 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4257 OVP_DEBOUNCE_TIME, 0x6);
4258 if (rc) {
4259 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4260 return rc;
4261 }
4262
4263 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004264 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004265 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004266 rc = pm_chg_uvd_threshold_set(chip,
4267 chip->uvd_voltage_mv);
4268 if (rc) {
4269 pr_err("Failed to set UVD threshold %drc=%d\n",
4270 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004271 return rc;
4272 }
David Keitel0789fc62012-06-07 17:43:27 -07004273 }
4274 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004275
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004276 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004277
David Keitela3c0d822011-11-03 14:18:52 -07004278 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004279 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004280
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004281 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4282 VREF_BATT_THERM_FORCE_ON);
4283 if (rc)
4284 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 rc = pm_chg_charge_dis(chip, charging_disabled);
4287 if (rc) {
4288 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4289 return rc;
4290 }
4291
4292 rc = pm_chg_auto_enable(chip, !charging_disabled);
4293 if (rc) {
4294 pr_err("Failed to enable charging rc=%d\n", rc);
4295 return rc;
4296 }
4297
4298 return 0;
4299}
4300
4301static int get_rt_status(void *data, u64 * val)
4302{
4303 int i = (int)data;
4304 int ret;
4305
4306 /* global irq number is passed in via data */
4307 ret = pm_chg_get_rt_status(the_chip, i);
4308 *val = ret;
4309 return 0;
4310}
4311DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4312
4313static int get_fsm_status(void *data, u64 * val)
4314{
4315 u8 temp;
4316
4317 temp = pm_chg_get_fsm_state(the_chip);
4318 *val = temp;
4319 return 0;
4320}
4321DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4322
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004323static int get_reg_loop(void *data, u64 * val)
4324{
4325 u8 temp;
4326
4327 if (!the_chip) {
4328 pr_err("%s called before init\n", __func__);
4329 return -EINVAL;
4330 }
4331 temp = pm_chg_get_regulation_loop(the_chip);
4332 *val = temp;
4333 return 0;
4334}
4335DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004337static int get_reg(void *data, u64 * val)
4338{
4339 int addr = (int)data;
4340 int ret;
4341 u8 temp;
4342
4343 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4344 if (ret) {
4345 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4346 addr, temp, ret);
4347 return -EAGAIN;
4348 }
4349 *val = temp;
4350 return 0;
4351}
4352
4353static int set_reg(void *data, u64 val)
4354{
4355 int addr = (int)data;
4356 int ret;
4357 u8 temp;
4358
4359 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004360 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004362 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004363 addr, temp, ret);
4364 return -EAGAIN;
4365 }
4366 return 0;
4367}
4368DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4369
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004370static int reg_loop;
4371#define MAX_REG_LOOP_CHAR 10
4372static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4373{
4374 u8 temp;
4375
4376 if (!the_chip) {
4377 pr_err("called before init\n");
4378 return -EINVAL;
4379 }
4380 temp = pm_chg_get_regulation_loop(the_chip);
4381 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4382}
4383module_param_call(reg_loop, NULL, get_reg_loop_param,
4384 &reg_loop, 0644);
4385
4386static int max_chg_ma;
4387#define MAX_MA_CHAR 10
4388static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4389{
4390 if (!the_chip) {
4391 pr_err("called before init\n");
4392 return -EINVAL;
4393 }
4394 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4395}
4396module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4397 &max_chg_ma, 0644);
4398static int ibatmax_ma;
4399static int set_ibat_max(const char *val, struct kernel_param *kp)
4400{
4401 int rc;
4402
4403 if (!the_chip) {
4404 pr_err("called before init\n");
4405 return -EINVAL;
4406 }
4407
4408 rc = param_set_int(val, kp);
4409 if (rc) {
4410 pr_err("error setting value %d\n", rc);
4411 return rc;
4412 }
4413
4414 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4415 <= the_chip->ibatmax_max_adj_ma) {
4416 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4417 if (rc) {
4418 pr_err("Failed to set ibatmax rc = %d\n", rc);
4419 return rc;
4420 }
4421 }
4422
4423 return 0;
4424}
4425static int get_ibat_max(char *buf, struct kernel_param *kp)
4426{
4427 int ibat_ma;
4428 int rc;
4429
4430 if (!the_chip) {
4431 pr_err("called before init\n");
4432 return -EINVAL;
4433 }
4434
4435 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4436 if (rc) {
4437 pr_err("ibatmax_get error = %d\n", rc);
4438 return rc;
4439 }
4440
4441 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4442}
4443module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4444 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004445enum {
4446 BAT_WARM_ZONE,
4447 BAT_COOL_ZONE,
4448};
4449static int get_warm_cool(void *data, u64 * val)
4450{
4451 if (!the_chip) {
4452 pr_err("%s called before init\n", __func__);
4453 return -EINVAL;
4454 }
4455 if ((int)data == BAT_WARM_ZONE)
4456 *val = the_chip->is_bat_warm;
4457 if ((int)data == BAT_COOL_ZONE)
4458 *val = the_chip->is_bat_cool;
4459 return 0;
4460}
4461DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004463static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4464{
4465 int i;
4466
4467 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4468
4469 if (IS_ERR(chip->dent)) {
4470 pr_err("pmic charger couldnt create debugfs dir\n");
4471 return;
4472 }
4473
4474 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4475 (void *)CHG_CNTRL, &reg_fops);
4476 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4477 (void *)CHG_CNTRL_2, &reg_fops);
4478 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4479 (void *)CHG_CNTRL_3, &reg_fops);
4480 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4481 (void *)PBL_ACCESS1, &reg_fops);
4482 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4483 (void *)PBL_ACCESS2, &reg_fops);
4484 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4485 (void *)SYS_CONFIG_1, &reg_fops);
4486 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4487 (void *)SYS_CONFIG_2, &reg_fops);
4488 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4489 (void *)CHG_VDD_MAX, &reg_fops);
4490 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4491 (void *)CHG_VDD_SAFE, &reg_fops);
4492 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4493 (void *)CHG_VBAT_DET, &reg_fops);
4494 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4495 (void *)CHG_IBAT_MAX, &reg_fops);
4496 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4497 (void *)CHG_IBAT_SAFE, &reg_fops);
4498 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4499 (void *)CHG_VIN_MIN, &reg_fops);
4500 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4501 (void *)CHG_VTRICKLE, &reg_fops);
4502 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4503 (void *)CHG_ITRICKLE, &reg_fops);
4504 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4505 (void *)CHG_ITERM, &reg_fops);
4506 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4507 (void *)CHG_TCHG_MAX, &reg_fops);
4508 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4509 (void *)CHG_TWDOG, &reg_fops);
4510 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4511 (void *)CHG_TEMP_THRESH, &reg_fops);
4512 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4513 (void *)CHG_COMP_OVR, &reg_fops);
4514 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4515 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4516 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4517 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4518 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4519 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4520 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4521 (void *)CHG_TEST, &reg_fops);
4522
4523 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4524 &fsm_fops);
4525
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004526 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4527 &reg_loop_fops);
4528
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004529 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4530 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4531 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4532 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004534 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4535 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4536 debugfs_create_file(chg_irq_data[i].name, 0444,
4537 chip->dent,
4538 (void *)chg_irq_data[i].irq_id,
4539 &rt_fops);
4540 }
4541}
4542
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004543static int pm8921_charger_suspend_noirq(struct device *dev)
4544{
4545 int rc;
4546 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4547
4548 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4549 if (rc)
4550 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004551
4552 rc = pm8921_chg_set_lpm(chip, 1);
4553 if (rc)
4554 pr_err("Failed to set lpm rc=%d\n", rc);
4555
4556 pm8921_chg_set_hw_clk_switching(chip);
4557
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004558 return 0;
4559}
4560
4561static int pm8921_charger_resume_noirq(struct device *dev)
4562{
4563 int rc;
4564 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4565
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004566 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004567
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004568 rc = pm8921_chg_set_lpm(chip, 0);
4569 if (rc)
4570 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004571
4572 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4573 VREF_BATT_THERM_FORCE_ON);
4574 if (rc)
4575 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4576 return 0;
4577}
4578
David Keitelf2226022011-12-13 15:55:50 -08004579static int pm8921_charger_resume(struct device *dev)
4580{
David Keitelf2226022011-12-13 15:55:50 -08004581 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4582
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004583 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4584 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4585 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4586 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004587
4588 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4589 is_usb_chg_plugged_in(the_chip)))
4590 schedule_delayed_work(&chip->btc_override_work, 0);
4591
David Keitelf2226022011-12-13 15:55:50 -08004592 return 0;
4593}
4594
4595static int pm8921_charger_suspend(struct device *dev)
4596{
David Keitelf2226022011-12-13 15:55:50 -08004597 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4598
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004599 if (chip->btc_override)
4600 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004601
4602 if (is_usb_chg_plugged_in(chip)) {
4603 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4604 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4605 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004606
David Keitelf2226022011-12-13 15:55:50 -08004607 return 0;
4608}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004609static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4610{
4611 int rc = 0;
4612 struct pm8921_chg_chip *chip;
4613 const struct pm8921_charger_platform_data *pdata
4614 = pdev->dev.platform_data;
4615
4616 if (!pdata) {
4617 pr_err("missing platform data\n");
4618 return -EINVAL;
4619 }
4620
4621 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4622 GFP_KERNEL);
4623 if (!chip) {
4624 pr_err("Cannot allocate pm_chg_chip\n");
4625 return -ENOMEM;
4626 }
4627
4628 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004629 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004631 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004632 chip->alarm_low_mv = pdata->alarm_low_mv;
4633 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004634 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004635 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004636 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004637 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004638 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004639 chip->term_current = pdata->term_current;
4640 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004641 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004642 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4643 chip->batt_id_min = pdata->batt_id_min;
4644 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004645 if (pdata->cool_temp != INT_MIN)
4646 chip->cool_temp_dc = pdata->cool_temp * 10;
4647 else
4648 chip->cool_temp_dc = INT_MIN;
4649
4650 if (pdata->warm_temp != INT_MIN)
4651 chip->warm_temp_dc = pdata->warm_temp * 10;
4652 else
4653 chip->warm_temp_dc = INT_MIN;
4654
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004655 chip->temp_check_period = pdata->temp_check_period;
4656 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004657 /* Assign to corresponding module parameter */
4658 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004659 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4660 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4661 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4662 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004663 chip->trkl_voltage = pdata->trkl_voltage;
4664 chip->weak_voltage = pdata->weak_voltage;
4665 chip->trkl_current = pdata->trkl_current;
4666 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004667 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004668 chip->thermal_mitigation = pdata->thermal_mitigation;
4669 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304670 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004671
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004672 chip->cold_thr = pdata->cold_thr;
4673 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004674 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004675 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004676 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004677 chip->battery_less_hardware = pdata->battery_less_hardware;
4678 chip->btc_override = pdata->btc_override;
4679 if (chip->btc_override) {
4680 chip->btc_delay_ms = pdata->btc_delay_ms;
4681 chip->btc_override_cold_decidegc
4682 = pdata->btc_override_cold_degc * 10;
4683 chip->btc_override_hot_decidegc
4684 = pdata->btc_override_hot_degc * 10;
4685 chip->btc_panic_if_cant_stop_chg
4686 = pdata->btc_panic_if_cant_stop_chg;
4687 }
4688
4689 if (chip->battery_less_hardware)
4690 charging_disabled = 1;
4691
4692 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4693 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 rc = pm8921_chg_hw_init(chip);
4696 if (rc) {
4697 pr_err("couldn't init hardware rc=%d\n", rc);
4698 goto free_chip;
4699 }
4700
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004701 if (chip->btc_override)
4702 pm8921_chg_btc_override_init(chip);
4703
4704 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304705 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004706
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004707 chip->usb_psy.name = "usb";
4708 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4709 chip->usb_psy.supplied_to = pm_power_supplied_to;
4710 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4711 chip->usb_psy.properties = pm_power_props_usb;
4712 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4713 chip->usb_psy.get_property = pm_power_get_property_usb;
4714 chip->usb_psy.set_property = pm_power_set_property_usb;
4715 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004716
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004717 chip->dc_psy.name = "pm8921-dc";
4718 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4719 chip->dc_psy.supplied_to = pm_power_supplied_to;
4720 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4721 chip->dc_psy.properties = pm_power_props_mains;
4722 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4723 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004724
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004725 chip->batt_psy.name = "battery";
4726 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4727 chip->batt_psy.properties = msm_batt_power_props;
4728 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4729 chip->batt_psy.get_property = pm_batt_power_get_property;
4730 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004731 rc = power_supply_register(chip->dev, &chip->usb_psy);
4732 if (rc < 0) {
4733 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004734 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004735 }
4736
David Keitel6ed71a52012-01-30 12:42:18 -08004737 rc = power_supply_register(chip->dev, &chip->dc_psy);
4738 if (rc < 0) {
4739 pr_err("power_supply_register usb failed rc = %d\n", rc);
4740 goto unregister_usb;
4741 }
4742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004743 rc = power_supply_register(chip->dev, &chip->batt_psy);
4744 if (rc < 0) {
4745 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004746 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747 }
4748
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004749 platform_set_drvdata(pdev, chip);
4750 the_chip = chip;
4751
4752 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004753 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004754 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4755 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004756 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004757
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004758 INIT_WORK(&chip->bms_notify.work, bms_notify);
4759 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4760
4761 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4762 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004764 rc = request_irqs(chip, pdev);
4765 if (rc) {
4766 pr_err("couldn't register interrupts rc=%d\n", rc);
4767 goto unregister_batt;
4768 }
4769
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004770 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004771 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004772 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004773 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004775 create_debugfs_entries(chip);
4776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004777 /* determine what state the charger is in */
4778 determine_initial_state(chip);
4779
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004780 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004781 schedule_delayed_work(&chip->update_heartbeat_work,
4782 round_jiffies_relative(msecs_to_jiffies
4783 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004784 return 0;
4785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004786unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004787 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004789unregister_dc:
4790 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004791unregister_usb:
4792 power_supply_unregister(&chip->usb_psy);
4793free_chip:
4794 kfree(chip);
4795 return rc;
4796}
4797
4798static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4799{
4800 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4801
4802 free_irqs(chip);
4803 platform_set_drvdata(pdev, NULL);
4804 the_chip = NULL;
4805 kfree(chip);
4806 return 0;
4807}
David Keitelf2226022011-12-13 15:55:50 -08004808static const struct dev_pm_ops pm8921_pm_ops = {
4809 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004810 .suspend_noirq = pm8921_charger_suspend_noirq,
4811 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004812 .resume = pm8921_charger_resume,
4813};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004814static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004815 .probe = pm8921_charger_probe,
4816 .remove = __devexit_p(pm8921_charger_remove),
4817 .driver = {
4818 .name = PM8921_CHARGER_DEV_NAME,
4819 .owner = THIS_MODULE,
4820 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821 },
4822};
4823
4824static int __init pm8921_charger_init(void)
4825{
4826 return platform_driver_register(&pm8921_charger_driver);
4827}
4828
4829static void __exit pm8921_charger_exit(void)
4830{
4831 platform_driver_unregister(&pm8921_charger_driver);
4832}
4833
4834late_initcall(pm8921_charger_init);
4835module_exit(pm8921_charger_exit);
4836
4837MODULE_LICENSE("GPL v2");
4838MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4839MODULE_VERSION("1.0");
4840MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);