blob: 68f4bdd4ffa1c8194f840c66fcf821fe8edf7a65 [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{
3145 /* Only look for an external supply if it hasn't been registered */
3146 if (!the_chip->ext_psy)
3147 class_for_each_device(power_supply_class, NULL, psy,
3148 __pm_batt_external_power_changed_work);
3149}
3150
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003151/**
3152 * update_heartbeat - internal function to update userspace
3153 * per update_time minutes
3154 *
3155 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003156#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003157static void update_heartbeat(struct work_struct *work)
3158{
3159 struct delayed_work *dwork = to_delayed_work(work);
3160 struct pm8921_chg_chip *chip = container_of(dwork,
3161 struct pm8921_chg_chip, update_heartbeat_work);
3162
3163 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003164 if (chip->recent_reported_soc <= 20)
3165 schedule_delayed_work(&chip->update_heartbeat_work,
3166 round_jiffies_relative(msecs_to_jiffies
3167 (LOW_SOC_HEARTBEAT_MS)));
3168 else
3169 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003170 round_jiffies_relative(msecs_to_jiffies
3171 (chip->update_time)));
3172}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003173#define VDD_LOOP_ACTIVE_BIT BIT(3)
3174#define VDD_MAX_INCREASE_MV 400
3175static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3176module_param(vdd_max_increase_mv, int, 0644);
3177
3178static int ichg_threshold_ua = -400000;
3179module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003180
3181#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003182static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3183 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003184{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003185 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003186 int vbat_batt_terminal_mv;
3187 int reg_loop;
3188 int delta_mv = 0;
3189
3190 if (chip->rconn_mohm == 0) {
3191 pr_debug("Exiting as rconn_mohm is 0\n");
3192 return;
3193 }
3194 /* adjust vdd_max only in normal temperature zone */
3195 if (chip->is_bat_cool || chip->is_bat_warm) {
3196 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3197 chip->is_bat_cool, chip->is_bat_warm);
3198 return;
3199 }
3200
3201 reg_loop = pm_chg_get_regulation_loop(chip);
3202 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3203 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3204 reg_loop);
3205 return;
3206 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003207 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3208 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3209
3210 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3211
3212 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3213 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3214 delta_mv,
3215 programmed_vdd_max,
3216 adj_vdd_max_mv);
3217
3218 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3219 pr_debug("adj vdd_max lower than default max voltage\n");
3220 return;
3221 }
3222
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003223 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3224 * PM8921_CHG_VDDMAX_RES_MV;
3225
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003226 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3227 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003228 pr_debug("adjusting vdd_max_mv to %d to make "
3229 "vbat_batt_termial_uv = %d to %d\n",
3230 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3231 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3232}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003233
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003234static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3235{
3236 if (chip->is_bat_cool)
3237 pm_chg_vbatdet_set(the_chip,
3238 the_chip->cool_bat_voltage
3239 - the_chip->resume_voltage_delta);
3240 else if (chip->is_bat_warm)
3241 pm_chg_vbatdet_set(the_chip,
3242 the_chip->warm_bat_voltage
3243 - the_chip->resume_voltage_delta);
3244 else
3245 pm_chg_vbatdet_set(the_chip,
3246 the_chip->max_voltage_mv
3247 - the_chip->resume_voltage_delta);
3248}
3249
3250static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3251{
3252 unsigned int chg_current = chip->max_bat_chg_current;
3253
3254 if (chip->is_bat_cool)
3255 chg_current = min(chg_current, chip->cool_bat_chg_current);
3256
3257 if (chip->is_bat_warm)
3258 chg_current = min(chg_current, chip->warm_bat_chg_current);
3259
3260 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3261 chg_current = min(chg_current,
3262 chip->thermal_mitigation[thermal_mitigation]);
3263
3264 pm_chg_ibatmax_set(the_chip, chg_current);
3265}
3266
3267#define TEMP_HYSTERISIS_DECIDEGC 20
3268static void battery_cool(bool enter)
3269{
3270 pr_debug("enter = %d\n", enter);
3271 if (enter == the_chip->is_bat_cool)
3272 return;
3273 the_chip->is_bat_cool = enter;
3274 if (enter)
3275 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3276 else
3277 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3278 set_appropriate_battery_current(the_chip);
3279 set_appropriate_vbatdet(the_chip);
3280}
3281
3282static void battery_warm(bool enter)
3283{
3284 pr_debug("enter = %d\n", enter);
3285 if (enter == the_chip->is_bat_warm)
3286 return;
3287 the_chip->is_bat_warm = enter;
3288 if (enter)
3289 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3290 else
3291 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3292
3293 set_appropriate_battery_current(the_chip);
3294 set_appropriate_vbatdet(the_chip);
3295}
3296
3297static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3298{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303299 int temp = 0, rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003300
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303301 rc = get_prop_batt_temp(chip, &temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003302 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3303 temp, chip->warm_temp_dc,
3304 chip->cool_temp_dc);
3305
3306 if (chip->warm_temp_dc != INT_MIN) {
3307 if (chip->is_bat_warm
3308 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3309 battery_warm(false);
3310 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3311 battery_warm(true);
3312 }
3313
3314 if (chip->cool_temp_dc != INT_MIN) {
3315 if (chip->is_bat_cool
3316 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3317 battery_cool(false);
3318 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3319 battery_cool(true);
3320 }
3321}
3322
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003323enum {
3324 CHG_IN_PROGRESS,
3325 CHG_NOT_IN_PROGRESS,
3326 CHG_FINISHED,
3327};
3328
3329#define VBAT_TOLERANCE_MV 70
3330#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003331static int is_charging_finished(struct pm8921_chg_chip *chip,
3332 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003333{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003334 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003335 int regulation_loop, fast_chg, vcp;
3336 int rc;
3337 static int last_vbat_programmed = -EINVAL;
3338
3339 if (!is_ext_charging(chip)) {
3340 /* return if the battery is not being fastcharged */
3341 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3342 pr_debug("fast_chg = %d\n", fast_chg);
3343 if (fast_chg == 0)
3344 return CHG_NOT_IN_PROGRESS;
3345
3346 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3347 pr_debug("vcp = %d\n", vcp);
3348 if (vcp == 1)
3349 return CHG_IN_PROGRESS;
3350
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003351 /* reset count if battery is hot/cold */
3352 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3353 pr_debug("batt_temp_ok = %d\n", rc);
3354 if (rc == 0)
3355 return CHG_IN_PROGRESS;
3356
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003357 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3358 if (rc) {
3359 pr_err("couldnt read vddmax rc = %d\n", rc);
3360 return CHG_IN_PROGRESS;
3361 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003362 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3363 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003364
3365 if (last_vbat_programmed == -EINVAL)
3366 last_vbat_programmed = vbat_programmed;
3367 if (last_vbat_programmed != vbat_programmed) {
3368 /* vddmax changed, reset and check again */
3369 pr_debug("vddmax = %d last_vdd_max=%d\n",
3370 vbat_programmed, last_vbat_programmed);
3371 last_vbat_programmed = vbat_programmed;
3372 return CHG_IN_PROGRESS;
3373 }
3374
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003375 if (chip->is_bat_cool)
3376 vbat_intended = chip->cool_bat_voltage;
3377 else if (chip->is_bat_warm)
3378 vbat_intended = chip->warm_bat_voltage;
3379 else
3380 vbat_intended = chip->max_voltage_mv;
3381
3382 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3383 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3384 vbat_batt_terminal_uv,
3385 vbat_intended);
3386 return CHG_IN_PROGRESS;
3387 }
3388
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003389 regulation_loop = pm_chg_get_regulation_loop(chip);
3390 if (regulation_loop < 0) {
3391 pr_err("couldnt read the regulation loop err=%d\n",
3392 regulation_loop);
3393 return CHG_IN_PROGRESS;
3394 }
3395 pr_debug("regulation_loop=%d\n", regulation_loop);
3396
3397 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3398 return CHG_IN_PROGRESS;
3399 } /* !is_ext_charging */
3400
3401 /* reset count if battery chg current is more than iterm */
3402 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3403 if (rc) {
3404 pr_err("couldnt read iterm rc = %d\n", rc);
3405 return CHG_IN_PROGRESS;
3406 }
3407
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003408 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3409 iterm_programmed, ichg_meas_ma);
3410 /*
3411 * ichg_meas_ma < 0 means battery is drawing current
3412 * ichg_meas_ma > 0 means battery is providing current
3413 */
3414 if (ichg_meas_ma > 0)
3415 return CHG_IN_PROGRESS;
3416
3417 if (ichg_meas_ma * -1 > iterm_programmed)
3418 return CHG_IN_PROGRESS;
3419
3420 return CHG_FINISHED;
3421}
3422
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003423#define COMP_OVERRIDE_HOT_BANK 6
3424#define COMP_OVERRIDE_COLD_BANK 7
3425#define COMP_OVERRIDE_BIT BIT(1)
3426static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3427{
3428 u8 val;
3429 int rc = 0;
3430
3431 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3432
3433 if (flag)
3434 val |= 0x01;
3435
3436 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3437 if (rc < 0)
3438 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3439
3440 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3441 return rc;
3442}
3443
3444static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3445{
3446 u8 val;
3447 int rc = 0;
3448
3449 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3450
3451 if (flag)
3452 val |= 0x01;
3453
3454 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3455 if (rc < 0)
3456 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3457
3458 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3459 return rc;
3460}
3461
3462static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3463{
3464 int rc = 0;
3465 u8 reg;
3466 u8 val;
3467
3468 val = COMP_OVERRIDE_HOT_BANK << 2;
3469 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3470 if (rc < 0) {
3471 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3472 goto cold_init;
3473 }
3474 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3475 if (rc < 0) {
3476 pr_err("Could not read bank %d of override rc = %d\n",
3477 COMP_OVERRIDE_HOT_BANK, rc);
3478 goto cold_init;
3479 }
3480 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3481 /* for now override it as not hot */
3482 rc = pm_chg_override_hot(chip, 0);
3483 if (rc < 0)
3484 pr_err("Could not override hot rc = %d\n", rc);
3485 }
3486
3487cold_init:
3488 val = COMP_OVERRIDE_COLD_BANK << 2;
3489 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3490 if (rc < 0) {
3491 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3492 return;
3493 }
3494 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3495 if (rc < 0) {
3496 pr_err("Could not read bank %d of override rc = %d\n",
3497 COMP_OVERRIDE_COLD_BANK, rc);
3498 return;
3499 }
3500 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3501 /* for now override it as not cold */
3502 rc = pm_chg_override_cold(chip, 0);
3503 if (rc < 0)
3504 pr_err("Could not override cold rc = %d\n", rc);
3505 }
3506}
3507
3508static void btc_override_worker(struct work_struct *work)
3509{
3510 int decidegc;
3511 int temp;
3512 int rc = 0;
3513 struct delayed_work *dwork = to_delayed_work(work);
3514 struct pm8921_chg_chip *chip = container_of(dwork,
3515 struct pm8921_chg_chip, btc_override_work);
3516
3517 if (!chip->btc_override) {
3518 pr_err("called when not enabled\n");
3519 return;
3520 }
3521
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303522 rc = get_prop_batt_temp(chip, &decidegc);
3523 if (rc) {
3524 pr_info("Failed to read temperature\n");
3525 goto fail_btc_temp;
3526 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003527
3528 pr_debug("temp=%d\n", decidegc);
3529
3530 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3531 if (temp) {
3532 if (decidegc < chip->btc_override_hot_decidegc)
3533 /* stop forcing batt hot */
3534 rc = pm_chg_override_hot(chip, 0);
3535 if (rc)
3536 pr_err("Couldnt write 0 to hot comp\n");
3537 } else {
3538 if (decidegc >= chip->btc_override_hot_decidegc)
3539 /* start forcing batt hot */
3540 rc = pm_chg_override_hot(chip, 1);
3541 if (rc && chip->btc_panic_if_cant_stop_chg)
3542 panic("Couldnt override comps to stop chg\n");
3543 }
3544
3545 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3546 if (temp) {
3547 if (decidegc > chip->btc_override_cold_decidegc)
3548 /* stop forcing batt cold */
3549 rc = pm_chg_override_cold(chip, 0);
3550 if (rc)
3551 pr_err("Couldnt write 0 to cold comp\n");
3552 } else {
3553 if (decidegc <= chip->btc_override_cold_decidegc)
3554 /* start forcing batt cold */
3555 rc = pm_chg_override_cold(chip, 1);
3556 if (rc && chip->btc_panic_if_cant_stop_chg)
3557 panic("Couldnt override comps to stop chg\n");
3558 }
3559
3560 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3561 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3562 schedule_delayed_work(&chip->btc_override_work,
3563 round_jiffies_relative(msecs_to_jiffies
3564 (chip->btc_delay_ms)));
3565 return;
3566 }
3567
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303568fail_btc_temp:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003569 rc = pm_chg_override_hot(chip, 0);
3570 if (rc)
3571 pr_err("Couldnt write 0 to hot comp\n");
3572 rc = pm_chg_override_cold(chip, 0);
3573 if (rc)
3574 pr_err("Couldnt write 0 to cold comp\n");
3575}
3576
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003577/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003578 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003579 * has happened
3580 *
3581 * If all conditions favouring, if the charge current is
3582 * less than the term current for three consecutive times
3583 * an EOC has happened.
3584 * The wakelock is released if there is no need to reshedule
3585 * - this happens when the battery is removed or EOC has
3586 * happened
3587 */
3588#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003589static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003590{
3591 struct delayed_work *dwork = to_delayed_work(work);
3592 struct pm8921_chg_chip *chip = container_of(dwork,
3593 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003594 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003595 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003596 int vbat_meas_uv, vbat_meas_mv;
3597 int ichg_meas_ua, ichg_meas_ma;
3598 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003599
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003600 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3601 &ichg_meas_ua, &vbat_meas_uv);
3602 vbat_meas_mv = vbat_meas_uv / 1000;
3603 /* rconn_mohm is in milliOhms */
3604 ichg_meas_ma = ichg_meas_ua / 1000;
3605 vbat_batt_terminal_uv = vbat_meas_uv
3606 + ichg_meas_ma
3607 * the_chip->rconn_mohm;
3608
3609 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003610
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003611 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003612 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003613 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003614 }
3615
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003616 if (end == CHG_FINISHED) {
3617 count++;
3618 } else {
3619 count = 0;
3620 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003621
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003622 if (count == CONSECUTIVE_COUNT) {
3623 count = 0;
3624 pr_info("End of Charging\n");
3625
3626 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003627
Amir Samuelovd31ef502011-10-26 14:41:36 +02003628 if (is_ext_charging(chip))
3629 chip->ext_charge_done = true;
3630
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003631 if (chip->is_bat_warm || chip->is_bat_cool)
3632 chip->bms_notify.is_battery_full = 0;
3633 else
3634 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003635 /* declare end of charging by invoking chgdone interrupt */
3636 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003637 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003638 check_temp_thresholds(chip);
3639 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003640 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003641 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003642 round_jiffies_relative(msecs_to_jiffies
3643 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003644 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003645 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003646
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003647eoc_worker_stop:
3648 wake_unlock(&chip->eoc_wake_lock);
3649 /* set the vbatdet back, in case it was changed to trigger charging */
3650 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003651}
3652
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003653/**
3654 * set_disable_status_param -
3655 *
3656 * Internal function to disable battery charging and also disable drawing
3657 * any current from the source. The device is forced to run on a battery
3658 * after this.
3659 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660static int set_disable_status_param(const char *val, struct kernel_param *kp)
3661{
3662 int ret;
3663 struct pm8921_chg_chip *chip = the_chip;
3664
3665 ret = param_set_int(val, kp);
3666 if (ret) {
3667 pr_err("error setting value %d\n", ret);
3668 return ret;
3669 }
3670 pr_info("factory set disable param to %d\n", charging_disabled);
3671 if (chip) {
3672 pm_chg_auto_enable(chip, !charging_disabled);
3673 pm_chg_charge_dis(chip, charging_disabled);
3674 }
3675 return 0;
3676}
3677module_param_call(disabled, set_disable_status_param, param_get_uint,
3678 &charging_disabled, 0644);
3679
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003680static int rconn_mohm;
3681static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3682{
3683 int ret;
3684 struct pm8921_chg_chip *chip = the_chip;
3685
3686 ret = param_set_int(val, kp);
3687 if (ret) {
3688 pr_err("error setting value %d\n", ret);
3689 return ret;
3690 }
3691 if (chip)
3692 chip->rconn_mohm = rconn_mohm;
3693 return 0;
3694}
3695module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3696 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003697/**
3698 * set_thermal_mitigation_level -
3699 *
3700 * Internal function to control battery charging current to reduce
3701 * temperature
3702 */
3703static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3704{
3705 int ret;
3706 struct pm8921_chg_chip *chip = the_chip;
3707
3708 ret = param_set_int(val, kp);
3709 if (ret) {
3710 pr_err("error setting value %d\n", ret);
3711 return ret;
3712 }
3713
3714 if (!chip) {
3715 pr_err("called before init\n");
3716 return -EINVAL;
3717 }
3718
3719 if (!chip->thermal_mitigation) {
3720 pr_err("no thermal mitigation\n");
3721 return -EINVAL;
3722 }
3723
3724 if (thermal_mitigation < 0
3725 || thermal_mitigation >= chip->thermal_levels) {
3726 pr_err("out of bound level selected\n");
3727 return -EINVAL;
3728 }
3729
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003730 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003731 return ret;
3732}
3733module_param_call(thermal_mitigation, set_therm_mitigation_level,
3734 param_get_uint,
3735 &thermal_mitigation, 0644);
3736
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003737static int set_usb_max_current(const char *val, struct kernel_param *kp)
3738{
3739 int ret, mA;
3740 struct pm8921_chg_chip *chip = the_chip;
3741
3742 ret = param_set_int(val, kp);
3743 if (ret) {
3744 pr_err("error setting value %d\n", ret);
3745 return ret;
3746 }
3747 if (chip) {
3748 pr_warn("setting current max to %d\n", usb_max_current);
3749 pm_chg_iusbmax_get(chip, &mA);
3750 if (mA > usb_max_current)
3751 pm8921_charger_vbus_draw(usb_max_current);
3752 return 0;
3753 }
3754 return -EINVAL;
3755}
David Keitelacf57c82012-03-07 18:48:50 -08003756module_param_call(usb_max_current, set_usb_max_current,
3757 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003759static void free_irqs(struct pm8921_chg_chip *chip)
3760{
3761 int i;
3762
3763 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3764 if (chip->pmic_chg_irq[i]) {
3765 free_irq(chip->pmic_chg_irq[i], chip);
3766 chip->pmic_chg_irq[i] = 0;
3767 }
3768}
3769
David Keitel88e1b572012-01-11 11:57:14 -08003770/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3772{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003774 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003775
3776 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3777 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3778
3779 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003780 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003781 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003782 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003783 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003784 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003785
3786 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3787 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3788 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003789 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003790 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3791 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003792 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003793 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3794 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003795 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003796
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003797 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3798 if (usb_chg_current)
3799 /*
3800 * Reissue a vbus draw call only if a battery
3801 * or DC is present. We don't want to brown out the
3802 * device if usb is its only source
3803 */
3804 __pm8921_charger_vbus_draw(usb_chg_current);
3805 usb_chg_current = 0;
3806
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003807 /*
3808 * The bootloader could have started charging, a fastchg interrupt
3809 * might not happen. Check the real time status and if it is fast
3810 * charging invoke the handler so that the eoc worker could be
3811 * started
3812 */
3813 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3814 if (is_fast_chg)
3815 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816
3817 fsm_state = pm_chg_get_fsm_state(chip);
3818 if (is_battery_charging(fsm_state)) {
3819 chip->bms_notify.is_charging = 1;
3820 pm8921_bms_charging_began();
3821 }
3822
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003823 check_battery_valid(chip);
3824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3826 chip->usb_present,
3827 chip->dc_present,
3828 get_prop_batt_present(chip),
3829 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003830
3831 /* Determine which USB trim column to use */
3832 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3833 chip->usb_trim_table = usb_trim_8917_table;
3834 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3835 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836}
3837
3838struct pm_chg_irq_init_data {
3839 unsigned int irq_id;
3840 char *name;
3841 unsigned long flags;
3842 irqreturn_t (*handler)(int, void *);
3843};
3844
3845#define CHG_IRQ(_id, _flags, _handler) \
3846{ \
3847 .irq_id = _id, \
3848 .name = #_id, \
3849 .flags = _flags, \
3850 .handler = _handler, \
3851}
3852struct pm_chg_irq_init_data chg_irq_data[] = {
3853 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3854 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003855 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3856 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003857 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3858 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3860 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3861 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3862 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3863 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3864 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3865 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3866 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003867 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3868 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003869 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3870 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3871 batt_removed_irq_handler),
3872 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3873 batttemp_hot_irq_handler),
3874 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3875 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3876 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003877 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3878 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003879 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3880 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003881 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3882 coarse_det_low_irq_handler),
3883 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3884 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3885 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3886 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3887 batfet_irq_handler),
3888 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3889 dcin_valid_irq_handler),
3890 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3891 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003892 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003893};
3894
3895static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3896 struct platform_device *pdev)
3897{
3898 struct resource *res;
3899 int ret, i;
3900
3901 ret = 0;
3902 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3903
3904 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3905 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3906 chg_irq_data[i].name);
3907 if (res == NULL) {
3908 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3909 goto err_out;
3910 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003911 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 ret = request_irq(res->start, chg_irq_data[i].handler,
3913 chg_irq_data[i].flags,
3914 chg_irq_data[i].name, chip);
3915 if (ret < 0) {
3916 pr_err("couldn't request %d (%s) %d\n", res->start,
3917 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003918 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003919 goto err_out;
3920 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003921 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3922 }
3923 return 0;
3924
3925err_out:
3926 free_irqs(chip);
3927 return -EINVAL;
3928}
3929
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003930static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3931{
3932 int err;
3933 u8 temp;
3934
3935 temp = 0xD1;
3936 err = pm_chg_write(chip, CHG_TEST, temp);
3937 if (err) {
3938 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3939 return;
3940 }
3941
3942 temp = 0xD3;
3943 err = pm_chg_write(chip, CHG_TEST, temp);
3944 if (err) {
3945 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3946 return;
3947 }
3948
3949 temp = 0xD1;
3950 err = pm_chg_write(chip, CHG_TEST, temp);
3951 if (err) {
3952 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3953 return;
3954 }
3955
3956 temp = 0xD5;
3957 err = pm_chg_write(chip, CHG_TEST, temp);
3958 if (err) {
3959 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3960 return;
3961 }
3962
3963 udelay(183);
3964
3965 temp = 0xD1;
3966 err = pm_chg_write(chip, CHG_TEST, temp);
3967 if (err) {
3968 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3969 return;
3970 }
3971
3972 temp = 0xD0;
3973 err = pm_chg_write(chip, CHG_TEST, temp);
3974 if (err) {
3975 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3976 return;
3977 }
3978 udelay(32);
3979
3980 temp = 0xD1;
3981 err = pm_chg_write(chip, CHG_TEST, temp);
3982 if (err) {
3983 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3984 return;
3985 }
3986
3987 temp = 0xD3;
3988 err = pm_chg_write(chip, CHG_TEST, temp);
3989 if (err) {
3990 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3991 return;
3992 }
3993}
3994
3995static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3996{
3997 int err;
3998 u8 temp;
3999
4000 temp = 0xD1;
4001 err = pm_chg_write(chip, CHG_TEST, temp);
4002 if (err) {
4003 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4004 return;
4005 }
4006
4007 temp = 0xD0;
4008 err = pm_chg_write(chip, CHG_TEST, temp);
4009 if (err) {
4010 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4011 return;
4012 }
4013}
4014
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004015#define VREF_BATT_THERM_FORCE_ON BIT(7)
4016static void detect_battery_removal(struct pm8921_chg_chip *chip)
4017{
4018 u8 temp;
4019
4020 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4021 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4022
4023 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4024 /*
4025 * batt therm force on bit is battery backed and is default 0
4026 * The charger sets this bit at init time. If this bit is found
4027 * 0 that means the battery was removed. Tell the bms about it
4028 */
4029 pm8921_bms_invalidate_shutdown_soc();
4030}
4031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032#define ENUM_TIMER_STOP_BIT BIT(1)
4033#define BOOT_DONE_BIT BIT(6)
4034#define CHG_BATFET_ON_BIT BIT(3)
4035#define CHG_VCP_EN BIT(0)
4036#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4037#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004038#define PM_SUB_REV 0x001
4039#define MIN_CHARGE_CURRENT_MA 350
4040#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004041static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4042{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004043 u8 subrev;
4044 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004046 /* forcing 19p2mhz before accessing any charger registers */
4047 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004048
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004049 detect_battery_removal(chip);
4050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004051 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004052 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053 if (rc) {
4054 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4055 return rc;
4056 }
4057
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004058 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4059
4060 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4061 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4062
4063 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4064
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 if (rc) {
4066 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004067 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 return rc;
4069 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004070 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004071 chip->max_voltage_mv
4072 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 if (rc) {
4074 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004075 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004076 return rc;
4077 }
4078
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004079 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 if (rc) {
4081 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004082 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083 return rc;
4084 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004085
4086 if (chip->safe_current_ma == 0)
4087 chip->safe_current_ma = SAFE_CURRENT_MA;
4088
4089 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004090 if (rc) {
4091 pr_err("Failed to set max voltage to %d rc=%d\n",
4092 SAFE_CURRENT_MA, rc);
4093 return rc;
4094 }
4095
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004096 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097 if (rc) {
4098 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4099 return rc;
4100 }
4101
4102 rc = pm_chg_iterm_set(chip, chip->term_current);
4103 if (rc) {
4104 pr_err("Failed to set term current to %d rc=%d\n",
4105 chip->term_current, rc);
4106 return rc;
4107 }
4108
4109 /* Disable the ENUM TIMER */
4110 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4111 ENUM_TIMER_STOP_BIT);
4112 if (rc) {
4113 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4114 return rc;
4115 }
4116
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004117 fcc_uah = pm8921_bms_get_fcc();
4118 if (fcc_uah > 0) {
4119 safety_time = div_s64((s64)fcc_uah * 60,
4120 1000 * MIN_CHARGE_CURRENT_MA);
4121 /* add 20 minutes of buffer time */
4122 safety_time += 20;
4123
4124 /* make sure we do not exceed the maximum programmable time */
4125 if (safety_time > PM8921_CHG_TCHG_MAX)
4126 safety_time = PM8921_CHG_TCHG_MAX;
4127 }
4128
4129 rc = pm_chg_tchg_max_set(chip, safety_time);
4130 if (rc) {
4131 pr_err("Failed to set max time to %d minutes rc=%d\n",
4132 safety_time, rc);
4133 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004134 }
4135
4136 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004137 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004138 if (rc) {
4139 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004140 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004141 return rc;
4142 }
4143 }
4144
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004145 if (chip->vin_min != 0) {
4146 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4147 if (rc) {
4148 pr_err("Failed to set vin min to %d mV rc=%d\n",
4149 chip->vin_min, rc);
4150 return rc;
4151 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004152 } else {
4153 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004154 }
4155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156 rc = pm_chg_disable_wd(chip);
4157 if (rc) {
4158 pr_err("Failed to disable wd rc=%d\n", rc);
4159 return rc;
4160 }
4161
4162 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4163 CHG_BAT_TEMP_DIS_BIT, 0);
4164 if (rc) {
4165 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4166 return rc;
4167 }
4168 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004169 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4170 rc = pm_chg_write(chip,
4171 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4172 else
4173 rc = pm_chg_write(chip,
4174 CHG_BUCK_CLOCK_CTRL, 0x15);
4175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176 if (rc) {
4177 pr_err("Failed to switch buck clk rc=%d\n", rc);
4178 return rc;
4179 }
4180
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004181 if (chip->trkl_voltage != 0) {
4182 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4183 if (rc) {
4184 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4185 chip->trkl_voltage, rc);
4186 return rc;
4187 }
4188 }
4189
4190 if (chip->weak_voltage != 0) {
4191 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4192 if (rc) {
4193 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4194 chip->weak_voltage, rc);
4195 return rc;
4196 }
4197 }
4198
4199 if (chip->trkl_current != 0) {
4200 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4201 if (rc) {
4202 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4203 chip->trkl_voltage, rc);
4204 return rc;
4205 }
4206 }
4207
4208 if (chip->weak_current != 0) {
4209 rc = pm_chg_iweak_set(chip, chip->weak_current);
4210 if (rc) {
4211 pr_err("Failed to set weak current to %dmA rc=%d\n",
4212 chip->weak_current, rc);
4213 return rc;
4214 }
4215 }
4216
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004217 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4218 if (rc) {
4219 pr_err("Failed to set cold config %d rc=%d\n",
4220 chip->cold_thr, rc);
4221 }
4222
4223 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4224 if (rc) {
4225 pr_err("Failed to set hot config %d rc=%d\n",
4226 chip->hot_thr, rc);
4227 }
4228
Jay Chokshid674a512012-03-15 14:06:04 -07004229 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4230 if (rc) {
4231 pr_err("Failed to set charger LED src config %d rc=%d\n",
4232 chip->led_src_config, rc);
4233 }
4234
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004235 /* Workarounds for die 3.0 */
4236 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4237 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4238 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4239 if (rc) {
4240 pr_err("read failed: addr=%03X, rc=%d\n",
4241 PM_SUB_REV, rc);
4242 return rc;
4243 }
4244 /* Check if die 3.0.1 is present */
4245 if (subrev & 0x1)
4246 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4247 else
4248 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 }
4250
David Keitel0789fc62012-06-07 17:43:27 -07004251 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004252 /* Set PM8917 USB_OVP debounce time to 15 ms */
4253 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4254 OVP_DEBOUNCE_TIME, 0x6);
4255 if (rc) {
4256 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4257 return rc;
4258 }
4259
4260 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004261 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004262 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004263 rc = pm_chg_uvd_threshold_set(chip,
4264 chip->uvd_voltage_mv);
4265 if (rc) {
4266 pr_err("Failed to set UVD threshold %drc=%d\n",
4267 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004268 return rc;
4269 }
David Keitel0789fc62012-06-07 17:43:27 -07004270 }
4271 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004272
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004273 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004274
David Keitela3c0d822011-11-03 14:18:52 -07004275 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004276 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004277
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004278 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4279 VREF_BATT_THERM_FORCE_ON);
4280 if (rc)
4281 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004283 rc = pm_chg_charge_dis(chip, charging_disabled);
4284 if (rc) {
4285 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4286 return rc;
4287 }
4288
4289 rc = pm_chg_auto_enable(chip, !charging_disabled);
4290 if (rc) {
4291 pr_err("Failed to enable charging rc=%d\n", rc);
4292 return rc;
4293 }
4294
4295 return 0;
4296}
4297
4298static int get_rt_status(void *data, u64 * val)
4299{
4300 int i = (int)data;
4301 int ret;
4302
4303 /* global irq number is passed in via data */
4304 ret = pm_chg_get_rt_status(the_chip, i);
4305 *val = ret;
4306 return 0;
4307}
4308DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4309
4310static int get_fsm_status(void *data, u64 * val)
4311{
4312 u8 temp;
4313
4314 temp = pm_chg_get_fsm_state(the_chip);
4315 *val = temp;
4316 return 0;
4317}
4318DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4319
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004320static int get_reg_loop(void *data, u64 * val)
4321{
4322 u8 temp;
4323
4324 if (!the_chip) {
4325 pr_err("%s called before init\n", __func__);
4326 return -EINVAL;
4327 }
4328 temp = pm_chg_get_regulation_loop(the_chip);
4329 *val = temp;
4330 return 0;
4331}
4332DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004334static int get_reg(void *data, u64 * val)
4335{
4336 int addr = (int)data;
4337 int ret;
4338 u8 temp;
4339
4340 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4341 if (ret) {
4342 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4343 addr, temp, ret);
4344 return -EAGAIN;
4345 }
4346 *val = temp;
4347 return 0;
4348}
4349
4350static int set_reg(void *data, u64 val)
4351{
4352 int addr = (int)data;
4353 int ret;
4354 u8 temp;
4355
4356 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004357 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004358 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004359 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360 addr, temp, ret);
4361 return -EAGAIN;
4362 }
4363 return 0;
4364}
4365DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4366
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004367static int reg_loop;
4368#define MAX_REG_LOOP_CHAR 10
4369static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4370{
4371 u8 temp;
4372
4373 if (!the_chip) {
4374 pr_err("called before init\n");
4375 return -EINVAL;
4376 }
4377 temp = pm_chg_get_regulation_loop(the_chip);
4378 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4379}
4380module_param_call(reg_loop, NULL, get_reg_loop_param,
4381 &reg_loop, 0644);
4382
4383static int max_chg_ma;
4384#define MAX_MA_CHAR 10
4385static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4386{
4387 if (!the_chip) {
4388 pr_err("called before init\n");
4389 return -EINVAL;
4390 }
4391 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4392}
4393module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4394 &max_chg_ma, 0644);
4395static int ibatmax_ma;
4396static int set_ibat_max(const char *val, struct kernel_param *kp)
4397{
4398 int rc;
4399
4400 if (!the_chip) {
4401 pr_err("called before init\n");
4402 return -EINVAL;
4403 }
4404
4405 rc = param_set_int(val, kp);
4406 if (rc) {
4407 pr_err("error setting value %d\n", rc);
4408 return rc;
4409 }
4410
4411 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4412 <= the_chip->ibatmax_max_adj_ma) {
4413 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4414 if (rc) {
4415 pr_err("Failed to set ibatmax rc = %d\n", rc);
4416 return rc;
4417 }
4418 }
4419
4420 return 0;
4421}
4422static int get_ibat_max(char *buf, struct kernel_param *kp)
4423{
4424 int ibat_ma;
4425 int rc;
4426
4427 if (!the_chip) {
4428 pr_err("called before init\n");
4429 return -EINVAL;
4430 }
4431
4432 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4433 if (rc) {
4434 pr_err("ibatmax_get error = %d\n", rc);
4435 return rc;
4436 }
4437
4438 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4439}
4440module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4441 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004442enum {
4443 BAT_WARM_ZONE,
4444 BAT_COOL_ZONE,
4445};
4446static int get_warm_cool(void *data, u64 * val)
4447{
4448 if (!the_chip) {
4449 pr_err("%s called before init\n", __func__);
4450 return -EINVAL;
4451 }
4452 if ((int)data == BAT_WARM_ZONE)
4453 *val = the_chip->is_bat_warm;
4454 if ((int)data == BAT_COOL_ZONE)
4455 *val = the_chip->is_bat_cool;
4456 return 0;
4457}
4458DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004460static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4461{
4462 int i;
4463
4464 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4465
4466 if (IS_ERR(chip->dent)) {
4467 pr_err("pmic charger couldnt create debugfs dir\n");
4468 return;
4469 }
4470
4471 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4472 (void *)CHG_CNTRL, &reg_fops);
4473 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4474 (void *)CHG_CNTRL_2, &reg_fops);
4475 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4476 (void *)CHG_CNTRL_3, &reg_fops);
4477 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4478 (void *)PBL_ACCESS1, &reg_fops);
4479 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4480 (void *)PBL_ACCESS2, &reg_fops);
4481 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4482 (void *)SYS_CONFIG_1, &reg_fops);
4483 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4484 (void *)SYS_CONFIG_2, &reg_fops);
4485 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4486 (void *)CHG_VDD_MAX, &reg_fops);
4487 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4488 (void *)CHG_VDD_SAFE, &reg_fops);
4489 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4490 (void *)CHG_VBAT_DET, &reg_fops);
4491 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4492 (void *)CHG_IBAT_MAX, &reg_fops);
4493 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4494 (void *)CHG_IBAT_SAFE, &reg_fops);
4495 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4496 (void *)CHG_VIN_MIN, &reg_fops);
4497 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4498 (void *)CHG_VTRICKLE, &reg_fops);
4499 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4500 (void *)CHG_ITRICKLE, &reg_fops);
4501 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4502 (void *)CHG_ITERM, &reg_fops);
4503 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4504 (void *)CHG_TCHG_MAX, &reg_fops);
4505 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4506 (void *)CHG_TWDOG, &reg_fops);
4507 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4508 (void *)CHG_TEMP_THRESH, &reg_fops);
4509 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4510 (void *)CHG_COMP_OVR, &reg_fops);
4511 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4512 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4513 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4514 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4515 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4516 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4517 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4518 (void *)CHG_TEST, &reg_fops);
4519
4520 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4521 &fsm_fops);
4522
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004523 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4524 &reg_loop_fops);
4525
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004526 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4527 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4528 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4529 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004531 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4532 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4533 debugfs_create_file(chg_irq_data[i].name, 0444,
4534 chip->dent,
4535 (void *)chg_irq_data[i].irq_id,
4536 &rt_fops);
4537 }
4538}
4539
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004540static int pm8921_charger_suspend_noirq(struct device *dev)
4541{
4542 int rc;
4543 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4544
4545 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4546 if (rc)
4547 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004548
4549 rc = pm8921_chg_set_lpm(chip, 1);
4550 if (rc)
4551 pr_err("Failed to set lpm rc=%d\n", rc);
4552
4553 pm8921_chg_set_hw_clk_switching(chip);
4554
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004555 return 0;
4556}
4557
4558static int pm8921_charger_resume_noirq(struct device *dev)
4559{
4560 int rc;
4561 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4562
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004563 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004564
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004565 rc = pm8921_chg_set_lpm(chip, 0);
4566 if (rc)
4567 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004568
4569 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4570 VREF_BATT_THERM_FORCE_ON);
4571 if (rc)
4572 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4573 return 0;
4574}
4575
David Keitelf2226022011-12-13 15:55:50 -08004576static int pm8921_charger_resume(struct device *dev)
4577{
David Keitelf2226022011-12-13 15:55:50 -08004578 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4579
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004580 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4581 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4582 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4583 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004584
4585 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4586 is_usb_chg_plugged_in(the_chip)))
4587 schedule_delayed_work(&chip->btc_override_work, 0);
4588
David Keitelf2226022011-12-13 15:55:50 -08004589 return 0;
4590}
4591
4592static int pm8921_charger_suspend(struct device *dev)
4593{
David Keitelf2226022011-12-13 15:55:50 -08004594 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4595
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004596 if (chip->btc_override)
4597 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004598
4599 if (is_usb_chg_plugged_in(chip)) {
4600 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4601 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4602 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004603
David Keitelf2226022011-12-13 15:55:50 -08004604 return 0;
4605}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004606static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4607{
4608 int rc = 0;
4609 struct pm8921_chg_chip *chip;
4610 const struct pm8921_charger_platform_data *pdata
4611 = pdev->dev.platform_data;
4612
4613 if (!pdata) {
4614 pr_err("missing platform data\n");
4615 return -EINVAL;
4616 }
4617
4618 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4619 GFP_KERNEL);
4620 if (!chip) {
4621 pr_err("Cannot allocate pm_chg_chip\n");
4622 return -ENOMEM;
4623 }
4624
4625 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004626 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004628 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004629 chip->alarm_low_mv = pdata->alarm_low_mv;
4630 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004631 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004632 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004633 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004634 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004635 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004636 chip->term_current = pdata->term_current;
4637 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004638 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004639 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4640 chip->batt_id_min = pdata->batt_id_min;
4641 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004642 if (pdata->cool_temp != INT_MIN)
4643 chip->cool_temp_dc = pdata->cool_temp * 10;
4644 else
4645 chip->cool_temp_dc = INT_MIN;
4646
4647 if (pdata->warm_temp != INT_MIN)
4648 chip->warm_temp_dc = pdata->warm_temp * 10;
4649 else
4650 chip->warm_temp_dc = INT_MIN;
4651
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004652 chip->temp_check_period = pdata->temp_check_period;
4653 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004654 /* Assign to corresponding module parameter */
4655 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004656 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4657 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4658 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4659 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004660 chip->trkl_voltage = pdata->trkl_voltage;
4661 chip->weak_voltage = pdata->weak_voltage;
4662 chip->trkl_current = pdata->trkl_current;
4663 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004664 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004665 chip->thermal_mitigation = pdata->thermal_mitigation;
4666 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304667 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004669 chip->cold_thr = pdata->cold_thr;
4670 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004671 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004672 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004673 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004674 chip->battery_less_hardware = pdata->battery_less_hardware;
4675 chip->btc_override = pdata->btc_override;
4676 if (chip->btc_override) {
4677 chip->btc_delay_ms = pdata->btc_delay_ms;
4678 chip->btc_override_cold_decidegc
4679 = pdata->btc_override_cold_degc * 10;
4680 chip->btc_override_hot_decidegc
4681 = pdata->btc_override_hot_degc * 10;
4682 chip->btc_panic_if_cant_stop_chg
4683 = pdata->btc_panic_if_cant_stop_chg;
4684 }
4685
4686 if (chip->battery_less_hardware)
4687 charging_disabled = 1;
4688
4689 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4690 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004692 rc = pm8921_chg_hw_init(chip);
4693 if (rc) {
4694 pr_err("couldn't init hardware rc=%d\n", rc);
4695 goto free_chip;
4696 }
4697
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004698 if (chip->btc_override)
4699 pm8921_chg_btc_override_init(chip);
4700
4701 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304702 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004703
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004704 chip->usb_psy.name = "usb";
4705 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4706 chip->usb_psy.supplied_to = pm_power_supplied_to;
4707 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4708 chip->usb_psy.properties = pm_power_props_usb;
4709 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4710 chip->usb_psy.get_property = pm_power_get_property_usb;
4711 chip->usb_psy.set_property = pm_power_set_property_usb;
4712 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004714 chip->dc_psy.name = "pm8921-dc";
4715 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4716 chip->dc_psy.supplied_to = pm_power_supplied_to;
4717 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4718 chip->dc_psy.properties = pm_power_props_mains;
4719 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4720 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004721
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004722 chip->batt_psy.name = "battery";
4723 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4724 chip->batt_psy.properties = msm_batt_power_props;
4725 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4726 chip->batt_psy.get_property = pm_batt_power_get_property;
4727 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728 rc = power_supply_register(chip->dev, &chip->usb_psy);
4729 if (rc < 0) {
4730 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004731 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004732 }
4733
David Keitel6ed71a52012-01-30 12:42:18 -08004734 rc = power_supply_register(chip->dev, &chip->dc_psy);
4735 if (rc < 0) {
4736 pr_err("power_supply_register usb failed rc = %d\n", rc);
4737 goto unregister_usb;
4738 }
4739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740 rc = power_supply_register(chip->dev, &chip->batt_psy);
4741 if (rc < 0) {
4742 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004743 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744 }
4745
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004746 platform_set_drvdata(pdev, chip);
4747 the_chip = chip;
4748
4749 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004750 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004751 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4752 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004753 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004754
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004755 INIT_WORK(&chip->bms_notify.work, bms_notify);
4756 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4757
4758 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4759 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004761 rc = request_irqs(chip, pdev);
4762 if (rc) {
4763 pr_err("couldn't register interrupts rc=%d\n", rc);
4764 goto unregister_batt;
4765 }
4766
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004767 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004768 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004769 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004770 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004772 create_debugfs_entries(chip);
4773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 /* determine what state the charger is in */
4775 determine_initial_state(chip);
4776
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004777 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004778 schedule_delayed_work(&chip->update_heartbeat_work,
4779 round_jiffies_relative(msecs_to_jiffies
4780 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004781 return 0;
4782
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004784 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004786unregister_dc:
4787 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004788unregister_usb:
4789 power_supply_unregister(&chip->usb_psy);
4790free_chip:
4791 kfree(chip);
4792 return rc;
4793}
4794
4795static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4796{
4797 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4798
4799 free_irqs(chip);
4800 platform_set_drvdata(pdev, NULL);
4801 the_chip = NULL;
4802 kfree(chip);
4803 return 0;
4804}
David Keitelf2226022011-12-13 15:55:50 -08004805static const struct dev_pm_ops pm8921_pm_ops = {
4806 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004807 .suspend_noirq = pm8921_charger_suspend_noirq,
4808 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004809 .resume = pm8921_charger_resume,
4810};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004811static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004812 .probe = pm8921_charger_probe,
4813 .remove = __devexit_p(pm8921_charger_remove),
4814 .driver = {
4815 .name = PM8921_CHARGER_DEV_NAME,
4816 .owner = THIS_MODULE,
4817 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004818 },
4819};
4820
4821static int __init pm8921_charger_init(void)
4822{
4823 return platform_driver_register(&pm8921_charger_driver);
4824}
4825
4826static void __exit pm8921_charger_exit(void)
4827{
4828 platform_driver_unregister(&pm8921_charger_driver);
4829}
4830
4831late_initcall(pm8921_charger_init);
4832module_exit(pm8921_charger_exit);
4833
4834MODULE_LICENSE("GPL v2");
4835MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4836MODULE_VERSION("1.0");
4837MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);