blob: bbe5de7eafbf613044f9ab5cc4fb8aab5a351653 [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
2907 return ibatmax_adj_table[i].max_adj_ma;
2908}
2909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002910static irqreturn_t fastchg_irq_handler(int irq, void *data)
2911{
2912 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002913 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002915 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2916 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2917 wake_lock(&chip->eoc_wake_lock);
2918 schedule_delayed_work(&chip->eoc_work,
2919 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002920 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002921 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002922 if (high_transition
2923 && chip->btc_override
2924 && !delayed_work_pending(&chip->btc_override_work)) {
2925 schedule_delayed_work(&chip->btc_override_work,
2926 round_jiffies_relative(msecs_to_jiffies
2927 (chip->btc_delay_ms)));
2928 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002929 power_supply_changed(&chip->batt_psy);
2930 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931 return IRQ_HANDLED;
2932}
2933
2934static irqreturn_t trklchg_irq_handler(int irq, void *data)
2935{
2936 struct pm8921_chg_chip *chip = data;
2937
2938 power_supply_changed(&chip->batt_psy);
2939 return IRQ_HANDLED;
2940}
2941
2942static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2943{
2944 struct pm8921_chg_chip *chip = data;
2945 int status;
2946
2947 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2948 pr_debug("battery present=%d state=%d", !status,
2949 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002950 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951 power_supply_changed(&chip->batt_psy);
2952 return IRQ_HANDLED;
2953}
2954
2955static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2956{
2957 struct pm8921_chg_chip *chip = data;
2958
Amir Samuelovd31ef502011-10-26 14:41:36 +02002959 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002960 power_supply_changed(&chip->batt_psy);
2961 return IRQ_HANDLED;
2962}
2963
2964static irqreturn_t chghot_irq_handler(int irq, void *data)
2965{
2966 struct pm8921_chg_chip *chip = data;
2967
2968 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2969 power_supply_changed(&chip->batt_psy);
2970 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002971 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002972 return IRQ_HANDLED;
2973}
2974
2975static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2976{
2977 struct pm8921_chg_chip *chip = data;
2978
2979 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002980 handle_stop_ext_chg(chip);
2981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982 power_supply_changed(&chip->batt_psy);
2983 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002984 return IRQ_HANDLED;
2985}
2986
2987static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2988{
2989 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002990 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002991
2992 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2993 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2994
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002995 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2996 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07002997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002998 power_supply_changed(&chip->batt_psy);
2999 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 return IRQ_HANDLED;
3001}
David Keitel52fda532011-11-10 10:43:44 -08003002/*
3003 *
3004 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3005 * fire for two cases:
3006 *
3007 * If the interrupt line switches to high temperature is okay
3008 * and thus charging begins.
3009 * If bat_temp_ok is low this means the temperature is now
3010 * too hot or cold, so charging is stopped.
3011 *
3012 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3014{
David Keitel52fda532011-11-10 10:43:44 -08003015 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003016 struct pm8921_chg_chip *chip = data;
3017
David Keitel52fda532011-11-10 10:43:44 -08003018 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3019
3020 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3021 bat_temp_ok, pm_chg_get_fsm_state(data));
3022
3023 if (bat_temp_ok)
3024 handle_start_ext_chg(chip);
3025 else
3026 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 power_supply_changed(&chip->batt_psy);
3029 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003030 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031 return IRQ_HANDLED;
3032}
3033
3034static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3035{
3036 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3037 return IRQ_HANDLED;
3038}
3039
3040static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3041{
3042 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3043 return IRQ_HANDLED;
3044}
3045
3046static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3047{
3048 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3049 return IRQ_HANDLED;
3050}
3051
3052static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3053{
3054 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3055 return IRQ_HANDLED;
3056}
3057
3058static irqreturn_t batfet_irq_handler(int irq, void *data)
3059{
3060 struct pm8921_chg_chip *chip = data;
3061
3062 pr_debug("vreg ov\n");
3063 power_supply_changed(&chip->batt_psy);
3064 return IRQ_HANDLED;
3065}
3066
3067static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3068{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003069 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003070 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003071
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003072 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003073 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003074
3075 if (chip->dc_present ^ dc_present)
3076 pm8921_bms_calibrate_hkadc();
3077
David Keitel88e1b572012-01-11 11:57:14 -08003078 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003079 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003080 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003081 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3082
3083 chip->dc_present = dc_present;
3084
3085 if (chip->ext_psy) {
3086 if (dc_present)
3087 handle_start_ext_chg(chip);
3088 else
3089 handle_stop_ext_chg(chip);
3090 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003091 if (dc_present)
3092 schedule_delayed_work(&chip->unplug_check_work,
3093 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3094 power_supply_changed(&chip->dc_psy);
3095 }
3096
3097 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003098 return IRQ_HANDLED;
3099}
3100
3101static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3102{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003103 struct pm8921_chg_chip *chip = data;
3104
Amir Samuelovd31ef502011-10-26 14:41:36 +02003105 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003106 return IRQ_HANDLED;
3107}
3108
3109static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3110{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003111 struct pm8921_chg_chip *chip = data;
3112
Amir Samuelovd31ef502011-10-26 14:41:36 +02003113 handle_stop_ext_chg(chip);
3114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003115 return IRQ_HANDLED;
3116}
3117
David Keitel88e1b572012-01-11 11:57:14 -08003118static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3119{
3120 struct power_supply *psy = &the_chip->batt_psy;
3121 struct power_supply *epsy = dev_get_drvdata(dev);
3122 int i, dcin_irq;
3123
3124 /* Only search for external supply if none is registered */
3125 if (!the_chip->ext_psy) {
3126 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3127 for (i = 0; i < epsy->num_supplicants; i++) {
3128 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3129 if (!strncmp(epsy->name, "dc", 2)) {
3130 the_chip->ext_psy = epsy;
3131 dcin_valid_irq_handler(dcin_irq,
3132 the_chip);
3133 }
3134 }
3135 }
3136 }
3137 return 0;
3138}
3139
3140static void pm_batt_external_power_changed(struct power_supply *psy)
3141{
3142 /* Only look for an external supply if it hasn't been registered */
3143 if (!the_chip->ext_psy)
3144 class_for_each_device(power_supply_class, NULL, psy,
3145 __pm_batt_external_power_changed_work);
3146}
3147
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003148/**
3149 * update_heartbeat - internal function to update userspace
3150 * per update_time minutes
3151 *
3152 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003153#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003154static void update_heartbeat(struct work_struct *work)
3155{
3156 struct delayed_work *dwork = to_delayed_work(work);
3157 struct pm8921_chg_chip *chip = container_of(dwork,
3158 struct pm8921_chg_chip, update_heartbeat_work);
3159
3160 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003161 if (chip->recent_reported_soc <= 20)
3162 schedule_delayed_work(&chip->update_heartbeat_work,
3163 round_jiffies_relative(msecs_to_jiffies
3164 (LOW_SOC_HEARTBEAT_MS)));
3165 else
3166 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003167 round_jiffies_relative(msecs_to_jiffies
3168 (chip->update_time)));
3169}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003170#define VDD_LOOP_ACTIVE_BIT BIT(3)
3171#define VDD_MAX_INCREASE_MV 400
3172static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3173module_param(vdd_max_increase_mv, int, 0644);
3174
3175static int ichg_threshold_ua = -400000;
3176module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003177
3178#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003179static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3180 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003181{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003182 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003183 int vbat_batt_terminal_mv;
3184 int reg_loop;
3185 int delta_mv = 0;
3186
3187 if (chip->rconn_mohm == 0) {
3188 pr_debug("Exiting as rconn_mohm is 0\n");
3189 return;
3190 }
3191 /* adjust vdd_max only in normal temperature zone */
3192 if (chip->is_bat_cool || chip->is_bat_warm) {
3193 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3194 chip->is_bat_cool, chip->is_bat_warm);
3195 return;
3196 }
3197
3198 reg_loop = pm_chg_get_regulation_loop(chip);
3199 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3200 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3201 reg_loop);
3202 return;
3203 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003204 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3205 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3206
3207 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3208
3209 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3210 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3211 delta_mv,
3212 programmed_vdd_max,
3213 adj_vdd_max_mv);
3214
3215 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3216 pr_debug("adj vdd_max lower than default max voltage\n");
3217 return;
3218 }
3219
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003220 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3221 * PM8921_CHG_VDDMAX_RES_MV;
3222
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003223 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3224 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003225 pr_debug("adjusting vdd_max_mv to %d to make "
3226 "vbat_batt_termial_uv = %d to %d\n",
3227 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3228 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3229}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003230
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003231static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3232{
3233 if (chip->is_bat_cool)
3234 pm_chg_vbatdet_set(the_chip,
3235 the_chip->cool_bat_voltage
3236 - the_chip->resume_voltage_delta);
3237 else if (chip->is_bat_warm)
3238 pm_chg_vbatdet_set(the_chip,
3239 the_chip->warm_bat_voltage
3240 - the_chip->resume_voltage_delta);
3241 else
3242 pm_chg_vbatdet_set(the_chip,
3243 the_chip->max_voltage_mv
3244 - the_chip->resume_voltage_delta);
3245}
3246
3247static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3248{
3249 unsigned int chg_current = chip->max_bat_chg_current;
3250
3251 if (chip->is_bat_cool)
3252 chg_current = min(chg_current, chip->cool_bat_chg_current);
3253
3254 if (chip->is_bat_warm)
3255 chg_current = min(chg_current, chip->warm_bat_chg_current);
3256
3257 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3258 chg_current = min(chg_current,
3259 chip->thermal_mitigation[thermal_mitigation]);
3260
3261 pm_chg_ibatmax_set(the_chip, chg_current);
3262}
3263
3264#define TEMP_HYSTERISIS_DECIDEGC 20
3265static void battery_cool(bool enter)
3266{
3267 pr_debug("enter = %d\n", enter);
3268 if (enter == the_chip->is_bat_cool)
3269 return;
3270 the_chip->is_bat_cool = enter;
3271 if (enter)
3272 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3273 else
3274 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3275 set_appropriate_battery_current(the_chip);
3276 set_appropriate_vbatdet(the_chip);
3277}
3278
3279static void battery_warm(bool enter)
3280{
3281 pr_debug("enter = %d\n", enter);
3282 if (enter == the_chip->is_bat_warm)
3283 return;
3284 the_chip->is_bat_warm = enter;
3285 if (enter)
3286 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3287 else
3288 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3289
3290 set_appropriate_battery_current(the_chip);
3291 set_appropriate_vbatdet(the_chip);
3292}
3293
3294static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3295{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303296 int temp = 0, rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003297
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303298 rc = get_prop_batt_temp(chip, &temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003299 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3300 temp, chip->warm_temp_dc,
3301 chip->cool_temp_dc);
3302
3303 if (chip->warm_temp_dc != INT_MIN) {
3304 if (chip->is_bat_warm
3305 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3306 battery_warm(false);
3307 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3308 battery_warm(true);
3309 }
3310
3311 if (chip->cool_temp_dc != INT_MIN) {
3312 if (chip->is_bat_cool
3313 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3314 battery_cool(false);
3315 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3316 battery_cool(true);
3317 }
3318}
3319
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003320enum {
3321 CHG_IN_PROGRESS,
3322 CHG_NOT_IN_PROGRESS,
3323 CHG_FINISHED,
3324};
3325
3326#define VBAT_TOLERANCE_MV 70
3327#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003328static int is_charging_finished(struct pm8921_chg_chip *chip,
3329 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003330{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003331 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003332 int regulation_loop, fast_chg, vcp;
3333 int rc;
3334 static int last_vbat_programmed = -EINVAL;
3335
3336 if (!is_ext_charging(chip)) {
3337 /* return if the battery is not being fastcharged */
3338 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3339 pr_debug("fast_chg = %d\n", fast_chg);
3340 if (fast_chg == 0)
3341 return CHG_NOT_IN_PROGRESS;
3342
3343 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3344 pr_debug("vcp = %d\n", vcp);
3345 if (vcp == 1)
3346 return CHG_IN_PROGRESS;
3347
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003348 /* reset count if battery is hot/cold */
3349 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3350 pr_debug("batt_temp_ok = %d\n", rc);
3351 if (rc == 0)
3352 return CHG_IN_PROGRESS;
3353
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003354 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3355 if (rc) {
3356 pr_err("couldnt read vddmax rc = %d\n", rc);
3357 return CHG_IN_PROGRESS;
3358 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003359 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3360 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003361
3362 if (last_vbat_programmed == -EINVAL)
3363 last_vbat_programmed = vbat_programmed;
3364 if (last_vbat_programmed != vbat_programmed) {
3365 /* vddmax changed, reset and check again */
3366 pr_debug("vddmax = %d last_vdd_max=%d\n",
3367 vbat_programmed, last_vbat_programmed);
3368 last_vbat_programmed = vbat_programmed;
3369 return CHG_IN_PROGRESS;
3370 }
3371
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003372 if (chip->is_bat_cool)
3373 vbat_intended = chip->cool_bat_voltage;
3374 else if (chip->is_bat_warm)
3375 vbat_intended = chip->warm_bat_voltage;
3376 else
3377 vbat_intended = chip->max_voltage_mv;
3378
3379 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3380 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3381 vbat_batt_terminal_uv,
3382 vbat_intended);
3383 return CHG_IN_PROGRESS;
3384 }
3385
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003386 regulation_loop = pm_chg_get_regulation_loop(chip);
3387 if (regulation_loop < 0) {
3388 pr_err("couldnt read the regulation loop err=%d\n",
3389 regulation_loop);
3390 return CHG_IN_PROGRESS;
3391 }
3392 pr_debug("regulation_loop=%d\n", regulation_loop);
3393
3394 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3395 return CHG_IN_PROGRESS;
3396 } /* !is_ext_charging */
3397
3398 /* reset count if battery chg current is more than iterm */
3399 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3400 if (rc) {
3401 pr_err("couldnt read iterm rc = %d\n", rc);
3402 return CHG_IN_PROGRESS;
3403 }
3404
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003405 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3406 iterm_programmed, ichg_meas_ma);
3407 /*
3408 * ichg_meas_ma < 0 means battery is drawing current
3409 * ichg_meas_ma > 0 means battery is providing current
3410 */
3411 if (ichg_meas_ma > 0)
3412 return CHG_IN_PROGRESS;
3413
3414 if (ichg_meas_ma * -1 > iterm_programmed)
3415 return CHG_IN_PROGRESS;
3416
3417 return CHG_FINISHED;
3418}
3419
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003420#define COMP_OVERRIDE_HOT_BANK 6
3421#define COMP_OVERRIDE_COLD_BANK 7
3422#define COMP_OVERRIDE_BIT BIT(1)
3423static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3424{
3425 u8 val;
3426 int rc = 0;
3427
3428 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3429
3430 if (flag)
3431 val |= 0x01;
3432
3433 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3434 if (rc < 0)
3435 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3436
3437 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3438 return rc;
3439}
3440
3441static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3442{
3443 u8 val;
3444 int rc = 0;
3445
3446 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3447
3448 if (flag)
3449 val |= 0x01;
3450
3451 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3452 if (rc < 0)
3453 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3454
3455 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3456 return rc;
3457}
3458
3459static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3460{
3461 int rc = 0;
3462 u8 reg;
3463 u8 val;
3464
3465 val = COMP_OVERRIDE_HOT_BANK << 2;
3466 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3467 if (rc < 0) {
3468 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3469 goto cold_init;
3470 }
3471 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3472 if (rc < 0) {
3473 pr_err("Could not read bank %d of override rc = %d\n",
3474 COMP_OVERRIDE_HOT_BANK, rc);
3475 goto cold_init;
3476 }
3477 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3478 /* for now override it as not hot */
3479 rc = pm_chg_override_hot(chip, 0);
3480 if (rc < 0)
3481 pr_err("Could not override hot rc = %d\n", rc);
3482 }
3483
3484cold_init:
3485 val = COMP_OVERRIDE_COLD_BANK << 2;
3486 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3487 if (rc < 0) {
3488 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3489 return;
3490 }
3491 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3492 if (rc < 0) {
3493 pr_err("Could not read bank %d of override rc = %d\n",
3494 COMP_OVERRIDE_COLD_BANK, rc);
3495 return;
3496 }
3497 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3498 /* for now override it as not cold */
3499 rc = pm_chg_override_cold(chip, 0);
3500 if (rc < 0)
3501 pr_err("Could not override cold rc = %d\n", rc);
3502 }
3503}
3504
3505static void btc_override_worker(struct work_struct *work)
3506{
3507 int decidegc;
3508 int temp;
3509 int rc = 0;
3510 struct delayed_work *dwork = to_delayed_work(work);
3511 struct pm8921_chg_chip *chip = container_of(dwork,
3512 struct pm8921_chg_chip, btc_override_work);
3513
3514 if (!chip->btc_override) {
3515 pr_err("called when not enabled\n");
3516 return;
3517 }
3518
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303519 rc = get_prop_batt_temp(chip, &decidegc);
3520 if (rc) {
3521 pr_info("Failed to read temperature\n");
3522 goto fail_btc_temp;
3523 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003524
3525 pr_debug("temp=%d\n", decidegc);
3526
3527 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3528 if (temp) {
3529 if (decidegc < chip->btc_override_hot_decidegc)
3530 /* stop forcing batt hot */
3531 rc = pm_chg_override_hot(chip, 0);
3532 if (rc)
3533 pr_err("Couldnt write 0 to hot comp\n");
3534 } else {
3535 if (decidegc >= chip->btc_override_hot_decidegc)
3536 /* start forcing batt hot */
3537 rc = pm_chg_override_hot(chip, 1);
3538 if (rc && chip->btc_panic_if_cant_stop_chg)
3539 panic("Couldnt override comps to stop chg\n");
3540 }
3541
3542 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3543 if (temp) {
3544 if (decidegc > chip->btc_override_cold_decidegc)
3545 /* stop forcing batt cold */
3546 rc = pm_chg_override_cold(chip, 0);
3547 if (rc)
3548 pr_err("Couldnt write 0 to cold comp\n");
3549 } else {
3550 if (decidegc <= chip->btc_override_cold_decidegc)
3551 /* start forcing batt cold */
3552 rc = pm_chg_override_cold(chip, 1);
3553 if (rc && chip->btc_panic_if_cant_stop_chg)
3554 panic("Couldnt override comps to stop chg\n");
3555 }
3556
3557 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3558 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3559 schedule_delayed_work(&chip->btc_override_work,
3560 round_jiffies_relative(msecs_to_jiffies
3561 (chip->btc_delay_ms)));
3562 return;
3563 }
3564
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303565fail_btc_temp:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003566 rc = pm_chg_override_hot(chip, 0);
3567 if (rc)
3568 pr_err("Couldnt write 0 to hot comp\n");
3569 rc = pm_chg_override_cold(chip, 0);
3570 if (rc)
3571 pr_err("Couldnt write 0 to cold comp\n");
3572}
3573
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003574/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003575 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003576 * has happened
3577 *
3578 * If all conditions favouring, if the charge current is
3579 * less than the term current for three consecutive times
3580 * an EOC has happened.
3581 * The wakelock is released if there is no need to reshedule
3582 * - this happens when the battery is removed or EOC has
3583 * happened
3584 */
3585#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003586static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003587{
3588 struct delayed_work *dwork = to_delayed_work(work);
3589 struct pm8921_chg_chip *chip = container_of(dwork,
3590 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003591 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003592 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003593 int vbat_meas_uv, vbat_meas_mv;
3594 int ichg_meas_ua, ichg_meas_ma;
3595 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003596
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003597 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3598 &ichg_meas_ua, &vbat_meas_uv);
3599 vbat_meas_mv = vbat_meas_uv / 1000;
3600 /* rconn_mohm is in milliOhms */
3601 ichg_meas_ma = ichg_meas_ua / 1000;
3602 vbat_batt_terminal_uv = vbat_meas_uv
3603 + ichg_meas_ma
3604 * the_chip->rconn_mohm;
3605
3606 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003607
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003608 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003609 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003610 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003611 }
3612
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003613 if (end == CHG_FINISHED) {
3614 count++;
3615 } else {
3616 count = 0;
3617 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003618
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003619 if (count == CONSECUTIVE_COUNT) {
3620 count = 0;
3621 pr_info("End of Charging\n");
3622
3623 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003624
Amir Samuelovd31ef502011-10-26 14:41:36 +02003625 if (is_ext_charging(chip))
3626 chip->ext_charge_done = true;
3627
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003628 if (chip->is_bat_warm || chip->is_bat_cool)
3629 chip->bms_notify.is_battery_full = 0;
3630 else
3631 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003632 /* declare end of charging by invoking chgdone interrupt */
3633 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003634 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003635 check_temp_thresholds(chip);
3636 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003637 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003638 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003639 round_jiffies_relative(msecs_to_jiffies
3640 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003641 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003642 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003643
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003644eoc_worker_stop:
3645 wake_unlock(&chip->eoc_wake_lock);
3646 /* set the vbatdet back, in case it was changed to trigger charging */
3647 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003648}
3649
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003650/**
3651 * set_disable_status_param -
3652 *
3653 * Internal function to disable battery charging and also disable drawing
3654 * any current from the source. The device is forced to run on a battery
3655 * after this.
3656 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003657static int set_disable_status_param(const char *val, struct kernel_param *kp)
3658{
3659 int ret;
3660 struct pm8921_chg_chip *chip = the_chip;
3661
3662 ret = param_set_int(val, kp);
3663 if (ret) {
3664 pr_err("error setting value %d\n", ret);
3665 return ret;
3666 }
3667 pr_info("factory set disable param to %d\n", charging_disabled);
3668 if (chip) {
3669 pm_chg_auto_enable(chip, !charging_disabled);
3670 pm_chg_charge_dis(chip, charging_disabled);
3671 }
3672 return 0;
3673}
3674module_param_call(disabled, set_disable_status_param, param_get_uint,
3675 &charging_disabled, 0644);
3676
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003677static int rconn_mohm;
3678static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3679{
3680 int ret;
3681 struct pm8921_chg_chip *chip = the_chip;
3682
3683 ret = param_set_int(val, kp);
3684 if (ret) {
3685 pr_err("error setting value %d\n", ret);
3686 return ret;
3687 }
3688 if (chip)
3689 chip->rconn_mohm = rconn_mohm;
3690 return 0;
3691}
3692module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3693 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003694/**
3695 * set_thermal_mitigation_level -
3696 *
3697 * Internal function to control battery charging current to reduce
3698 * temperature
3699 */
3700static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3701{
3702 int ret;
3703 struct pm8921_chg_chip *chip = the_chip;
3704
3705 ret = param_set_int(val, kp);
3706 if (ret) {
3707 pr_err("error setting value %d\n", ret);
3708 return ret;
3709 }
3710
3711 if (!chip) {
3712 pr_err("called before init\n");
3713 return -EINVAL;
3714 }
3715
3716 if (!chip->thermal_mitigation) {
3717 pr_err("no thermal mitigation\n");
3718 return -EINVAL;
3719 }
3720
3721 if (thermal_mitigation < 0
3722 || thermal_mitigation >= chip->thermal_levels) {
3723 pr_err("out of bound level selected\n");
3724 return -EINVAL;
3725 }
3726
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003727 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003728 return ret;
3729}
3730module_param_call(thermal_mitigation, set_therm_mitigation_level,
3731 param_get_uint,
3732 &thermal_mitigation, 0644);
3733
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003734static int set_usb_max_current(const char *val, struct kernel_param *kp)
3735{
3736 int ret, mA;
3737 struct pm8921_chg_chip *chip = the_chip;
3738
3739 ret = param_set_int(val, kp);
3740 if (ret) {
3741 pr_err("error setting value %d\n", ret);
3742 return ret;
3743 }
3744 if (chip) {
3745 pr_warn("setting current max to %d\n", usb_max_current);
3746 pm_chg_iusbmax_get(chip, &mA);
3747 if (mA > usb_max_current)
3748 pm8921_charger_vbus_draw(usb_max_current);
3749 return 0;
3750 }
3751 return -EINVAL;
3752}
David Keitelacf57c82012-03-07 18:48:50 -08003753module_param_call(usb_max_current, set_usb_max_current,
3754 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003756static void free_irqs(struct pm8921_chg_chip *chip)
3757{
3758 int i;
3759
3760 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3761 if (chip->pmic_chg_irq[i]) {
3762 free_irq(chip->pmic_chg_irq[i], chip);
3763 chip->pmic_chg_irq[i] = 0;
3764 }
3765}
3766
David Keitel88e1b572012-01-11 11:57:14 -08003767/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3769{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003770 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003771 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003772
3773 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3774 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3775
3776 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003777 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003778 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003779 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003780 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003781 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782
3783 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3784 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3785 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003786 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003787 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3788 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003789 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003790 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3791 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003792 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003794 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3795 if (usb_chg_current)
3796 /*
3797 * Reissue a vbus draw call only if a battery
3798 * or DC is present. We don't want to brown out the
3799 * device if usb is its only source
3800 */
3801 __pm8921_charger_vbus_draw(usb_chg_current);
3802 usb_chg_current = 0;
3803
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003804 /*
3805 * The bootloader could have started charging, a fastchg interrupt
3806 * might not happen. Check the real time status and if it is fast
3807 * charging invoke the handler so that the eoc worker could be
3808 * started
3809 */
3810 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3811 if (is_fast_chg)
3812 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813
3814 fsm_state = pm_chg_get_fsm_state(chip);
3815 if (is_battery_charging(fsm_state)) {
3816 chip->bms_notify.is_charging = 1;
3817 pm8921_bms_charging_began();
3818 }
3819
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003820 check_battery_valid(chip);
3821
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3823 chip->usb_present,
3824 chip->dc_present,
3825 get_prop_batt_present(chip),
3826 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003827
3828 /* Determine which USB trim column to use */
3829 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3830 chip->usb_trim_table = usb_trim_8917_table;
3831 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3832 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003833}
3834
3835struct pm_chg_irq_init_data {
3836 unsigned int irq_id;
3837 char *name;
3838 unsigned long flags;
3839 irqreturn_t (*handler)(int, void *);
3840};
3841
3842#define CHG_IRQ(_id, _flags, _handler) \
3843{ \
3844 .irq_id = _id, \
3845 .name = #_id, \
3846 .flags = _flags, \
3847 .handler = _handler, \
3848}
3849struct pm_chg_irq_init_data chg_irq_data[] = {
3850 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3851 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003852 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3853 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003854 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3855 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003856 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3857 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3858 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3859 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3860 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3861 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3862 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3863 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003864 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3865 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003866 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3867 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3868 batt_removed_irq_handler),
3869 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3870 batttemp_hot_irq_handler),
3871 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3872 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3873 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003874 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3875 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003876 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3877 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3879 coarse_det_low_irq_handler),
3880 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3881 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3882 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3883 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3884 batfet_irq_handler),
3885 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3886 dcin_valid_irq_handler),
3887 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3888 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003889 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003890};
3891
3892static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3893 struct platform_device *pdev)
3894{
3895 struct resource *res;
3896 int ret, i;
3897
3898 ret = 0;
3899 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3900
3901 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3902 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3903 chg_irq_data[i].name);
3904 if (res == NULL) {
3905 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3906 goto err_out;
3907 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003908 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909 ret = request_irq(res->start, chg_irq_data[i].handler,
3910 chg_irq_data[i].flags,
3911 chg_irq_data[i].name, chip);
3912 if (ret < 0) {
3913 pr_err("couldn't request %d (%s) %d\n", res->start,
3914 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003915 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003916 goto err_out;
3917 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003918 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3919 }
3920 return 0;
3921
3922err_out:
3923 free_irqs(chip);
3924 return -EINVAL;
3925}
3926
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003927static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3928{
3929 int err;
3930 u8 temp;
3931
3932 temp = 0xD1;
3933 err = pm_chg_write(chip, CHG_TEST, temp);
3934 if (err) {
3935 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3936 return;
3937 }
3938
3939 temp = 0xD3;
3940 err = pm_chg_write(chip, CHG_TEST, temp);
3941 if (err) {
3942 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3943 return;
3944 }
3945
3946 temp = 0xD1;
3947 err = pm_chg_write(chip, CHG_TEST, temp);
3948 if (err) {
3949 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3950 return;
3951 }
3952
3953 temp = 0xD5;
3954 err = pm_chg_write(chip, CHG_TEST, temp);
3955 if (err) {
3956 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3957 return;
3958 }
3959
3960 udelay(183);
3961
3962 temp = 0xD1;
3963 err = pm_chg_write(chip, CHG_TEST, temp);
3964 if (err) {
3965 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3966 return;
3967 }
3968
3969 temp = 0xD0;
3970 err = pm_chg_write(chip, CHG_TEST, temp);
3971 if (err) {
3972 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3973 return;
3974 }
3975 udelay(32);
3976
3977 temp = 0xD1;
3978 err = pm_chg_write(chip, CHG_TEST, temp);
3979 if (err) {
3980 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3981 return;
3982 }
3983
3984 temp = 0xD3;
3985 err = pm_chg_write(chip, CHG_TEST, temp);
3986 if (err) {
3987 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3988 return;
3989 }
3990}
3991
3992static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3993{
3994 int err;
3995 u8 temp;
3996
3997 temp = 0xD1;
3998 err = pm_chg_write(chip, CHG_TEST, temp);
3999 if (err) {
4000 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4001 return;
4002 }
4003
4004 temp = 0xD0;
4005 err = pm_chg_write(chip, CHG_TEST, temp);
4006 if (err) {
4007 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4008 return;
4009 }
4010}
4011
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004012#define VREF_BATT_THERM_FORCE_ON BIT(7)
4013static void detect_battery_removal(struct pm8921_chg_chip *chip)
4014{
4015 u8 temp;
4016
4017 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4018 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4019
4020 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4021 /*
4022 * batt therm force on bit is battery backed and is default 0
4023 * The charger sets this bit at init time. If this bit is found
4024 * 0 that means the battery was removed. Tell the bms about it
4025 */
4026 pm8921_bms_invalidate_shutdown_soc();
4027}
4028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029#define ENUM_TIMER_STOP_BIT BIT(1)
4030#define BOOT_DONE_BIT BIT(6)
4031#define CHG_BATFET_ON_BIT BIT(3)
4032#define CHG_VCP_EN BIT(0)
4033#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4034#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004035#define PM_SUB_REV 0x001
4036#define MIN_CHARGE_CURRENT_MA 350
4037#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4039{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004040 u8 subrev;
4041 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004043 /* forcing 19p2mhz before accessing any charger registers */
4044 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004045
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004046 detect_battery_removal(chip);
4047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004049 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050 if (rc) {
4051 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4052 return rc;
4053 }
4054
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004055 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4056
4057 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4058 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4059
4060 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4061
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004062 if (rc) {
4063 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004064 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 return rc;
4066 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004067 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004068 chip->max_voltage_mv
4069 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070 if (rc) {
4071 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004072 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 return rc;
4074 }
4075
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004076 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 if (rc) {
4078 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004079 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 return rc;
4081 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004082
4083 if (chip->safe_current_ma == 0)
4084 chip->safe_current_ma = SAFE_CURRENT_MA;
4085
4086 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004087 if (rc) {
4088 pr_err("Failed to set max voltage to %d rc=%d\n",
4089 SAFE_CURRENT_MA, rc);
4090 return rc;
4091 }
4092
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004093 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 if (rc) {
4095 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4096 return rc;
4097 }
4098
4099 rc = pm_chg_iterm_set(chip, chip->term_current);
4100 if (rc) {
4101 pr_err("Failed to set term current to %d rc=%d\n",
4102 chip->term_current, rc);
4103 return rc;
4104 }
4105
4106 /* Disable the ENUM TIMER */
4107 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4108 ENUM_TIMER_STOP_BIT);
4109 if (rc) {
4110 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4111 return rc;
4112 }
4113
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004114 fcc_uah = pm8921_bms_get_fcc();
4115 if (fcc_uah > 0) {
4116 safety_time = div_s64((s64)fcc_uah * 60,
4117 1000 * MIN_CHARGE_CURRENT_MA);
4118 /* add 20 minutes of buffer time */
4119 safety_time += 20;
4120
4121 /* make sure we do not exceed the maximum programmable time */
4122 if (safety_time > PM8921_CHG_TCHG_MAX)
4123 safety_time = PM8921_CHG_TCHG_MAX;
4124 }
4125
4126 rc = pm_chg_tchg_max_set(chip, safety_time);
4127 if (rc) {
4128 pr_err("Failed to set max time to %d minutes rc=%d\n",
4129 safety_time, rc);
4130 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004131 }
4132
4133 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004134 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004135 if (rc) {
4136 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004137 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004138 return rc;
4139 }
4140 }
4141
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004142 if (chip->vin_min != 0) {
4143 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4144 if (rc) {
4145 pr_err("Failed to set vin min to %d mV rc=%d\n",
4146 chip->vin_min, rc);
4147 return rc;
4148 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004149 } else {
4150 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004151 }
4152
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153 rc = pm_chg_disable_wd(chip);
4154 if (rc) {
4155 pr_err("Failed to disable wd rc=%d\n", rc);
4156 return rc;
4157 }
4158
4159 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4160 CHG_BAT_TEMP_DIS_BIT, 0);
4161 if (rc) {
4162 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4163 return rc;
4164 }
4165 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004166 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4167 rc = pm_chg_write(chip,
4168 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4169 else
4170 rc = pm_chg_write(chip,
4171 CHG_BUCK_CLOCK_CTRL, 0x15);
4172
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004173 if (rc) {
4174 pr_err("Failed to switch buck clk rc=%d\n", rc);
4175 return rc;
4176 }
4177
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004178 if (chip->trkl_voltage != 0) {
4179 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4180 if (rc) {
4181 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4182 chip->trkl_voltage, rc);
4183 return rc;
4184 }
4185 }
4186
4187 if (chip->weak_voltage != 0) {
4188 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4189 if (rc) {
4190 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4191 chip->weak_voltage, rc);
4192 return rc;
4193 }
4194 }
4195
4196 if (chip->trkl_current != 0) {
4197 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4198 if (rc) {
4199 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4200 chip->trkl_voltage, rc);
4201 return rc;
4202 }
4203 }
4204
4205 if (chip->weak_current != 0) {
4206 rc = pm_chg_iweak_set(chip, chip->weak_current);
4207 if (rc) {
4208 pr_err("Failed to set weak current to %dmA rc=%d\n",
4209 chip->weak_current, rc);
4210 return rc;
4211 }
4212 }
4213
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004214 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4215 if (rc) {
4216 pr_err("Failed to set cold config %d rc=%d\n",
4217 chip->cold_thr, rc);
4218 }
4219
4220 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4221 if (rc) {
4222 pr_err("Failed to set hot config %d rc=%d\n",
4223 chip->hot_thr, rc);
4224 }
4225
Jay Chokshid674a512012-03-15 14:06:04 -07004226 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4227 if (rc) {
4228 pr_err("Failed to set charger LED src config %d rc=%d\n",
4229 chip->led_src_config, rc);
4230 }
4231
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004232 /* Workarounds for die 3.0 */
4233 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4234 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4235 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4236 if (rc) {
4237 pr_err("read failed: addr=%03X, rc=%d\n",
4238 PM_SUB_REV, rc);
4239 return rc;
4240 }
4241 /* Check if die 3.0.1 is present */
4242 if (subrev & 0x1)
4243 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4244 else
4245 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004246 }
4247
David Keitel0789fc62012-06-07 17:43:27 -07004248 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004249 /* Set PM8917 USB_OVP debounce time to 15 ms */
4250 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4251 OVP_DEBOUNCE_TIME, 0x6);
4252 if (rc) {
4253 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4254 return rc;
4255 }
4256
4257 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004258 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004259 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004260 rc = pm_chg_uvd_threshold_set(chip,
4261 chip->uvd_voltage_mv);
4262 if (rc) {
4263 pr_err("Failed to set UVD threshold %drc=%d\n",
4264 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004265 return rc;
4266 }
David Keitel0789fc62012-06-07 17:43:27 -07004267 }
4268 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004269
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004270 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004271
David Keitela3c0d822011-11-03 14:18:52 -07004272 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004273 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004274
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004275 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4276 VREF_BATT_THERM_FORCE_ON);
4277 if (rc)
4278 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004280 rc = pm_chg_charge_dis(chip, charging_disabled);
4281 if (rc) {
4282 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4283 return rc;
4284 }
4285
4286 rc = pm_chg_auto_enable(chip, !charging_disabled);
4287 if (rc) {
4288 pr_err("Failed to enable charging rc=%d\n", rc);
4289 return rc;
4290 }
4291
4292 return 0;
4293}
4294
4295static int get_rt_status(void *data, u64 * val)
4296{
4297 int i = (int)data;
4298 int ret;
4299
4300 /* global irq number is passed in via data */
4301 ret = pm_chg_get_rt_status(the_chip, i);
4302 *val = ret;
4303 return 0;
4304}
4305DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4306
4307static int get_fsm_status(void *data, u64 * val)
4308{
4309 u8 temp;
4310
4311 temp = pm_chg_get_fsm_state(the_chip);
4312 *val = temp;
4313 return 0;
4314}
4315DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4316
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004317static int get_reg_loop(void *data, u64 * val)
4318{
4319 u8 temp;
4320
4321 if (!the_chip) {
4322 pr_err("%s called before init\n", __func__);
4323 return -EINVAL;
4324 }
4325 temp = pm_chg_get_regulation_loop(the_chip);
4326 *val = temp;
4327 return 0;
4328}
4329DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004331static int get_reg(void *data, u64 * val)
4332{
4333 int addr = (int)data;
4334 int ret;
4335 u8 temp;
4336
4337 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4338 if (ret) {
4339 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4340 addr, temp, ret);
4341 return -EAGAIN;
4342 }
4343 *val = temp;
4344 return 0;
4345}
4346
4347static int set_reg(void *data, u64 val)
4348{
4349 int addr = (int)data;
4350 int ret;
4351 u8 temp;
4352
4353 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004354 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004356 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004357 addr, temp, ret);
4358 return -EAGAIN;
4359 }
4360 return 0;
4361}
4362DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4363
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004364static int reg_loop;
4365#define MAX_REG_LOOP_CHAR 10
4366static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4367{
4368 u8 temp;
4369
4370 if (!the_chip) {
4371 pr_err("called before init\n");
4372 return -EINVAL;
4373 }
4374 temp = pm_chg_get_regulation_loop(the_chip);
4375 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4376}
4377module_param_call(reg_loop, NULL, get_reg_loop_param,
4378 &reg_loop, 0644);
4379
4380static int max_chg_ma;
4381#define MAX_MA_CHAR 10
4382static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4383{
4384 if (!the_chip) {
4385 pr_err("called before init\n");
4386 return -EINVAL;
4387 }
4388 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4389}
4390module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4391 &max_chg_ma, 0644);
4392static int ibatmax_ma;
4393static int set_ibat_max(const char *val, struct kernel_param *kp)
4394{
4395 int rc;
4396
4397 if (!the_chip) {
4398 pr_err("called before init\n");
4399 return -EINVAL;
4400 }
4401
4402 rc = param_set_int(val, kp);
4403 if (rc) {
4404 pr_err("error setting value %d\n", rc);
4405 return rc;
4406 }
4407
4408 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4409 <= the_chip->ibatmax_max_adj_ma) {
4410 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4411 if (rc) {
4412 pr_err("Failed to set ibatmax rc = %d\n", rc);
4413 return rc;
4414 }
4415 }
4416
4417 return 0;
4418}
4419static int get_ibat_max(char *buf, struct kernel_param *kp)
4420{
4421 int ibat_ma;
4422 int rc;
4423
4424 if (!the_chip) {
4425 pr_err("called before init\n");
4426 return -EINVAL;
4427 }
4428
4429 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4430 if (rc) {
4431 pr_err("ibatmax_get error = %d\n", rc);
4432 return rc;
4433 }
4434
4435 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4436}
4437module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4438 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004439enum {
4440 BAT_WARM_ZONE,
4441 BAT_COOL_ZONE,
4442};
4443static int get_warm_cool(void *data, u64 * val)
4444{
4445 if (!the_chip) {
4446 pr_err("%s called before init\n", __func__);
4447 return -EINVAL;
4448 }
4449 if ((int)data == BAT_WARM_ZONE)
4450 *val = the_chip->is_bat_warm;
4451 if ((int)data == BAT_COOL_ZONE)
4452 *val = the_chip->is_bat_cool;
4453 return 0;
4454}
4455DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004457static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4458{
4459 int i;
4460
4461 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4462
4463 if (IS_ERR(chip->dent)) {
4464 pr_err("pmic charger couldnt create debugfs dir\n");
4465 return;
4466 }
4467
4468 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4469 (void *)CHG_CNTRL, &reg_fops);
4470 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4471 (void *)CHG_CNTRL_2, &reg_fops);
4472 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4473 (void *)CHG_CNTRL_3, &reg_fops);
4474 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4475 (void *)PBL_ACCESS1, &reg_fops);
4476 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4477 (void *)PBL_ACCESS2, &reg_fops);
4478 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4479 (void *)SYS_CONFIG_1, &reg_fops);
4480 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4481 (void *)SYS_CONFIG_2, &reg_fops);
4482 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4483 (void *)CHG_VDD_MAX, &reg_fops);
4484 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4485 (void *)CHG_VDD_SAFE, &reg_fops);
4486 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4487 (void *)CHG_VBAT_DET, &reg_fops);
4488 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4489 (void *)CHG_IBAT_MAX, &reg_fops);
4490 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4491 (void *)CHG_IBAT_SAFE, &reg_fops);
4492 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4493 (void *)CHG_VIN_MIN, &reg_fops);
4494 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4495 (void *)CHG_VTRICKLE, &reg_fops);
4496 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4497 (void *)CHG_ITRICKLE, &reg_fops);
4498 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4499 (void *)CHG_ITERM, &reg_fops);
4500 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4501 (void *)CHG_TCHG_MAX, &reg_fops);
4502 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4503 (void *)CHG_TWDOG, &reg_fops);
4504 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4505 (void *)CHG_TEMP_THRESH, &reg_fops);
4506 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4507 (void *)CHG_COMP_OVR, &reg_fops);
4508 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4509 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4510 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4511 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4512 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4513 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4514 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4515 (void *)CHG_TEST, &reg_fops);
4516
4517 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4518 &fsm_fops);
4519
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004520 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4521 &reg_loop_fops);
4522
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004523 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4524 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4525 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4526 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4529 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4530 debugfs_create_file(chg_irq_data[i].name, 0444,
4531 chip->dent,
4532 (void *)chg_irq_data[i].irq_id,
4533 &rt_fops);
4534 }
4535}
4536
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004537static int pm8921_charger_suspend_noirq(struct device *dev)
4538{
4539 int rc;
4540 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4541
4542 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4543 if (rc)
4544 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004545
4546 rc = pm8921_chg_set_lpm(chip, 1);
4547 if (rc)
4548 pr_err("Failed to set lpm rc=%d\n", rc);
4549
4550 pm8921_chg_set_hw_clk_switching(chip);
4551
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004552 return 0;
4553}
4554
4555static int pm8921_charger_resume_noirq(struct device *dev)
4556{
4557 int rc;
4558 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4559
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004560 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004561
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004562 rc = pm8921_chg_set_lpm(chip, 0);
4563 if (rc)
4564 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004565
4566 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4567 VREF_BATT_THERM_FORCE_ON);
4568 if (rc)
4569 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4570 return 0;
4571}
4572
David Keitelf2226022011-12-13 15:55:50 -08004573static int pm8921_charger_resume(struct device *dev)
4574{
David Keitelf2226022011-12-13 15:55:50 -08004575 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4576
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004577 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4578 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4579 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4580 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004581
4582 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4583 is_usb_chg_plugged_in(the_chip)))
4584 schedule_delayed_work(&chip->btc_override_work, 0);
4585
David Keitelf2226022011-12-13 15:55:50 -08004586 return 0;
4587}
4588
4589static int pm8921_charger_suspend(struct device *dev)
4590{
David Keitelf2226022011-12-13 15:55:50 -08004591 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4592
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004593 if (chip->btc_override)
4594 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004595
4596 if (is_usb_chg_plugged_in(chip)) {
4597 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4598 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4599 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004600
David Keitelf2226022011-12-13 15:55:50 -08004601 return 0;
4602}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004603static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4604{
4605 int rc = 0;
4606 struct pm8921_chg_chip *chip;
4607 const struct pm8921_charger_platform_data *pdata
4608 = pdev->dev.platform_data;
4609
4610 if (!pdata) {
4611 pr_err("missing platform data\n");
4612 return -EINVAL;
4613 }
4614
4615 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4616 GFP_KERNEL);
4617 if (!chip) {
4618 pr_err("Cannot allocate pm_chg_chip\n");
4619 return -ENOMEM;
4620 }
4621
4622 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004623 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004624 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004625 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004626 chip->alarm_low_mv = pdata->alarm_low_mv;
4627 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004628 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004629 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004630 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004631 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004632 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004633 chip->term_current = pdata->term_current;
4634 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004635 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004636 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4637 chip->batt_id_min = pdata->batt_id_min;
4638 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004639 if (pdata->cool_temp != INT_MIN)
4640 chip->cool_temp_dc = pdata->cool_temp * 10;
4641 else
4642 chip->cool_temp_dc = INT_MIN;
4643
4644 if (pdata->warm_temp != INT_MIN)
4645 chip->warm_temp_dc = pdata->warm_temp * 10;
4646 else
4647 chip->warm_temp_dc = INT_MIN;
4648
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004649 chip->temp_check_period = pdata->temp_check_period;
4650 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004651 /* Assign to corresponding module parameter */
4652 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004653 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4654 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4655 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4656 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004657 chip->trkl_voltage = pdata->trkl_voltage;
4658 chip->weak_voltage = pdata->weak_voltage;
4659 chip->trkl_current = pdata->trkl_current;
4660 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004661 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004662 chip->thermal_mitigation = pdata->thermal_mitigation;
4663 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304664 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004666 chip->cold_thr = pdata->cold_thr;
4667 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004668 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004669 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004670 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004671 chip->battery_less_hardware = pdata->battery_less_hardware;
4672 chip->btc_override = pdata->btc_override;
4673 if (chip->btc_override) {
4674 chip->btc_delay_ms = pdata->btc_delay_ms;
4675 chip->btc_override_cold_decidegc
4676 = pdata->btc_override_cold_degc * 10;
4677 chip->btc_override_hot_decidegc
4678 = pdata->btc_override_hot_degc * 10;
4679 chip->btc_panic_if_cant_stop_chg
4680 = pdata->btc_panic_if_cant_stop_chg;
4681 }
4682
4683 if (chip->battery_less_hardware)
4684 charging_disabled = 1;
4685
4686 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4687 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004689 rc = pm8921_chg_hw_init(chip);
4690 if (rc) {
4691 pr_err("couldn't init hardware rc=%d\n", rc);
4692 goto free_chip;
4693 }
4694
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004695 if (chip->btc_override)
4696 pm8921_chg_btc_override_init(chip);
4697
4698 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304699 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004700
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004701 chip->usb_psy.name = "usb";
4702 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4703 chip->usb_psy.supplied_to = pm_power_supplied_to;
4704 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4705 chip->usb_psy.properties = pm_power_props_usb;
4706 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4707 chip->usb_psy.get_property = pm_power_get_property_usb;
4708 chip->usb_psy.set_property = pm_power_set_property_usb;
4709 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004711 chip->dc_psy.name = "pm8921-dc";
4712 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4713 chip->dc_psy.supplied_to = pm_power_supplied_to;
4714 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4715 chip->dc_psy.properties = pm_power_props_mains;
4716 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4717 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004718
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004719 chip->batt_psy.name = "battery";
4720 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4721 chip->batt_psy.properties = msm_batt_power_props;
4722 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4723 chip->batt_psy.get_property = pm_batt_power_get_property;
4724 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004725 rc = power_supply_register(chip->dev, &chip->usb_psy);
4726 if (rc < 0) {
4727 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004728 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729 }
4730
David Keitel6ed71a52012-01-30 12:42:18 -08004731 rc = power_supply_register(chip->dev, &chip->dc_psy);
4732 if (rc < 0) {
4733 pr_err("power_supply_register usb failed rc = %d\n", rc);
4734 goto unregister_usb;
4735 }
4736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737 rc = power_supply_register(chip->dev, &chip->batt_psy);
4738 if (rc < 0) {
4739 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004740 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004741 }
4742
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004743 platform_set_drvdata(pdev, chip);
4744 the_chip = chip;
4745
4746 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004747 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004748 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4749 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004750 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004751
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004752 INIT_WORK(&chip->bms_notify.work, bms_notify);
4753 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4754
4755 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4756 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4757
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758 rc = request_irqs(chip, pdev);
4759 if (rc) {
4760 pr_err("couldn't register interrupts rc=%d\n", rc);
4761 goto unregister_batt;
4762 }
4763
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004764 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004765 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004766 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004767 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004769 create_debugfs_entries(chip);
4770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004771 /* determine what state the charger is in */
4772 determine_initial_state(chip);
4773
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004774 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004775 schedule_delayed_work(&chip->update_heartbeat_work,
4776 round_jiffies_relative(msecs_to_jiffies
4777 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004778 return 0;
4779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004781 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004782 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004783unregister_dc:
4784 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785unregister_usb:
4786 power_supply_unregister(&chip->usb_psy);
4787free_chip:
4788 kfree(chip);
4789 return rc;
4790}
4791
4792static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4793{
4794 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4795
4796 free_irqs(chip);
4797 platform_set_drvdata(pdev, NULL);
4798 the_chip = NULL;
4799 kfree(chip);
4800 return 0;
4801}
David Keitelf2226022011-12-13 15:55:50 -08004802static const struct dev_pm_ops pm8921_pm_ops = {
4803 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004804 .suspend_noirq = pm8921_charger_suspend_noirq,
4805 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004806 .resume = pm8921_charger_resume,
4807};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004808static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004809 .probe = pm8921_charger_probe,
4810 .remove = __devexit_p(pm8921_charger_remove),
4811 .driver = {
4812 .name = PM8921_CHARGER_DEV_NAME,
4813 .owner = THIS_MODULE,
4814 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004815 },
4816};
4817
4818static int __init pm8921_charger_init(void)
4819{
4820 return platform_driver_register(&pm8921_charger_driver);
4821}
4822
4823static void __exit pm8921_charger_exit(void)
4824{
4825 platform_driver_unregister(&pm8921_charger_driver);
4826}
4827
4828late_initcall(pm8921_charger_init);
4829module_exit(pm8921_charger_exit);
4830
4831MODULE_LICENSE("GPL v2");
4832MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4833MODULE_VERSION("1.0");
4834MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);