blob: e00e1c37bd26f2b5a4dadcb55f67a15bb550d268 [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
Anirudh Ghayale747b7e2013-04-04 12:18:18 +0530216 * @hysteresis_temp_dc: the hysteresis between temp thresholds in
217 * deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700218 * @resume_voltage_delta: the voltage delta from vdd max at which the
219 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 * @term_current: The charging based term current
221 *
222 */
223struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700224 struct device *dev;
225 unsigned int usb_present;
226 unsigned int dc_present;
227 unsigned int usb_charger_current;
228 unsigned int max_bat_chg_current;
229 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700230 unsigned int ttrkl_time;
231 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800232 unsigned int max_voltage_mv;
233 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700234 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700235 unsigned int safe_current_ma;
236 unsigned int alarm_low_mv;
237 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800238 int cool_temp_dc;
239 int warm_temp_dc;
Anirudh Ghayale747b7e2013-04-04 12:18:18 +0530240 int hysteresis_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700241 unsigned int temp_check_period;
242 unsigned int cool_bat_chg_current;
243 unsigned int warm_bat_chg_current;
244 unsigned int cool_bat_voltage;
245 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700246 unsigned int is_bat_cool;
247 unsigned int is_bat_warm;
248 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700249 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700250 unsigned int term_current;
251 unsigned int vbat_channel;
252 unsigned int batt_temp_channel;
253 unsigned int batt_id_channel;
254 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800255 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800256 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700257 struct power_supply batt_psy;
258 struct dentry *dent;
259 struct bms_notify bms_notify;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700260 int *usb_trim_table;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200261 bool ext_charging;
262 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700263 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700265 struct work_struct battery_id_valid_work;
266 int64_t batt_id_min;
267 int64_t batt_id_max;
268 int trkl_voltage;
269 int weak_voltage;
270 int trkl_current;
271 int weak_current;
272 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800273 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700274 int thermal_levels;
275 struct delayed_work update_heartbeat_work;
276 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800277 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800278 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700279 struct delayed_work btc_override_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700280 struct wake_lock eoc_wake_lock;
281 enum pm8921_chg_cold_thr cold_thr;
282 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800283 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700284 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700285 bool host_mode;
David Keitelff4f9ce2012-08-24 15:11:23 -0700286 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700287 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700288 int recent_reported_soc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700289 int battery_less_hardware;
290 int ibatmax_max_adj_ma;
291 int btc_override;
292 int btc_override_cold_decidegc;
293 int btc_override_hot_decidegc;
294 int btc_delay_ms;
295 bool btc_panic_if_cant_stop_chg;
296 int stop_chg_upon_expiry;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -0800297 bool disable_aicl;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +0530298 int usb_type;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +0530299 bool disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300};
301
David Keitelacf57c82012-03-07 18:48:50 -0800302/* user space parameter to limit usb current */
303static unsigned int usb_max_current;
304/*
305 * usb_target_ma is used for wall charger
306 * adaptive input current limiting only. Use
307 * pm_iusbmax_get() to get current maximum usb current setting.
308 */
309static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700311static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700312
313static struct pm8921_chg_chip *the_chip;
Anirudh Ghayale747b7e2013-04-04 12:18:18 +0530314static void check_temp_thresholds(struct pm8921_chg_chip *chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700316#define LPM_ENABLE_BIT BIT(2)
317static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
318{
319 int rc;
320 u8 reg;
321
322 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
323 if (rc) {
324 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
325 CHG_CNTRL, rc);
326 return rc;
327 }
328 reg &= ~LPM_ENABLE_BIT;
329 reg |= (enable ? LPM_ENABLE_BIT : 0);
330
331 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
332 if (rc) {
333 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
334 CHG_CNTRL, rc);
335 return rc;
336 }
337
338 return rc;
339}
340
341static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
342{
343 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700344
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -0800345 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
346 if (rc)
347 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700348
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700349 return rc;
350}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700351
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700352static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
353 u8 mask, u8 val)
354{
355 int rc;
356 u8 reg;
357
358 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
359 if (rc) {
360 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
361 return rc;
362 }
363 reg &= ~mask;
364 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700365 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700366 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700367 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368 return rc;
369 }
370 return 0;
371}
372
David Keitelcf867232012-01-27 18:40:12 -0800373static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
374{
375 return pm8xxx_read_irq_stat(chip->dev->parent,
376 chip->pmic_chg_irq[irq_id]);
377}
378
379/* Treat OverVoltage/UnderVoltage as source missing */
380static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
381{
382 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
383}
384
385/* Treat OverVoltage/UnderVoltage as source missing */
386static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
387{
388 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
389}
390
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700391static int is_batfet_closed(struct pm8921_chg_chip *chip)
392{
393 return pm_chg_get_rt_status(chip, BATFET_IRQ);
394}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700395#define CAPTURE_FSM_STATE_CMD 0xC2
396#define READ_BANK_7 0x70
397#define READ_BANK_4 0x40
398static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
399{
400 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800401 int err = 0, ret = 0;
402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800404 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 if (err) {
406 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800407 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 }
409
410 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800411 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 if (err) {
413 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800414 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 }
416
417 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
418 if (err) {
419 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800420 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 }
422 /* get the lower 4 bits */
423 ret = temp & 0xF;
424
425 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800426 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427 if (err) {
428 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800429 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700430 }
431
432 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
433 if (err) {
434 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800435 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 }
437 /* get the upper 1 bit */
438 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800439
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800440err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800441 if (err)
442 return err;
443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700444 return ret;
445}
446
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700447#define READ_BANK_6 0x60
448static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
449{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800450 u8 temp, data;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800451 int err = 0;
452
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700453 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800454 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700455 if (err) {
456 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800457 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700458 }
459
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800460 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700461 if (err) {
462 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800463 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700464 }
465
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800466err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800467 if (err)
468 return err;
469
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700470 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800471 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700472}
473
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474#define CHG_USB_SUSPEND_BIT BIT(2)
475static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
476{
477 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
478 enable ? CHG_USB_SUSPEND_BIT : 0);
479}
480
481#define CHG_EN_BIT BIT(7)
482static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
483{
484 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
485 enable ? CHG_EN_BIT : 0);
486}
487
David Keitel753ec8d2011-11-02 10:56:37 -0700488#define CHG_FAILED_CLEAR BIT(0)
489#define ATC_FAILED_CLEAR BIT(1)
490static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
491{
492 int rc;
493
494 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
495 clear ? ATC_FAILED_CLEAR : 0);
496 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
497 clear ? CHG_FAILED_CLEAR : 0);
498 return rc;
499}
500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501#define CHG_CHARGE_DIS_BIT BIT(1)
502static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
503{
504 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
505 disable ? CHG_CHARGE_DIS_BIT : 0);
506}
507
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800508static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
509{
510 u8 temp;
511
512 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
513 return temp & CHG_CHARGE_DIS_BIT;
514}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515#define PM8921_CHG_V_MIN_MV 3240
516#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800517#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518#define PM8921_CHG_VDDMAX_MAX 4500
519#define PM8921_CHG_VDDMAX_MIN 3400
520#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800521static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800523 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800524 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800526 if (voltage < PM8921_CHG_VDDMAX_MIN
527 || voltage > PM8921_CHG_VDDMAX_MAX) {
528 pr_err("bad mV=%d asked to set\n", voltage);
529 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 }
David Keitelcf867232012-01-27 18:40:12 -0800531
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800532 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
533
534 remainder = voltage % 20;
535 if (remainder >= 10) {
536 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
537 }
538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700540 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541}
542
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700543static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
544{
545 u8 temp;
546 int rc;
547
548 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
549 if (rc) {
550 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700551 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700552 return rc;
553 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800554 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
555 + PM8921_CHG_V_MIN_MV;
556 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
557 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700558 return 0;
559}
560
David Keitelcf867232012-01-27 18:40:12 -0800561static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
562{
563 int current_mv, ret, steps, i;
564 bool increase;
565
566 ret = 0;
567
568 if (voltage < PM8921_CHG_VDDMAX_MIN
569 || voltage > PM8921_CHG_VDDMAX_MAX) {
570 pr_err("bad mV=%d asked to set\n", voltage);
571 return -EINVAL;
572 }
573
574 ret = pm_chg_vddmax_get(chip, &current_mv);
575 if (ret) {
576 pr_err("Failed to read vddmax rc=%d\n", ret);
577 return -EINVAL;
578 }
579 if (current_mv == voltage)
580 return 0;
581
582 /* Only change in increments when USB is present */
583 if (is_usb_chg_plugged_in(chip)) {
584 if (current_mv < voltage) {
585 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
586 increase = true;
587 } else {
588 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
589 increase = false;
590 }
591 for (i = 0; i < steps; i++) {
592 if (increase)
593 current_mv += PM8921_CHG_V_STEP_MV;
594 else
595 current_mv -= PM8921_CHG_V_STEP_MV;
596 ret |= __pm_chg_vddmax_set(chip, current_mv);
597 }
598 }
599 ret |= __pm_chg_vddmax_set(chip, voltage);
600 return ret;
601}
602
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603#define PM8921_CHG_VDDSAFE_MIN 3400
604#define PM8921_CHG_VDDSAFE_MAX 4500
605static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
606{
607 u8 temp;
608
609 if (voltage < PM8921_CHG_VDDSAFE_MIN
610 || voltage > PM8921_CHG_VDDSAFE_MAX) {
611 pr_err("bad mV=%d asked to set\n", voltage);
612 return -EINVAL;
613 }
614 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
615 pr_debug("voltage=%d setting %02x\n", voltage, temp);
616 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
617}
618
619#define PM8921_CHG_VBATDET_MIN 3240
620#define PM8921_CHG_VBATDET_MAX 5780
621static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
622{
623 u8 temp;
624
625 if (voltage < PM8921_CHG_VBATDET_MIN
626 || voltage > PM8921_CHG_VBATDET_MAX) {
627 pr_err("bad mV=%d asked to set\n", voltage);
628 return -EINVAL;
629 }
630 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
631 pr_debug("voltage=%d setting %02x\n", voltage, temp);
632 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
633}
634
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700635#define PM8921_CHG_VINMIN_MIN_MV 3800
636#define PM8921_CHG_VINMIN_STEP_MV 100
637#define PM8921_CHG_VINMIN_USABLE_MAX 6500
638#define PM8921_CHG_VINMIN_USABLE_MIN 4300
639#define PM8921_CHG_VINMIN_MASK 0x1F
640static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
641{
642 u8 temp;
643
644 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
645 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
646 pr_err("bad mV=%d asked to set\n", voltage);
647 return -EINVAL;
648 }
649 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
650 pr_debug("voltage=%d setting %02x\n", voltage, temp);
651 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
652 temp);
653}
654
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800655static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
656{
657 u8 temp;
658 int rc, voltage_mv;
659
660 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
661 temp &= PM8921_CHG_VINMIN_MASK;
662
663 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
664 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
665
666 return voltage_mv;
667}
668
David Keitel0789fc62012-06-07 17:43:27 -0700669#define PM8917_USB_UVD_MIN_MV 3850
670#define PM8917_USB_UVD_MAX_MV 4350
671#define PM8917_USB_UVD_STEP_MV 100
672#define PM8917_USB_UVD_MASK 0x7
673static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
674{
675 u8 temp;
676
677 if (thresh_mv < PM8917_USB_UVD_MIN_MV
678 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
679 pr_err("bad mV=%d asked to set\n", thresh_mv);
680 return -EINVAL;
681 }
682 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
683 return pm_chg_masked_write(chip, OVP_USB_UVD,
684 PM8917_USB_UVD_MASK, temp);
685}
686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700688#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689#define PM8921_CHG_I_MIN_MA 225
690#define PM8921_CHG_I_STEP_MA 50
691#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700692static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
693{
694 u8 temp;
695 int rc;
696
697 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
698 if (rc) {
699 pr_err("rc = %d while reading ibat max\n", rc);
700 *ibat_ma = 0;
701 return rc;
702 }
703 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
704 + PM8921_CHG_I_MIN_MA;
705 return 0;
706}
707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
709{
710 u8 temp;
711
712 if (chg_current < PM8921_CHG_IBATMAX_MIN
713 || chg_current > PM8921_CHG_IBATMAX_MAX) {
714 pr_err("bad mA=%d asked to set\n", chg_current);
715 return -EINVAL;
716 }
717 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
718 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
719}
720
721#define PM8921_CHG_IBATSAFE_MIN 225
722#define PM8921_CHG_IBATSAFE_MAX 3375
723static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
724{
725 u8 temp;
726
727 if (chg_current < PM8921_CHG_IBATSAFE_MIN
728 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
729 pr_err("bad mA=%d asked to set\n", chg_current);
730 return -EINVAL;
731 }
732 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
733 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
734 PM8921_CHG_I_MASK, temp);
735}
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700738#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700739#define PM8921_CHG_ITERM_STEP_MA 10
740#define PM8921_CHG_ITERM_MASK 0xF
741static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
742{
743 u8 temp;
744
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700745 if (chg_current < PM8921_CHG_ITERM_MIN_MA
746 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700747 pr_err("bad mA=%d asked to set\n", chg_current);
748 return -EINVAL;
749 }
750
751 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
752 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700753 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 temp);
755}
756
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700757static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
758{
759 u8 temp;
760 int rc;
761
762 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
763 if (rc) {
764 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700765 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700766 return rc;
767 }
768 temp &= PM8921_CHG_ITERM_MASK;
769 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
770 + PM8921_CHG_ITERM_MIN_MA;
771 return 0;
772}
773
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800774struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700775 int usb_ma;
776 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800777};
778
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700779/* USB Trim tables */
780static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
781 0x0,
782 0x0,
783 -0x9,
784 0x0,
785 -0xD,
786 0x0,
787 -0x10,
788 -0x11,
789 0x0,
790 0x0,
791 -0x25,
792 0x0,
793 -0x28,
794 0x0,
795 -0x32,
796 0x0
797};
798
799static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
800 0x0,
801 0x0,
802 0xA,
803 0xC,
804 0x10,
805 0x10,
806 0x13,
807 0x14,
808 0x13,
809 0x3,
810 0x1A,
811 0x1D,
812 0x1D,
813 0x21,
814 0x24,
815 0x26
816};
817
818/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800819static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700820 {100, 0x0},
821 {200, 0x1},
822 {500, 0x2},
823 {600, 0x3},
824 {700, 0x4},
825 {800, 0x5},
826 {850, 0x6},
827 {900, 0x8},
828 {950, 0x7},
829 {1000, 0x9},
830 {1100, 0xA},
831 {1200, 0xB},
832 {1300, 0xC},
833 {1400, 0xD},
834 {1500, 0xE},
835 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800836};
837
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700838#define REG_SBI_CONFIG 0x04F
839#define PAGE3_ENABLE_MASK 0x6
840#define USB_OVP_TRIM_MASK 0x3F
841#define USB_OVP_TRIM_PM8917_MASK 0x7F
842#define USB_OVP_TRIM_MIN 0x00
843#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
844#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
845#define REG_USB_OVP_TRIM_PM8917 0x2B5
846#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
847static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
848{
849 u8 temp, sbi_config, msb, lsb, mask;
850 s8 trim;
851 int rc = 0;
852 static u8 usb_trim_reg_orig = 0xFF;
853
854 /* No trim data for PM8921 */
855 if (!chip->usb_trim_table)
856 return 0;
857
858 if (usb_trim_reg_orig == 0xFF) {
859 rc = pm8xxx_readb(chip->dev->parent,
860 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
861 if (rc) {
862 pr_err("error = %d reading sbi config reg\n", rc);
863 return rc;
864 }
865
866 rc = pm8xxx_readb(chip->dev->parent,
867 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
868 if (rc) {
869 pr_err("error = %d reading sbi config reg\n", rc);
870 return rc;
871 }
872
873 msb = msb >> 5;
874 lsb = lsb >> 5;
875 usb_trim_reg_orig = msb << 3 | lsb;
876
877 if (pm8xxx_get_version(chip->dev->parent)
878 == PM8XXX_VERSION_8917) {
879 rc = pm8xxx_readb(chip->dev->parent,
880 REG_USB_OVP_TRIM_PM8917, &msb);
881 if (rc) {
882 pr_err("error = %d reading config reg\n", rc);
883 return rc;
884 }
885
886 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
887 usb_trim_reg_orig |= msb << 6;
888 }
889 }
890
891 /* use the original trim value */
892 trim = usb_trim_reg_orig;
893
894 trim += chip->usb_trim_table[index];
895 if (trim < 0)
896 trim = 0;
897
898 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
899 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
900
901 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
902 if (rc) {
903 pr_err("error = %d reading sbi config reg\n", rc);
904 return rc;
905 }
906
907 temp = sbi_config | PAGE3_ENABLE_MASK;
908 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
909 if (rc) {
910 pr_err("error = %d writing sbi config reg\n", rc);
911 return rc;
912 }
913
914 mask = USB_OVP_TRIM_MASK;
915
916 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
917 mask = USB_OVP_TRIM_PM8917_MASK;
918
919 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
920 if (rc) {
921 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
922 return rc;
923 }
924
925 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
926 if (rc) {
927 pr_err("error = %d writing sbi config reg\n", rc);
928 return rc;
929 }
930 return rc;
931}
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700934#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935#define PM8921_CHG_IUSB_MAX 7
936#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700937#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700938static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700940 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700941 int rc;
942
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700943 reg_val = usb_ma_table[index].value >> 1;
944 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700945
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700946 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
947 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700948 return -EINVAL;
949 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700950 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
951
952 /* IUSB_FINE_RES */
953 if (chip->iusb_fine_res) {
954 /* Clear IUSB_FINE_RES bit to avoid overshoot */
955 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
956 PM8917_IUSB_FINE_RES, 0);
957
958 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
959 PM8921_CHG_IUSB_MASK, temp);
960
961 if (rc) {
962 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
963 return rc;
964 }
965
966 if (fineres) {
967 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
968 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700969 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700970 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
971 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700972 return rc;
973 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700974 }
975 } else {
976 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
977 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700978 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700979 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700980 return rc;
981 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700982 }
983
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700984 rc = pm_chg_usb_trim(chip, index);
985 if (rc)
986 pr_err("unable to set usb trim rc = %d\n", rc);
987
David Keitel38bdd4f2012-04-19 15:39:13 -0700988 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989}
990
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800991static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
992{
David Keitel38bdd4f2012-04-19 15:39:13 -0700993 u8 temp, fineres;
994 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800995
David Keitel38bdd4f2012-04-19 15:39:13 -0700996 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800997 *mA = 0;
998 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
999 if (rc) {
1000 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1001 return rc;
1002 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001003
1004 if (chip->iusb_fine_res) {
1005 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1006 if (rc) {
1007 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1008 return rc;
1009 }
1010 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001011 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001012 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1013
1014 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1015 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1016 if (usb_ma_table[i].value == temp)
1017 break;
1018 }
1019
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001020 if (i < 0) {
1021 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1022 i = 0;
1023 }
1024
David Keitel38bdd4f2012-04-19 15:39:13 -07001025 *mA = usb_ma_table[i].usb_ma;
1026
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001027 return rc;
1028}
1029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030#define PM8921_CHG_WD_MASK 0x1F
1031static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1032{
1033 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001034 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1035}
1036
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001037#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001038#define PM8921_CHG_TCHG_MIN 4
1039#define PM8921_CHG_TCHG_MAX 512
1040#define PM8921_CHG_TCHG_STEP 4
1041static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1042{
1043 u8 temp;
1044
1045 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1046 pr_err("bad max minutes =%d asked to set\n", minutes);
1047 return -EINVAL;
1048 }
1049
1050 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1051 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1052 temp);
1053}
1054
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001055#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001056#define PM8921_CHG_TTRKL_MIN 1
1057#define PM8921_CHG_TTRKL_MAX 64
1058static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1059{
1060 u8 temp;
1061
1062 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1063 pr_err("bad max minutes =%d asked to set\n", minutes);
1064 return -EINVAL;
1065 }
1066
1067 temp = minutes - 1;
1068 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1069 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070}
1071
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001072#define PM8921_CHG_VTRKL_MIN_MV 2050
1073#define PM8921_CHG_VTRKL_MAX_MV 2800
1074#define PM8921_CHG_VTRKL_STEP_MV 50
1075#define PM8921_CHG_VTRKL_SHIFT 4
1076#define PM8921_CHG_VTRKL_MASK 0xF0
1077static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1078{
1079 u8 temp;
1080
1081 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1082 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1083 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1084 return -EINVAL;
1085 }
1086
1087 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1088 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1089 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1090 temp);
1091}
1092
1093#define PM8921_CHG_VWEAK_MIN_MV 2100
1094#define PM8921_CHG_VWEAK_MAX_MV 3600
1095#define PM8921_CHG_VWEAK_STEP_MV 100
1096#define PM8921_CHG_VWEAK_MASK 0x0F
1097static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1098{
1099 u8 temp;
1100
1101 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1102 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1103 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1104 return -EINVAL;
1105 }
1106
1107 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1108 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1109 temp);
1110}
1111
1112#define PM8921_CHG_ITRKL_MIN_MA 50
1113#define PM8921_CHG_ITRKL_MAX_MA 200
1114#define PM8921_CHG_ITRKL_MASK 0x0F
1115#define PM8921_CHG_ITRKL_STEP_MA 10
1116static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1117{
1118 u8 temp;
1119
1120 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1121 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1122 pr_err("bad current = %dmA asked to set\n", milliamps);
1123 return -EINVAL;
1124 }
1125
1126 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1127
1128 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1129 temp);
1130}
1131
1132#define PM8921_CHG_IWEAK_MIN_MA 325
1133#define PM8921_CHG_IWEAK_MAX_MA 525
1134#define PM8921_CHG_IWEAK_SHIFT 7
1135#define PM8921_CHG_IWEAK_MASK 0x80
1136static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1137{
1138 u8 temp;
1139
1140 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1141 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1142 pr_err("bad current = %dmA asked to set\n", milliamps);
1143 return -EINVAL;
1144 }
1145
1146 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1147 temp = 0;
1148 else
1149 temp = 1;
1150
1151 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1152 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1153 temp);
1154}
1155
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001156#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1157#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1158static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1159 enum pm8921_chg_cold_thr cold_thr)
1160{
1161 u8 temp;
1162
1163 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1164 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1165 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1166 PM8921_CHG_BATT_TEMP_THR_COLD,
1167 temp);
1168}
1169
1170#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1171#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1172static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1173 enum pm8921_chg_hot_thr hot_thr)
1174{
1175 u8 temp;
1176
1177 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1178 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1179 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1180 PM8921_CHG_BATT_TEMP_THR_HOT,
1181 temp);
1182}
1183
Jay Chokshid674a512012-03-15 14:06:04 -07001184#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1185#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1186static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1187 enum pm8921_chg_led_src_config led_src_config)
1188{
1189 u8 temp;
1190
1191 if (led_src_config < LED_SRC_GND ||
1192 led_src_config > LED_SRC_BYPASS)
1193 return -EINVAL;
1194
1195 if (led_src_config == LED_SRC_BYPASS)
1196 return 0;
1197
1198 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1199
1200 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1201 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1202}
1203
David Keitel8c5201a2012-02-24 16:08:54 -08001204
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001205static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1206{
1207 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001208 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001209
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001210 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001211 if (rc) {
1212 pr_err("error reading batt id channel = %d, rc = %d\n",
1213 chip->vbat_channel, rc);
1214 return rc;
1215 }
1216 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1217 result.measurement);
1218 return result.physical;
1219}
1220
1221static int is_battery_valid(struct pm8921_chg_chip *chip)
1222{
1223 int64_t rc;
1224
1225 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1226 return 1;
1227
1228 rc = read_battery_id(chip);
1229 if (rc < 0) {
1230 pr_err("error reading batt id channel = %d, rc = %lld\n",
1231 chip->vbat_channel, rc);
1232 /* assume battery id is valid when adc error happens */
1233 return 1;
1234 }
1235
1236 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1237 pr_err("batt_id phy =%lld is not valid\n", rc);
1238 return 0;
1239 }
1240 return 1;
1241}
1242
1243static void check_battery_valid(struct pm8921_chg_chip *chip)
1244{
1245 if (is_battery_valid(chip) == 0) {
1246 pr_err("batt_id not valid, disbling charging\n");
1247 pm_chg_auto_enable(chip, 0);
1248 } else {
1249 pm_chg_auto_enable(chip, !charging_disabled);
1250 }
1251}
1252
1253static void battery_id_valid(struct work_struct *work)
1254{
1255 struct pm8921_chg_chip *chip = container_of(work,
1256 struct pm8921_chg_chip, battery_id_valid_work);
1257
1258 check_battery_valid(chip);
1259}
1260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1262{
1263 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1264 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1265 enable_irq(chip->pmic_chg_irq[interrupt]);
1266 }
1267}
1268
1269static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1270{
1271 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1272 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1273 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1274 }
1275}
1276
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001277static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1278{
1279 return test_bit(interrupt, chip->enabled_irqs);
1280}
1281
Amir Samuelovd31ef502011-10-26 14:41:36 +02001282static bool is_ext_charging(struct pm8921_chg_chip *chip)
1283{
David Keitel88e1b572012-01-11 11:57:14 -08001284 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001285
David Keitel88e1b572012-01-11 11:57:14 -08001286 if (!chip->ext_psy)
1287 return false;
1288 if (chip->ext_psy->get_property(chip->ext_psy,
1289 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1290 return false;
1291 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1292 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001293
1294 return false;
1295}
1296
1297static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1298{
David Keitel88e1b572012-01-11 11:57:14 -08001299 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001300
David Keitel88e1b572012-01-11 11:57:14 -08001301 if (!chip->ext_psy)
1302 return false;
1303 if (chip->ext_psy->get_property(chip->ext_psy,
1304 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1305 return false;
1306 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001307 return true;
1308
1309 return false;
1310}
1311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312static int is_battery_charging(int fsm_state)
1313{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001314 if (is_ext_charging(the_chip))
1315 return 1;
1316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 switch (fsm_state) {
1318 case FSM_STATE_ATC_2A:
1319 case FSM_STATE_ATC_2B:
1320 case FSM_STATE_ON_CHG_AND_BAT_6:
1321 case FSM_STATE_FAST_CHG_7:
1322 case FSM_STATE_TRKL_CHG_8:
1323 return 1;
1324 }
1325 return 0;
1326}
1327
1328static void bms_notify(struct work_struct *work)
1329{
1330 struct bms_notify *n = container_of(work, struct bms_notify, work);
1331
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001332 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001334 } else {
1335 pm8921_bms_charging_end(n->is_battery_full);
1336 n->is_battery_full = 0;
1337 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338}
1339
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001340static void bms_notify_check(struct pm8921_chg_chip *chip)
1341{
1342 int fsm_state, new_is_charging;
1343
1344 fsm_state = pm_chg_get_fsm_state(chip);
1345 new_is_charging = is_battery_charging(fsm_state);
1346
1347 if (chip->bms_notify.is_charging ^ new_is_charging) {
1348 chip->bms_notify.is_charging = new_is_charging;
1349 schedule_work(&(chip->bms_notify.work));
1350 }
1351}
1352
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001353static enum power_supply_property pm_power_props_usb[] = {
1354 POWER_SUPPLY_PROP_PRESENT,
1355 POWER_SUPPLY_PROP_ONLINE,
1356 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001357 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001358 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001359};
1360
1361static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001363 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364};
1365
1366static char *pm_power_supplied_to[] = {
1367 "battery",
1368};
1369
David Keitel6ed71a52012-01-30 12:42:18 -08001370#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001371static int pm_power_get_property_mains(struct power_supply *psy,
1372 enum power_supply_property psp,
1373 union power_supply_propval *val)
1374{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001375 int type;
1376
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001377 /* Check if called before init */
1378 if (!the_chip)
1379 return -EINVAL;
1380
1381 switch (psp) {
1382 case POWER_SUPPLY_PROP_PRESENT:
1383 case POWER_SUPPLY_PROP_ONLINE:
1384 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001385
1386 if (the_chip->has_dc_supply) {
1387 val->intval = 1;
1388 return 0;
1389 }
1390
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001391 if (the_chip->dc_present) {
1392 val->intval = 1;
1393 return 0;
1394 }
1395
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301396 type = the_chip->usb_type;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001397 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1398 type == POWER_SUPPLY_TYPE_USB_ACA ||
1399 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001400 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001401
1402 break;
1403 default:
1404 return -EINVAL;
1405 }
1406 return 0;
1407}
1408
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001409static int disable_aicl(int disable)
1410{
1411 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1412 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1413 pr_err("called with invalid param :%d\n", disable);
1414 return -EINVAL;
1415 }
1416
1417 if (!the_chip) {
1418 pr_err("%s called before init\n", __func__);
1419 return -EINVAL;
1420 }
1421
1422 pr_debug("Disable AICL = %d\n", disable);
1423 the_chip->disable_aicl = disable;
1424 return 0;
1425}
1426
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001427static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1428{
1429 int rc;
1430
1431 if (!chip->host_mode)
1432 return 0;
1433
1434 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001435 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001436 if (rc < 0) {
1437 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1438 return rc;
1439 }
1440
1441 chip->host_mode = 0;
1442
1443 return 0;
1444}
1445
1446static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1447{
1448 int rc;
1449
1450 if (chip->host_mode)
1451 return 0;
1452
1453 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001454 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001455 if (rc < 0) {
1456 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1457 return rc;
1458 }
1459
1460 chip->host_mode = 1;
1461
1462 return 0;
1463}
1464
1465static int pm_power_set_property_usb(struct power_supply *psy,
1466 enum power_supply_property psp,
1467 const union power_supply_propval *val)
1468{
1469 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001470 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001471 return -EINVAL;
1472
1473 switch (psp) {
1474 case POWER_SUPPLY_PROP_SCOPE:
1475 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001476 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001477 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001478 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001479 else
1480 return -EINVAL;
1481 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001482 case POWER_SUPPLY_PROP_TYPE:
1483 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001484 case POWER_SUPPLY_PROP_HEALTH:
1485 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1486 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001487 default:
1488 return -EINVAL;
1489 }
1490 return 0;
1491}
1492
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001493static int usb_property_is_writeable(struct power_supply *psy,
1494 enum power_supply_property psp)
1495{
1496 switch (psp) {
1497 case POWER_SUPPLY_PROP_HEALTH:
1498 return 1;
1499 default:
1500 break;
1501 }
1502
1503 return 0;
1504}
1505
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001506static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 enum power_supply_property psp,
1508 union power_supply_propval *val)
1509{
David Keitel6ed71a52012-01-30 12:42:18 -08001510 int current_max;
1511
1512 /* Check if called before init */
1513 if (!the_chip)
1514 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515
1516 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001517 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001518 if (pm_is_chg_charge_dis(the_chip)) {
1519 val->intval = 0;
1520 } else {
1521 pm_chg_iusbmax_get(the_chip, &current_max);
1522 val->intval = current_max;
1523 }
David Keitel6ed71a52012-01-30 12:42:18 -08001524 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001526 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001527 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001528
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301529 if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001530 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001533
1534 case POWER_SUPPLY_PROP_SCOPE:
1535 if (the_chip->host_mode)
1536 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1537 else
1538 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1539 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001540 case POWER_SUPPLY_PROP_HEALTH:
1541 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1542 val->intval = the_chip->disable_aicl;
1543 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 default:
1545 return -EINVAL;
1546 }
1547 return 0;
1548}
1549
1550static enum power_supply_property msm_batt_power_props[] = {
1551 POWER_SUPPLY_PROP_STATUS,
1552 POWER_SUPPLY_PROP_CHARGE_TYPE,
1553 POWER_SUPPLY_PROP_HEALTH,
1554 POWER_SUPPLY_PROP_PRESENT,
1555 POWER_SUPPLY_PROP_TECHNOLOGY,
1556 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1557 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1558 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1559 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001560 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001561 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001562 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001563 POWER_SUPPLY_PROP_CHARGE_FULL,
1564 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565};
1566
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001567static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568{
1569 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001570 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001572 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 if (rc) {
1574 pr_err("error reading adc channel = %d, rc = %d\n",
1575 chip->vbat_channel, rc);
1576 return rc;
1577 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001578 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 result.measurement);
1580 return (int)result.physical;
1581}
1582
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301583static int voltage_based_capacity(struct pm8921_chg_chip *chip)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001584{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301585 int current_voltage_uv = get_prop_battery_uvolts(chip);
1586 int current_voltage_mv = current_voltage_uv / 1000;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001587 unsigned int low_voltage = chip->min_voltage_mv;
1588 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001589
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301590 if (current_voltage_uv < 0) {
1591 pr_err("Error reading current voltage\n");
1592 return -EIO;
1593 }
1594
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001595 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001596 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001597 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001598 return 100;
1599 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001600 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001601 / (high_voltage - low_voltage);
1602}
1603
David Keitel4f9397b2012-04-16 11:46:16 -07001604static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1605{
1606 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1607}
1608
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001609static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1610{
1611 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1612 int fsm_state = pm_chg_get_fsm_state(chip);
1613 int i;
1614
1615 if (chip->ext_psy) {
1616 if (chip->ext_charge_done)
1617 return POWER_SUPPLY_STATUS_FULL;
1618 if (chip->ext_charging)
1619 return POWER_SUPPLY_STATUS_CHARGING;
1620 }
1621
1622 for (i = 0; i < ARRAY_SIZE(map); i++)
1623 if (map[i].fsm_state == fsm_state)
1624 batt_state = map[i].batt_state;
1625
1626 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1627 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1628 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1629 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1630 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1631
1632 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1633 }
1634 return batt_state;
1635}
1636
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1638{
David Keitel4f9397b2012-04-16 11:46:16 -07001639 int percent_soc;
1640
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001641 if (chip->battery_less_hardware)
1642 return 100;
1643
David Keitel4f9397b2012-04-16 11:46:16 -07001644 if (!get_prop_batt_present(chip))
1645 percent_soc = voltage_based_capacity(chip);
1646 else
1647 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001648
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001649 if (percent_soc == -ENXIO)
1650 percent_soc = voltage_based_capacity(chip);
1651
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301652 if (percent_soc < 0) {
1653 pr_err("Unable to read battery voltage\n");
1654 goto fail_voltage;
1655 }
1656
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001657 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001658 pr_warn_ratelimited("low battery charge = %d%%\n",
1659 percent_soc);
1660
1661 if (percent_soc <= chip->resume_charge_percent
1662 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1663 pr_debug("soc fell below %d. charging enabled.\n",
1664 chip->resume_charge_percent);
1665 if (chip->is_bat_warm)
1666 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1667 chip->is_bat_warm,
1668 chip->resume_charge_percent);
1669 else if (chip->is_bat_cool)
1670 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1671 chip->is_bat_cool,
1672 chip->resume_charge_percent);
1673 else
1674 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1675 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001676
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301677fail_voltage:
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001678 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001679 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680}
1681
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301682static int get_prop_batt_current_max(struct pm8921_chg_chip *chip, int *curr)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001683{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301684 *curr = 0;
1685 *curr = pm8921_bms_get_current_max();
1686 if (*curr == -EINVAL)
1687 return -EINVAL;
1688
1689 return 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001690}
1691
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301692static int get_prop_batt_current(struct pm8921_chg_chip *chip, int *curr)
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001693{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301694 int rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001695
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301696 *curr = 0;
1697 rc = pm8921_bms_get_battery_current(curr);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001698 if (rc == -ENXIO) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301699 rc = pm8xxx_ccadc_get_battery_current(curr);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001700 }
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301701 if (rc)
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001702 pr_err("unable to get batt current rc = %d\n", rc);
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301703
1704 return rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001705}
1706
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001707static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1708{
1709 int rc;
1710
1711 rc = pm8921_bms_get_fcc();
1712 if (rc < 0)
1713 pr_err("unable to get batt fcc rc = %d\n", rc);
1714 return rc;
1715}
1716
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301717static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip, int *cc_uah)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001718{
1719 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001720
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301721 *cc_uah = 0;
1722 rc = pm8921_bms_cc_uah(cc_uah);
1723 if (rc)
1724 pr_err("unable to get batt fcc rc = %d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001725
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001726 return rc;
1727}
1728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1730{
1731 int temp;
1732
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001733 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1734 if (temp)
1735 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001737 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1738 if (temp)
1739 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001741 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742}
1743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1745{
1746 int temp;
1747
Amir Samuelovd31ef502011-10-26 14:41:36 +02001748 if (!get_prop_batt_present(chip))
1749 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1750
1751 if (is_ext_trickle_charging(chip))
1752 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1753
1754 if (is_ext_charging(chip))
1755 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1758 if (temp)
1759 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1760
1761 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1762 if (temp)
1763 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1764
1765 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1766}
1767
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001768#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301769static int get_prop_batt_temp(struct pm8921_chg_chip *chip, int *temp)
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001770{
1771 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001772 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001773
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301774 if (chip->battery_less_hardware) {
1775 *temp = 300;
1776 return 0;
1777 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001778
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001779 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001780 if (rc) {
1781 pr_err("error reading adc channel = %d, rc = %d\n",
1782 chip->vbat_channel, rc);
1783 return rc;
1784 }
1785 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1786 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001787 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1788 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1789 (int) result.physical);
1790
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301791 *temp = (int)result.physical;
1792
1793 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001794}
1795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796static int pm_batt_power_get_property(struct power_supply *psy,
1797 enum power_supply_property psp,
1798 union power_supply_propval *val)
1799{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301800 int rc = 0;
1801 int value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1803 batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 switch (psp) {
1805 case POWER_SUPPLY_PROP_STATUS:
1806 val->intval = get_prop_batt_status(chip);
1807 break;
1808 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1809 val->intval = get_prop_charge_type(chip);
1810 break;
1811 case POWER_SUPPLY_PROP_HEALTH:
1812 val->intval = get_prop_batt_health(chip);
1813 break;
1814 case POWER_SUPPLY_PROP_PRESENT:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301815 rc = get_prop_batt_present(chip);
1816 if (rc >= 0) {
1817 val->intval = rc;
1818 rc = 0;
1819 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001820 break;
1821 case POWER_SUPPLY_PROP_TECHNOLOGY:
1822 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1823 break;
1824 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001825 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826 break;
1827 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001828 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 break;
1830 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301831 rc = get_prop_battery_uvolts(chip);
1832 if (rc >= 0) {
1833 val->intval = rc;
1834 rc = 0;
1835 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836 break;
1837 case POWER_SUPPLY_PROP_CAPACITY:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301838 rc = get_prop_batt_capacity(chip);
1839 if (rc >= 0) {
1840 val->intval = rc;
1841 rc = 0;
1842 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001844 case POWER_SUPPLY_PROP_CURRENT_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301845 rc = get_prop_batt_current(chip, &value);
1846 if (!rc)
1847 val->intval = value;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001848 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001849 case POWER_SUPPLY_PROP_CURRENT_MAX:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301850 rc = get_prop_batt_current_max(chip, &value);
1851 if (!rc)
1852 val->intval = value;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001853 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001854 case POWER_SUPPLY_PROP_TEMP:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301855 rc = get_prop_batt_temp(chip, &value);
1856 if (!rc)
1857 val->intval = value;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001858 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001859 case POWER_SUPPLY_PROP_CHARGE_FULL:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301860 rc = get_prop_batt_fcc(chip);
1861 if (rc >= 0) {
1862 val->intval = rc;
1863 rc = 0;
1864 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001865 break;
1866 case POWER_SUPPLY_PROP_CHARGE_NOW:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301867 rc = get_prop_batt_charge_now(chip, &value);
1868 if (!rc) {
1869 val->intval = value;
1870 rc = 0;
1871 }
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001872 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 default:
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301874 rc = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 }
1876
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05301877 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878}
1879
1880static void (*notify_vbus_state_func_ptr)(int);
1881static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882
1883int pm8921_charger_register_vbus_sn(void (*callback)(int))
1884{
1885 pr_debug("%p\n", callback);
1886 notify_vbus_state_func_ptr = callback;
1887 return 0;
1888}
1889EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1890
1891/* this is passed to the hsusb via platform_data msm_otg_pdata */
1892void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1893{
1894 pr_debug("%p\n", callback);
1895 notify_vbus_state_func_ptr = NULL;
1896}
1897EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1898
1899static void notify_usb_of_the_plugin_event(int plugin)
1900{
1901 plugin = !!plugin;
1902 if (notify_vbus_state_func_ptr) {
1903 pr_debug("notifying plugin\n");
1904 (*notify_vbus_state_func_ptr) (plugin);
1905 } else {
1906 pr_debug("unable to notify plugin\n");
1907 }
1908}
1909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910static void __pm8921_charger_vbus_draw(unsigned int mA)
1911{
1912 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001913 if (!the_chip) {
1914 pr_err("called before init\n");
1915 return;
1916 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001918 if (usb_max_current && mA > usb_max_current) {
1919 pr_debug("restricting usb current to %d instead of %d\n",
1920 usb_max_current, mA);
1921 mA = usb_max_current;
1922 }
1923
1924 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001926 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001928 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929 }
1930 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1931 if (rc)
1932 pr_err("fail to set suspend bit rc=%d\n", rc);
1933 } else {
1934 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1935 if (rc)
1936 pr_err("fail to reset suspend bit rc=%d\n", rc);
1937 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1938 if (usb_ma_table[i].usb_ma <= mA)
1939 break;
1940 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001941
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001942 if (i < 0) {
1943 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1944 mA);
1945 i = 0;
1946 }
1947
David Keitel38bdd4f2012-04-19 15:39:13 -07001948 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001949 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001950 && !the_chip->iusb_fine_res)
1951 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952 if (i < 0)
1953 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001954 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001955 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001956 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 }
1958}
1959
1960/* USB calls these to tell us how much max usb current the system can draw */
1961void pm8921_charger_vbus_draw(unsigned int mA)
1962{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001963 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001964
1965 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001966
David Keitel62c6a4b2012-05-17 12:54:59 -07001967 /*
1968 * Reject VBUS requests if USB connection is the only available
1969 * power source. This makes sure that if booting without
1970 * battery the iusb_max value is not decreased avoiding potential
1971 * brown_outs.
1972 *
1973 * This would also apply when the battery has been
1974 * removed from the running system.
1975 */
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001976 if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07001977 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001978 if (!the_chip->has_dc_supply) {
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001979 pr_err("rejected: no other power source mA = %d\n", mA);
David Keitelff4f9ce2012-08-24 15:11:23 -07001980 return;
1981 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001982 }
1983
David Keitelacf57c82012-03-07 18:48:50 -08001984 if (usb_max_current && mA > usb_max_current) {
1985 pr_warn("restricting usb current to %d instead of %d\n",
1986 usb_max_current, mA);
1987 mA = usb_max_current;
1988 }
Devin Kim2073afb2012-09-05 13:01:51 -07001989 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1990 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001991
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301992 if (usb_target_ma)
1993 usb_target_ma = mA;
1994
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001995
1996 if (mA > USB_WALL_THRESHOLD_MA)
1997 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
1998 else
1999 set_usb_now_ma = mA;
2000
2001 if (the_chip && the_chip->disable_aicl)
2002 set_usb_now_ma = mA;
2003
2004 if (the_chip)
2005 __pm8921_charger_vbus_draw(set_usb_now_ma);
2006 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 /*
2008 * called before pmic initialized,
2009 * save this value and use it at probe
2010 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002011 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012}
2013EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
2014
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002015int pm8921_is_usb_chg_plugged_in(void)
2016{
2017 if (!the_chip) {
2018 pr_err("called before init\n");
2019 return -EINVAL;
2020 }
2021 return is_usb_chg_plugged_in(the_chip);
2022}
2023EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
2024
2025int pm8921_is_dc_chg_plugged_in(void)
2026{
2027 if (!the_chip) {
2028 pr_err("called before init\n");
2029 return -EINVAL;
2030 }
2031 return is_dc_chg_plugged_in(the_chip);
2032}
2033EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
2034
2035int pm8921_is_battery_present(void)
2036{
2037 if (!the_chip) {
2038 pr_err("called before init\n");
2039 return -EINVAL;
2040 }
2041 return get_prop_batt_present(the_chip);
2042}
2043EXPORT_SYMBOL(pm8921_is_battery_present);
2044
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002045int pm8921_is_batfet_closed(void)
2046{
2047 if (!the_chip) {
2048 pr_err("called before init\n");
2049 return -EINVAL;
2050 }
2051 return is_batfet_closed(the_chip);
2052}
2053EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002054/*
2055 * Disabling the charge current limit causes current
2056 * current limits to have no monitoring. An adequate charger
2057 * capable of supplying high current while sustaining VIN_MIN
2058 * is required if the limiting is disabled.
2059 */
2060int pm8921_disable_input_current_limit(bool disable)
2061{
2062 if (!the_chip) {
2063 pr_err("called before init\n");
2064 return -EINVAL;
2065 }
2066 if (disable) {
2067 pr_warn("Disabling input current limit!\n");
2068
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002069 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002070 }
2071 return 0;
2072}
2073EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2074
David Keitel0789fc62012-06-07 17:43:27 -07002075int pm8917_set_under_voltage_detection_threshold(int mv)
2076{
2077 if (!the_chip) {
2078 pr_err("called before init\n");
2079 return -EINVAL;
2080 }
2081 return pm_chg_uvd_threshold_set(the_chip, mv);
2082}
2083EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2084
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002085int pm8921_set_max_battery_charge_current(int ma)
2086{
2087 if (!the_chip) {
2088 pr_err("called before init\n");
2089 return -EINVAL;
2090 }
2091 return pm_chg_ibatmax_set(the_chip, ma);
2092}
2093EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2094
2095int pm8921_disable_source_current(bool disable)
2096{
2097 if (!the_chip) {
2098 pr_err("called before init\n");
2099 return -EINVAL;
2100 }
2101 if (disable)
2102 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002103
2104 pm_chg_usb_suspend_enable(the_chip, disable);
2105
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002106 return pm_chg_charge_dis(the_chip, disable);
2107}
2108EXPORT_SYMBOL(pm8921_disable_source_current);
2109
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002110int pm8921_regulate_input_voltage(int voltage)
2111{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002112 int rc;
2113
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002114 if (!the_chip) {
2115 pr_err("called before init\n");
2116 return -EINVAL;
2117 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002118 rc = pm_chg_vinmin_set(the_chip, voltage);
2119
2120 if (rc == 0)
2121 the_chip->vin_min = voltage;
2122
2123 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002124}
2125
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002126#define USB_OV_THRESHOLD_MASK 0x60
2127#define USB_OV_THRESHOLD_SHIFT 5
2128int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2129{
2130 u8 temp;
2131
2132 if (!the_chip) {
2133 pr_err("called before init\n");
2134 return -EINVAL;
2135 }
2136
2137 if (ov > PM_USB_OV_7V) {
2138 pr_err("limiting to over voltage threshold to 7volts\n");
2139 ov = PM_USB_OV_7V;
2140 }
2141
2142 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2143
2144 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2145 USB_OV_THRESHOLD_MASK, temp);
2146}
2147EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2148
2149#define USB_DEBOUNCE_TIME_MASK 0x06
2150#define USB_DEBOUNCE_TIME_SHIFT 1
2151int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2152{
2153 u8 temp;
2154
2155 if (!the_chip) {
2156 pr_err("called before init\n");
2157 return -EINVAL;
2158 }
2159
2160 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2161 pr_err("limiting debounce to 80.5ms\n");
2162 ms = PM_USB_DEBOUNCE_80P5MS;
2163 }
2164
2165 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2166
2167 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2168 USB_DEBOUNCE_TIME_MASK, temp);
2169}
2170EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2171
2172#define USB_OVP_DISABLE_MASK 0x80
2173int pm8921_usb_ovp_disable(int disable)
2174{
2175 u8 temp = 0;
2176
2177 if (!the_chip) {
2178 pr_err("called before init\n");
2179 return -EINVAL;
2180 }
2181
2182 if (disable)
2183 temp = USB_OVP_DISABLE_MASK;
2184
2185 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2186 USB_OVP_DISABLE_MASK, temp);
2187}
2188
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002189bool pm8921_is_battery_charging(int *source)
2190{
2191 int fsm_state, is_charging, dc_present, usb_present;
2192
2193 if (!the_chip) {
2194 pr_err("called before init\n");
2195 return -EINVAL;
2196 }
2197 fsm_state = pm_chg_get_fsm_state(the_chip);
2198 is_charging = is_battery_charging(fsm_state);
2199 if (is_charging == 0) {
2200 *source = PM8921_CHG_SRC_NONE;
2201 return is_charging;
2202 }
2203
2204 if (source == NULL)
2205 return is_charging;
2206
2207 /* the battery is charging, the source is requested, find it */
2208 dc_present = is_dc_chg_plugged_in(the_chip);
2209 usb_present = is_usb_chg_plugged_in(the_chip);
2210
2211 if (dc_present && !usb_present)
2212 *source = PM8921_CHG_SRC_DC;
2213
2214 if (usb_present && !dc_present)
2215 *source = PM8921_CHG_SRC_USB;
2216
2217 if (usb_present && dc_present)
2218 /*
2219 * The system always chooses dc for charging since it has
2220 * higher priority.
2221 */
2222 *source = PM8921_CHG_SRC_DC;
2223
2224 return is_charging;
2225}
2226EXPORT_SYMBOL(pm8921_is_battery_charging);
2227
David Keitel86034022012-04-18 12:33:58 -07002228int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2229{
2230 if (!the_chip) {
2231 pr_err("called before init\n");
2232 return -EINVAL;
2233 }
2234
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002235 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002236 return -EINVAL;
2237
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05302238 the_chip->usb_type = type;
David Keitel86034022012-04-18 12:33:58 -07002239 power_supply_changed(&the_chip->usb_psy);
2240 power_supply_changed(&the_chip->dc_psy);
2241 return 0;
2242}
2243EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2244
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002245int pm8921_batt_temperature(void)
2246{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302247 int temp = 0, rc = 0;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002248 if (!the_chip) {
2249 pr_err("called before init\n");
2250 return -EINVAL;
2251 }
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302252 rc = get_prop_batt_temp(the_chip, &temp);
2253 if (rc) {
2254 pr_err("Unable to read temperature");
2255 return rc;
2256 }
2257 return temp;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002258}
2259
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2261{
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08002262 int usb_present;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002264 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 usb_present = is_usb_chg_plugged_in(chip);
2266 if (chip->usb_present ^ usb_present) {
2267 notify_usb_of_the_plugin_event(usb_present);
2268 chip->usb_present = usb_present;
2269 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002270 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002271 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002273 if (usb_present) {
2274 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002275 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002276 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2277 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002278 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002279 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002280 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002281 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002282 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283}
2284
Amir Samuelovd31ef502011-10-26 14:41:36 +02002285static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2286{
David Keitel88e1b572012-01-11 11:57:14 -08002287 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002288 pr_debug("external charger not registered.\n");
2289 return;
2290 }
2291
2292 if (!chip->ext_charging) {
2293 pr_debug("already not charging.\n");
2294 return;
2295 }
2296
David Keitel88e1b572012-01-11 11:57:14 -08002297 power_supply_set_charge_type(chip->ext_psy,
2298 POWER_SUPPLY_CHARGE_TYPE_NONE);
2299 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002300 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002301 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002302 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002303 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002304 /* Update battery charging LEDs and user space battery info */
2305 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002306}
2307
2308static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2309{
2310 int dc_present;
2311 int batt_present;
2312 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002313 unsigned long delay =
2314 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2315
David Keitel88e1b572012-01-11 11:57:14 -08002316 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002317 pr_debug("external charger not registered.\n");
2318 return;
2319 }
2320
2321 if (chip->ext_charging) {
2322 pr_debug("already charging.\n");
2323 return;
2324 }
2325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002326 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002327 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2328 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002329
2330 if (!dc_present) {
2331 pr_warn("%s. dc not present.\n", __func__);
2332 return;
2333 }
2334 if (!batt_present) {
2335 pr_warn("%s. battery not present.\n", __func__);
2336 return;
2337 }
2338 if (!batt_temp_ok) {
2339 pr_warn("%s. battery temperature not ok.\n", __func__);
2340 return;
2341 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002342
2343 /* Force BATFET=ON */
2344 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002345
David Keitel6ccbf132012-05-30 14:21:24 -07002346 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002347 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002348
David Keitel63f71662012-02-08 20:30:00 -08002349 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002350 power_supply_set_charge_type(chip->ext_psy,
2351 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002352 chip->ext_charging = true;
2353 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002354 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002355 /*
2356 * since we wont get a fastchg irq from external charger
2357 * use eoc worker to detect end of charging
2358 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002359 schedule_delayed_work(&chip->eoc_work, delay);
2360 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002361 if (chip->btc_override)
2362 schedule_delayed_work(&chip->btc_override_work,
2363 round_jiffies_relative(msecs_to_jiffies
2364 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002365 /* Update battery charging LEDs and user space battery info */
2366 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002367}
2368
David Keitel6ccbf132012-05-30 14:21:24 -07002369static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002370{
2371 u8 temp;
2372 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002373
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002374 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002375 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002376 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002377 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002378 }
David Keitel6ccbf132012-05-30 14:21:24 -07002379 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002380 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002381 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002382 return;
2383 }
2384 /* set ovp fet disable bit and the write bit */
2385 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002386 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002387 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002388 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002389 return;
2390 }
2391}
2392
David Keitel6ccbf132012-05-30 14:21:24 -07002393static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002394{
2395 u8 temp;
2396 int rc;
2397
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002398 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002399 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002400 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002401 return;
2402 }
David Keitel6ccbf132012-05-30 14:21:24 -07002403 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002404 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002405 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002406 return;
2407 }
2408 /* unset ovp fet disable bit and set the write bit */
2409 temp &= 0xFE;
2410 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002411 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002412 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002413 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002414 temp, rc);
2415 return;
2416 }
2417}
2418
2419static int param_open_ovp_counter = 10;
2420module_param(param_open_ovp_counter, int, 0644);
2421
David Keitel6ccbf132012-05-30 14:21:24 -07002422#define USB_ACTIVE_BIT BIT(5)
2423#define DC_ACTIVE_BIT BIT(6)
2424static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2425 u8 active_chg_mask)
2426{
2427 if (active_chg_mask & USB_ACTIVE_BIT)
2428 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2429 else if (active_chg_mask & DC_ACTIVE_BIT)
2430 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2431 else
2432 return 0;
2433}
2434
David Keitel8c5201a2012-02-24 16:08:54 -08002435#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002436#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002437static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002438{
David Keitel6ccbf132012-05-30 14:21:24 -07002439 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002440 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002441 u8 active_mask = 0;
2442 u16 ovpreg, ovptestreg;
2443
2444 if (is_usb_chg_plugged_in(chip) &&
2445 (chip->active_path & USB_ACTIVE_BIT)) {
2446 ovpreg = USB_OVP_CONTROL;
2447 ovptestreg = USB_OVP_TEST;
2448 active_mask = USB_ACTIVE_BIT;
2449 } else if (is_dc_chg_plugged_in(chip) &&
2450 (chip->active_path & DC_ACTIVE_BIT)) {
2451 ovpreg = DC_OVP_CONTROL;
2452 ovptestreg = DC_OVP_TEST;
2453 active_mask = DC_ACTIVE_BIT;
2454 } else {
2455 return;
2456 }
David Keitel8c5201a2012-02-24 16:08:54 -08002457
2458 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002459 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002460 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002461 active_chg_plugged_in
2462 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002463 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002464 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2465 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002466
2467 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002468 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002469 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002470 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002471
2472 msleep(20);
2473
David Keitel6ccbf132012-05-30 14:21:24 -07002474 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002475 } else {
David Keitel712782e2012-03-29 14:11:47 -07002476 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002477 }
2478 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002479 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2480 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2481 else
2482 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2483
David Keitel6ccbf132012-05-30 14:21:24 -07002484 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2485 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002486 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002487}
David Keitelacf57c82012-03-07 18:48:50 -08002488
2489static int find_usb_ma_value(int value)
2490{
2491 int i;
2492
2493 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2494 if (value >= usb_ma_table[i].usb_ma)
2495 break;
2496 }
2497
2498 return i;
2499}
2500
2501static void decrease_usb_ma_value(int *value)
2502{
2503 int i;
2504
2505 if (value) {
2506 i = find_usb_ma_value(*value);
2507 if (i > 0)
2508 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002509 while (!the_chip->iusb_fine_res && i > 0
2510 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2511 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002512
2513 if (i < 0) {
2514 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2515 *value);
2516 i = 0;
2517 }
2518
David Keitelacf57c82012-03-07 18:48:50 -08002519 *value = usb_ma_table[i].usb_ma;
2520 }
2521}
2522
2523static void increase_usb_ma_value(int *value)
2524{
2525 int i;
2526
2527 if (value) {
2528 i = find_usb_ma_value(*value);
2529
2530 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2531 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002532 /* Get next correct entry if IUSB_FINE_RES is not available */
2533 while (!the_chip->iusb_fine_res
2534 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2535 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2536 i++;
2537
David Keitelacf57c82012-03-07 18:48:50 -08002538 *value = usb_ma_table[i].usb_ma;
2539 }
2540}
2541
2542static void vin_collapse_check_worker(struct work_struct *work)
2543{
2544 struct delayed_work *dwork = to_delayed_work(work);
2545 struct pm8921_chg_chip *chip = container_of(dwork,
2546 struct pm8921_chg_chip, vin_collapse_check_work);
2547
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002548 /*
2549 * AICL only for wall-chargers. If the charger appears to be plugged
2550 * back in now, the corresponding unplug must have been because of we
2551 * were trying to draw more current than the charger can support. In
2552 * such a case reset usb current to 500mA and decrease the target.
2553 * The AICL algorithm will step up the current from 500mA to target
2554 */
2555 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002556 && usb_target_ma > USB_WALL_THRESHOLD_MA
2557 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002558 /* decrease usb_target_ma */
2559 decrease_usb_ma_value(&usb_target_ma);
2560 /* reset here, increase in unplug_check_worker */
2561 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2562 pr_debug("usb_now=%d, usb_target = %d\n",
2563 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002564 if (!delayed_work_pending(&chip->unplug_check_work))
2565 schedule_delayed_work(&chip->unplug_check_work,
2566 msecs_to_jiffies
2567 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002568 } else {
2569 handle_usb_insertion_removal(chip);
2570 }
2571}
2572
2573#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2575{
David Keitelacf57c82012-03-07 18:48:50 -08002576 if (usb_target_ma)
2577 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2578 round_jiffies_relative(msecs_to_jiffies
2579 (VIN_MIN_COLLAPSE_CHECK_MS)));
2580 else
2581 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002582 return IRQ_HANDLED;
2583}
2584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2586{
2587 struct pm8921_chg_chip *chip = data;
2588 int status;
2589
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002590 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2591 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002592 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 pr_debug("battery present=%d", status);
2594 power_supply_changed(&chip->batt_psy);
2595 return IRQ_HANDLED;
2596}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002597
2598/*
2599 * this interrupt used to restart charging a battery.
2600 *
2601 * Note: When DC-inserted the VBAT can't go low.
2602 * VPH_PWR is provided by the ext-charger.
2603 * After End-Of-Charging from DC, charging can be resumed only
2604 * if DC is removed and then inserted after the battery was in use.
2605 * Therefore the handle_start_ext_chg() is not called.
2606 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2608{
2609 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002610 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002612 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002613
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002614 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002615 /* enable auto charging */
2616 pm_chg_auto_enable(chip, !charging_disabled);
2617 pr_info("batt fell below resume voltage %s\n",
2618 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 power_supply_changed(&chip->batt_psy);
2623 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002624 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002626 return IRQ_HANDLED;
2627}
2628
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2630{
2631 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2632 return IRQ_HANDLED;
2633}
2634
2635static irqreturn_t vcp_irq_handler(int irq, void *data)
2636{
David Keitel8c5201a2012-02-24 16:08:54 -08002637 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002638 return IRQ_HANDLED;
2639}
2640
2641static irqreturn_t atcdone_irq_handler(int irq, void *data)
2642{
2643 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2644 return IRQ_HANDLED;
2645}
2646
2647static irqreturn_t atcfail_irq_handler(int irq, void *data)
2648{
2649 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2650 return IRQ_HANDLED;
2651}
2652
2653static irqreturn_t chgdone_irq_handler(int irq, void *data)
2654{
2655 struct pm8921_chg_chip *chip = data;
2656
2657 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002658
2659 handle_stop_ext_chg(chip);
2660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 power_supply_changed(&chip->batt_psy);
2662 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002663 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002664
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002665 bms_notify_check(chip);
2666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 return IRQ_HANDLED;
2668}
2669
2670static irqreturn_t chgfail_irq_handler(int irq, void *data)
2671{
2672 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002673 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002675 if (!chip->stop_chg_upon_expiry) {
2676 ret = pm_chg_failed_clear(chip, 1);
2677 if (ret)
2678 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2679 }
David Keitel753ec8d2011-11-02 10:56:37 -07002680
2681 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2682 get_prop_batt_present(chip),
2683 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2684 pm_chg_get_fsm_state(data));
2685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686 power_supply_changed(&chip->batt_psy);
2687 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002688 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689 return IRQ_HANDLED;
2690}
2691
2692static irqreturn_t chgstate_irq_handler(int irq, void *data)
2693{
2694 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002695
2696 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2697 power_supply_changed(&chip->batt_psy);
2698 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002699 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002701 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002703 return IRQ_HANDLED;
2704}
2705
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002706enum {
2707 PON_TIME_25NS = 0x04,
2708 PON_TIME_50NS = 0x08,
2709 PON_TIME_100NS = 0x0C,
2710};
David Keitel8c5201a2012-02-24 16:08:54 -08002711
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002712static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002713{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002714 u8 temp;
2715 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002716
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002717 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2718 if (rc) {
2719 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2720 return;
2721 }
2722 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2723 if (rc) {
2724 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2725 return;
2726 }
2727 /* clear the min pon time select bit */
2728 temp &= 0xF3;
2729 /* set the pon time */
2730 temp |= (u8)pon_time_ns;
2731 /* write enable bank 4 */
2732 temp |= 0x80;
2733 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2734 if (rc) {
2735 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2736 return;
2737 }
2738}
David Keitel8c5201a2012-02-24 16:08:54 -08002739
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002740static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2741{
2742 pr_debug("Start\n");
2743 set_min_pon_time(chip, PON_TIME_100NS);
2744 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2745 msleep(250);
2746 pm_chg_vinmin_set(chip, chip->vin_min);
2747 set_min_pon_time(chip, PON_TIME_25NS);
2748 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002749}
2750
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002751#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002752#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2753#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002754static void unplug_check_worker(struct work_struct *work)
2755{
2756 struct delayed_work *dwork = to_delayed_work(work);
2757 struct pm8921_chg_chip *chip = container_of(dwork,
2758 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002759 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002760 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002761 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002762 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002763
2764 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2765 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002766 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2767 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002768 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002769
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002770 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002771 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002772 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2773 active_path, active_chg_plugged_in);
2774 if (active_path & USB_ACTIVE_BIT) {
2775 pr_debug("USB charger active\n");
2776
2777 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002778
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002779 if (usb_ma <= 100) {
2780 pr_debug(
2781 "Unenumerated or suspended usb_ma = %d skip\n",
2782 usb_ma);
2783 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002784 }
2785 } else if (active_path & DC_ACTIVE_BIT) {
2786 pr_debug("DC charger active\n");
2787 } else {
2788 /* No charger active */
2789 if (!(is_usb_chg_plugged_in(chip)
2790 && !(is_dc_chg_plugged_in(chip)))) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302791 get_prop_batt_current(chip, &ibat);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002792 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002793 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2794 pm_chg_get_regulation_loop(chip),
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302795 pm_chg_get_fsm_state(chip), ibat);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002796 return;
2797 } else {
2798 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002799 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002800 }
David Keitel8c5201a2012-02-24 16:08:54 -08002801
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002802 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002803 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
2804 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07002805 reg_loop = pm_chg_get_regulation_loop(chip);
2806 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2807 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002808 (usb_ma > USB_WALL_THRESHOLD_MA)
2809 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002810 decrease_usb_ma_value(&usb_ma);
2811 usb_target_ma = usb_ma;
2812 /* end AICL here */
2813 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002814 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002815 usb_ma, usb_target_ma);
2816 }
David Keitelacf57c82012-03-07 18:48:50 -08002817 }
2818
2819 reg_loop = pm_chg_get_regulation_loop(chip);
2820 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2821
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302822 rc = get_prop_batt_current(chip, &ibat);
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302823 if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) {
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05302824 if (ibat > 0 && !rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002825 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2826 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2827 attempt_reverse_boost_fix(chip);
2828 /* after reverse boost fix check if the active
2829 * charger was detected as removed */
2830 active_chg_plugged_in
2831 = is_active_chg_plugged_in(chip,
2832 active_path);
2833 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2834 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002835 }
2836 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002837
2838 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002839 pr_debug("active_path = 0x%x, active_chg = %d\n",
2840 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002841 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2842
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302843 if (chg_gone == 1 && active_chg_plugged_in == 1 &&
2844 !chip->disable_chg_rmvl_wrkarnd) {
David Keitel6ccbf132012-05-30 14:21:24 -07002845 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2846 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002847 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002848 }
2849
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002850 /* AICL only for usb wall charger */
2851 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2852 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002853 && !charging_disabled
2854 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002855 /* only increase iusb_max if vin loop not active */
2856 if (usb_ma < usb_target_ma) {
2857 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302858 if (usb_ma > usb_target_ma)
2859 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002860 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002861 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002862 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002863 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002864 } else {
2865 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002866 }
2867 }
Devin Kim2073afb2012-09-05 13:01:51 -07002868check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002869 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002870 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002871 if (ramp)
2872 schedule_delayed_work(&chip->unplug_check_work,
2873 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2874 else
2875 schedule_delayed_work(&chip->unplug_check_work,
2876 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002877}
2878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879static irqreturn_t loop_change_irq_handler(int irq, void *data)
2880{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002881 struct pm8921_chg_chip *chip = data;
2882
2883 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2884 pm_chg_get_fsm_state(data),
2885 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002886 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887 return IRQ_HANDLED;
2888}
2889
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002890struct ibatmax_max_adj_entry {
2891 int ibat_max_ma;
2892 int max_adj_ma;
2893};
2894
2895static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2896 {975, 300},
2897 {1475, 150},
2898 {1975, 200},
2899 {2475, 250},
2900};
2901
2902static int find_ibat_max_adj_ma(int ibat_target_ma)
2903{
2904 int i = 0;
2905
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002906 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2907 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002908 break;
2909 }
2910
Willie Ruaneeee0aa2013-03-04 21:54:10 -08002911 if (i > 0)
2912 i--;
2913
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002914 return ibatmax_adj_table[i].max_adj_ma;
2915}
2916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917static irqreturn_t fastchg_irq_handler(int irq, void *data)
2918{
2919 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002920 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002922 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2923 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2924 wake_lock(&chip->eoc_wake_lock);
2925 schedule_delayed_work(&chip->eoc_work,
2926 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002927 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002928 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002929 if (high_transition
2930 && chip->btc_override
2931 && !delayed_work_pending(&chip->btc_override_work)) {
2932 schedule_delayed_work(&chip->btc_override_work,
2933 round_jiffies_relative(msecs_to_jiffies
2934 (chip->btc_delay_ms)));
2935 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002936 power_supply_changed(&chip->batt_psy);
2937 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938 return IRQ_HANDLED;
2939}
2940
2941static irqreturn_t trklchg_irq_handler(int irq, void *data)
2942{
2943 struct pm8921_chg_chip *chip = data;
2944
2945 power_supply_changed(&chip->batt_psy);
2946 return IRQ_HANDLED;
2947}
2948
2949static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2950{
2951 struct pm8921_chg_chip *chip = data;
2952 int status;
2953
2954 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2955 pr_debug("battery present=%d state=%d", !status,
2956 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002957 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958 power_supply_changed(&chip->batt_psy);
2959 return IRQ_HANDLED;
2960}
2961
2962static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2963{
2964 struct pm8921_chg_chip *chip = data;
2965
Amir Samuelovd31ef502011-10-26 14:41:36 +02002966 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002967 power_supply_changed(&chip->batt_psy);
2968 return IRQ_HANDLED;
2969}
2970
2971static irqreturn_t chghot_irq_handler(int irq, void *data)
2972{
2973 struct pm8921_chg_chip *chip = data;
2974
2975 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2976 power_supply_changed(&chip->batt_psy);
2977 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002978 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 return IRQ_HANDLED;
2980}
2981
2982static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2983{
2984 struct pm8921_chg_chip *chip = data;
2985
2986 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002987 handle_stop_ext_chg(chip);
2988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 power_supply_changed(&chip->batt_psy);
2990 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002991 return IRQ_HANDLED;
2992}
2993
2994static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2995{
2996 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002997 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002998
2999 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3000 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3001
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003002 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3003 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 power_supply_changed(&chip->batt_psy);
3006 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007 return IRQ_HANDLED;
3008}
David Keitel52fda532011-11-10 10:43:44 -08003009/*
3010 *
3011 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3012 * fire for two cases:
3013 *
3014 * If the interrupt line switches to high temperature is okay
3015 * and thus charging begins.
3016 * If bat_temp_ok is low this means the temperature is now
3017 * too hot or cold, so charging is stopped.
3018 *
3019 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003020static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3021{
David Keitel52fda532011-11-10 10:43:44 -08003022 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 struct pm8921_chg_chip *chip = data;
3024
David Keitel52fda532011-11-10 10:43:44 -08003025 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3026
3027 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3028 bat_temp_ok, pm_chg_get_fsm_state(data));
3029
3030 if (bat_temp_ok)
3031 handle_start_ext_chg(chip);
3032 else
3033 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035 power_supply_changed(&chip->batt_psy);
3036 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003037 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038 return IRQ_HANDLED;
3039}
3040
3041static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3042{
3043 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3044 return IRQ_HANDLED;
3045}
3046
3047static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3048{
3049 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3050 return IRQ_HANDLED;
3051}
3052
3053static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3054{
3055 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3056 return IRQ_HANDLED;
3057}
3058
3059static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3060{
3061 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3062 return IRQ_HANDLED;
3063}
3064
3065static irqreturn_t batfet_irq_handler(int irq, void *data)
3066{
3067 struct pm8921_chg_chip *chip = data;
3068
3069 pr_debug("vreg ov\n");
3070 power_supply_changed(&chip->batt_psy);
3071 return IRQ_HANDLED;
3072}
3073
3074static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3075{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003076 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003077 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003078
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003079 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003080 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003081
3082 if (chip->dc_present ^ dc_present)
3083 pm8921_bms_calibrate_hkadc();
3084
David Keitel88e1b572012-01-11 11:57:14 -08003085 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003086 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003087 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003088 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3089
3090 chip->dc_present = dc_present;
3091
3092 if (chip->ext_psy) {
3093 if (dc_present)
3094 handle_start_ext_chg(chip);
3095 else
3096 handle_stop_ext_chg(chip);
3097 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003098 if (dc_present)
3099 schedule_delayed_work(&chip->unplug_check_work,
3100 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3101 power_supply_changed(&chip->dc_psy);
3102 }
3103
3104 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 return IRQ_HANDLED;
3106}
3107
3108static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3109{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003110 struct pm8921_chg_chip *chip = data;
3111
Amir Samuelovd31ef502011-10-26 14:41:36 +02003112 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003113 return IRQ_HANDLED;
3114}
3115
3116static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3117{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003118 struct pm8921_chg_chip *chip = data;
3119
Amir Samuelovd31ef502011-10-26 14:41:36 +02003120 handle_stop_ext_chg(chip);
3121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122 return IRQ_HANDLED;
3123}
3124
David Keitel88e1b572012-01-11 11:57:14 -08003125static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3126{
3127 struct power_supply *psy = &the_chip->batt_psy;
3128 struct power_supply *epsy = dev_get_drvdata(dev);
3129 int i, dcin_irq;
3130
3131 /* Only search for external supply if none is registered */
3132 if (!the_chip->ext_psy) {
3133 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3134 for (i = 0; i < epsy->num_supplicants; i++) {
3135 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3136 if (!strncmp(epsy->name, "dc", 2)) {
3137 the_chip->ext_psy = epsy;
3138 dcin_valid_irq_handler(dcin_irq,
3139 the_chip);
3140 }
3141 }
3142 }
3143 }
3144 return 0;
3145}
3146
3147static void pm_batt_external_power_changed(struct power_supply *psy)
3148{
Anirudh Ghayal34c9b852013-03-21 15:50:34 +05303149 if (!the_chip)
3150 return;
3151
David Keitel88e1b572012-01-11 11:57:14 -08003152 /* Only look for an external supply if it hasn't been registered */
3153 if (!the_chip->ext_psy)
3154 class_for_each_device(power_supply_class, NULL, psy,
3155 __pm_batt_external_power_changed_work);
3156}
3157
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003158/**
3159 * update_heartbeat - internal function to update userspace
3160 * per update_time minutes
3161 *
3162 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003163#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003164static void update_heartbeat(struct work_struct *work)
3165{
3166 struct delayed_work *dwork = to_delayed_work(work);
3167 struct pm8921_chg_chip *chip = container_of(dwork,
3168 struct pm8921_chg_chip, update_heartbeat_work);
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303169 bool chg_present = chip->usb_present || chip->dc_present;
3170
3171 /* for battery health when charger is not connected */
3172 if (chip->btc_override && !chg_present)
3173 schedule_delayed_work(&chip->btc_override_work,
3174 round_jiffies_relative(msecs_to_jiffies
3175 (chip->btc_delay_ms)));
3176
3177 /*
3178 * check temp thresholds when charger is present and
3179 * and battery is FULL. The temperature here can impact
3180 * the charging restart conditions.
3181 */
3182 if (chip->btc_override && chg_present &&
3183 !wake_lock_active(&chip->eoc_wake_lock))
3184 check_temp_thresholds(chip);
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003185
3186 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003187 if (chip->recent_reported_soc <= 20)
3188 schedule_delayed_work(&chip->update_heartbeat_work,
3189 round_jiffies_relative(msecs_to_jiffies
3190 (LOW_SOC_HEARTBEAT_MS)));
3191 else
3192 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003193 round_jiffies_relative(msecs_to_jiffies
3194 (chip->update_time)));
3195}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003196#define VDD_LOOP_ACTIVE_BIT BIT(3)
3197#define VDD_MAX_INCREASE_MV 400
3198static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3199module_param(vdd_max_increase_mv, int, 0644);
3200
3201static int ichg_threshold_ua = -400000;
3202module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003203
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003204#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX 13
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003205#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003206static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3207 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003208{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003209 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003210 int vbat_batt_terminal_mv;
3211 int reg_loop;
3212 int delta_mv = 0;
3213
3214 if (chip->rconn_mohm == 0) {
3215 pr_debug("Exiting as rconn_mohm is 0\n");
3216 return;
3217 }
3218 /* adjust vdd_max only in normal temperature zone */
3219 if (chip->is_bat_cool || chip->is_bat_warm) {
3220 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3221 chip->is_bat_cool, chip->is_bat_warm);
3222 return;
3223 }
3224
3225 reg_loop = pm_chg_get_regulation_loop(chip);
3226 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3227 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3228 reg_loop);
3229 return;
3230 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003231 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3232 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3233
3234 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3235
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003236 if (delta_mv > 0) /* meaning we want to increase the vddmax */ {
3237 if (delta_mv < MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
3238 pr_debug("vterm = %d is not low enough to inc vdd\n",
3239 vbat_batt_terminal_mv);
3240 return;
3241 }
3242 }
3243
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003244 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3245 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3246 delta_mv,
3247 programmed_vdd_max,
3248 adj_vdd_max_mv);
3249
3250 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3251 pr_debug("adj vdd_max lower than default max voltage\n");
3252 return;
3253 }
3254
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003255 adj_vdd_max_mv = (adj_vdd_max_mv / PM8921_CHG_VDDMAX_RES_MV)
3256 * PM8921_CHG_VDDMAX_RES_MV;
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003257
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003258 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3259 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003260 pr_debug("adjusting vdd_max_mv to %d to make "
3261 "vbat_batt_termial_uv = %d to %d\n",
3262 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3263 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3264}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003265
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003266static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3267{
3268 if (chip->is_bat_cool)
3269 pm_chg_vbatdet_set(the_chip,
3270 the_chip->cool_bat_voltage
3271 - the_chip->resume_voltage_delta);
3272 else if (chip->is_bat_warm)
3273 pm_chg_vbatdet_set(the_chip,
3274 the_chip->warm_bat_voltage
3275 - the_chip->resume_voltage_delta);
3276 else
3277 pm_chg_vbatdet_set(the_chip,
3278 the_chip->max_voltage_mv
3279 - the_chip->resume_voltage_delta);
3280}
3281
3282static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3283{
3284 unsigned int chg_current = chip->max_bat_chg_current;
3285
3286 if (chip->is_bat_cool)
3287 chg_current = min(chg_current, chip->cool_bat_chg_current);
3288
3289 if (chip->is_bat_warm)
3290 chg_current = min(chg_current, chip->warm_bat_chg_current);
3291
3292 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3293 chg_current = min(chg_current,
3294 chip->thermal_mitigation[thermal_mitigation]);
3295
3296 pm_chg_ibatmax_set(the_chip, chg_current);
3297}
3298
3299#define TEMP_HYSTERISIS_DECIDEGC 20
3300static void battery_cool(bool enter)
3301{
3302 pr_debug("enter = %d\n", enter);
3303 if (enter == the_chip->is_bat_cool)
3304 return;
3305 the_chip->is_bat_cool = enter;
3306 if (enter)
3307 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3308 else
3309 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3310 set_appropriate_battery_current(the_chip);
3311 set_appropriate_vbatdet(the_chip);
3312}
3313
3314static void battery_warm(bool enter)
3315{
3316 pr_debug("enter = %d\n", enter);
3317 if (enter == the_chip->is_bat_warm)
3318 return;
3319 the_chip->is_bat_warm = enter;
3320 if (enter)
3321 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3322 else
3323 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3324
3325 set_appropriate_battery_current(the_chip);
3326 set_appropriate_vbatdet(the_chip);
3327}
3328
3329static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3330{
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303331 int temp = 0, rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003332
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303333 rc = get_prop_batt_temp(chip, &temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003334 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3335 temp, chip->warm_temp_dc,
3336 chip->cool_temp_dc);
3337
3338 if (chip->warm_temp_dc != INT_MIN) {
3339 if (chip->is_bat_warm
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303340 && temp < chip->warm_temp_dc - chip->hysteresis_temp_dc)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003341 battery_warm(false);
3342 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3343 battery_warm(true);
3344 }
3345
3346 if (chip->cool_temp_dc != INT_MIN) {
3347 if (chip->is_bat_cool
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303348 && temp > chip->cool_temp_dc + chip->hysteresis_temp_dc)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003349 battery_cool(false);
3350 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3351 battery_cool(true);
3352 }
3353}
3354
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003355enum {
3356 CHG_IN_PROGRESS,
3357 CHG_NOT_IN_PROGRESS,
3358 CHG_FINISHED,
3359};
3360
3361#define VBAT_TOLERANCE_MV 70
3362#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003363static int is_charging_finished(struct pm8921_chg_chip *chip,
3364 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003365{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003366 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003367 int regulation_loop, fast_chg, vcp;
3368 int rc;
3369 static int last_vbat_programmed = -EINVAL;
3370
3371 if (!is_ext_charging(chip)) {
3372 /* return if the battery is not being fastcharged */
3373 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3374 pr_debug("fast_chg = %d\n", fast_chg);
3375 if (fast_chg == 0)
3376 return CHG_NOT_IN_PROGRESS;
3377
3378 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3379 pr_debug("vcp = %d\n", vcp);
3380 if (vcp == 1)
3381 return CHG_IN_PROGRESS;
3382
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003383 /* reset count if battery is hot/cold */
3384 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3385 pr_debug("batt_temp_ok = %d\n", rc);
3386 if (rc == 0)
3387 return CHG_IN_PROGRESS;
3388
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003389 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3390 if (rc) {
3391 pr_err("couldnt read vddmax rc = %d\n", rc);
3392 return CHG_IN_PROGRESS;
3393 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003394 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3395 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003396
3397 if (last_vbat_programmed == -EINVAL)
3398 last_vbat_programmed = vbat_programmed;
3399 if (last_vbat_programmed != vbat_programmed) {
3400 /* vddmax changed, reset and check again */
3401 pr_debug("vddmax = %d last_vdd_max=%d\n",
3402 vbat_programmed, last_vbat_programmed);
3403 last_vbat_programmed = vbat_programmed;
3404 return CHG_IN_PROGRESS;
3405 }
3406
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003407 if (chip->is_bat_cool)
3408 vbat_intended = chip->cool_bat_voltage;
3409 else if (chip->is_bat_warm)
3410 vbat_intended = chip->warm_bat_voltage;
3411 else
3412 vbat_intended = chip->max_voltage_mv;
3413
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003414 if (vbat_batt_terminal_uv / 1000
3415 < vbat_intended - MIN_DELTA_MV_TO_INCREASE_VDD_MAX) {
3416 pr_debug("terminal_uv:%d < vbat_intended:%d-hyst:%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003417 vbat_batt_terminal_uv,
Abhijeet Dharmapurikarc615f5a2013-03-25 14:35:18 -07003418 vbat_intended,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003419 vbat_intended);
3420 return CHG_IN_PROGRESS;
3421 }
3422
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003423 regulation_loop = pm_chg_get_regulation_loop(chip);
3424 if (regulation_loop < 0) {
3425 pr_err("couldnt read the regulation loop err=%d\n",
3426 regulation_loop);
3427 return CHG_IN_PROGRESS;
3428 }
3429 pr_debug("regulation_loop=%d\n", regulation_loop);
3430
3431 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3432 return CHG_IN_PROGRESS;
3433 } /* !is_ext_charging */
3434
3435 /* reset count if battery chg current is more than iterm */
3436 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3437 if (rc) {
3438 pr_err("couldnt read iterm rc = %d\n", rc);
3439 return CHG_IN_PROGRESS;
3440 }
3441
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003442 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3443 iterm_programmed, ichg_meas_ma);
3444 /*
3445 * ichg_meas_ma < 0 means battery is drawing current
3446 * ichg_meas_ma > 0 means battery is providing current
3447 */
3448 if (ichg_meas_ma > 0)
3449 return CHG_IN_PROGRESS;
3450
3451 if (ichg_meas_ma * -1 > iterm_programmed)
3452 return CHG_IN_PROGRESS;
3453
3454 return CHG_FINISHED;
3455}
3456
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003457#define COMP_OVERRIDE_HOT_BANK 6
3458#define COMP_OVERRIDE_COLD_BANK 7
3459#define COMP_OVERRIDE_BIT BIT(1)
3460static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3461{
3462 u8 val;
3463 int rc = 0;
3464
3465 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3466
3467 if (flag)
3468 val |= 0x01;
3469
3470 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3471 if (rc < 0)
3472 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3473
3474 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3475 return rc;
3476}
3477
3478static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3479{
3480 u8 val;
3481 int rc = 0;
3482
3483 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3484
3485 if (flag)
3486 val |= 0x01;
3487
3488 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3489 if (rc < 0)
3490 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3491
3492 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3493 return rc;
3494}
3495
3496static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3497{
3498 int rc = 0;
3499 u8 reg;
3500 u8 val;
3501
3502 val = COMP_OVERRIDE_HOT_BANK << 2;
3503 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3504 if (rc < 0) {
3505 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3506 goto cold_init;
3507 }
3508 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3509 if (rc < 0) {
3510 pr_err("Could not read bank %d of override rc = %d\n",
3511 COMP_OVERRIDE_HOT_BANK, rc);
3512 goto cold_init;
3513 }
3514 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3515 /* for now override it as not hot */
3516 rc = pm_chg_override_hot(chip, 0);
3517 if (rc < 0)
3518 pr_err("Could not override hot rc = %d\n", rc);
3519 }
3520
3521cold_init:
3522 val = COMP_OVERRIDE_COLD_BANK << 2;
3523 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3524 if (rc < 0) {
3525 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3526 return;
3527 }
3528 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3529 if (rc < 0) {
3530 pr_err("Could not read bank %d of override rc = %d\n",
3531 COMP_OVERRIDE_COLD_BANK, rc);
3532 return;
3533 }
3534 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3535 /* for now override it as not cold */
3536 rc = pm_chg_override_cold(chip, 0);
3537 if (rc < 0)
3538 pr_err("Could not override cold rc = %d\n", rc);
3539 }
3540}
3541
3542static void btc_override_worker(struct work_struct *work)
3543{
3544 int decidegc;
3545 int temp;
3546 int rc = 0;
3547 struct delayed_work *dwork = to_delayed_work(work);
3548 struct pm8921_chg_chip *chip = container_of(dwork,
3549 struct pm8921_chg_chip, btc_override_work);
3550
3551 if (!chip->btc_override) {
3552 pr_err("called when not enabled\n");
3553 return;
3554 }
3555
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303556 rc = get_prop_batt_temp(chip, &decidegc);
3557 if (rc) {
3558 pr_info("Failed to read temperature\n");
3559 goto fail_btc_temp;
3560 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003561
3562 pr_debug("temp=%d\n", decidegc);
3563
3564 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3565 if (temp) {
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303566 if (decidegc < chip->btc_override_hot_decidegc -
3567 chip->hysteresis_temp_dc)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003568 /* stop forcing batt hot */
3569 rc = pm_chg_override_hot(chip, 0);
3570 if (rc)
3571 pr_err("Couldnt write 0 to hot comp\n");
3572 } else {
3573 if (decidegc >= chip->btc_override_hot_decidegc)
3574 /* start forcing batt hot */
3575 rc = pm_chg_override_hot(chip, 1);
3576 if (rc && chip->btc_panic_if_cant_stop_chg)
3577 panic("Couldnt override comps to stop chg\n");
3578 }
3579
3580 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3581 if (temp) {
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303582 if (decidegc > chip->btc_override_cold_decidegc +
3583 chip->hysteresis_temp_dc)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003584 /* stop forcing batt cold */
3585 rc = pm_chg_override_cold(chip, 0);
3586 if (rc)
3587 pr_err("Couldnt write 0 to cold comp\n");
3588 } else {
3589 if (decidegc <= chip->btc_override_cold_decidegc)
3590 /* start forcing batt cold */
3591 rc = pm_chg_override_cold(chip, 1);
3592 if (rc && chip->btc_panic_if_cant_stop_chg)
3593 panic("Couldnt override comps to stop chg\n");
3594 }
3595
3596 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3597 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3598 schedule_delayed_work(&chip->btc_override_work,
3599 round_jiffies_relative(msecs_to_jiffies
3600 (chip->btc_delay_ms)));
3601 return;
3602 }
3603
Anirudh Ghayal833f22e2013-03-07 09:09:47 +05303604fail_btc_temp:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003605 rc = pm_chg_override_hot(chip, 0);
3606 if (rc)
3607 pr_err("Couldnt write 0 to hot comp\n");
3608 rc = pm_chg_override_cold(chip, 0);
3609 if (rc)
3610 pr_err("Couldnt write 0 to cold comp\n");
3611}
3612
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003613/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003614 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003615 * has happened
3616 *
3617 * If all conditions favouring, if the charge current is
3618 * less than the term current for three consecutive times
3619 * an EOC has happened.
3620 * The wakelock is released if there is no need to reshedule
3621 * - this happens when the battery is removed or EOC has
3622 * happened
3623 */
3624#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003625static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003626{
3627 struct delayed_work *dwork = to_delayed_work(work);
3628 struct pm8921_chg_chip *chip = container_of(dwork,
3629 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003630 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003631 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003632 int vbat_meas_uv, vbat_meas_mv;
3633 int ichg_meas_ua, ichg_meas_ma;
3634 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003635
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003636 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3637 &ichg_meas_ua, &vbat_meas_uv);
3638 vbat_meas_mv = vbat_meas_uv / 1000;
3639 /* rconn_mohm is in milliOhms */
3640 ichg_meas_ma = ichg_meas_ua / 1000;
3641 vbat_batt_terminal_uv = vbat_meas_uv
3642 + ichg_meas_ma
3643 * the_chip->rconn_mohm;
3644
3645 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003646
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303647 if (end == CHG_NOT_IN_PROGRESS && (!chip->btc_override ||
3648 !(chip->usb_present || chip->dc_present))) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003649 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003650 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003651 }
3652
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003653 if (end == CHG_FINISHED) {
3654 count++;
3655 } else {
3656 count = 0;
3657 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003658
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003659 if (count == CONSECUTIVE_COUNT) {
3660 count = 0;
3661 pr_info("End of Charging\n");
3662
3663 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003664
Amir Samuelovd31ef502011-10-26 14:41:36 +02003665 if (is_ext_charging(chip))
3666 chip->ext_charge_done = true;
3667
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003668 if (chip->is_bat_warm || chip->is_bat_cool)
3669 chip->bms_notify.is_battery_full = 0;
3670 else
3671 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003672 /* declare end of charging by invoking chgdone interrupt */
3673 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003674 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003675 check_temp_thresholds(chip);
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303676 if (end != CHG_NOT_IN_PROGRESS)
3677 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003678 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003679 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003680 round_jiffies_relative(msecs_to_jiffies
3681 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003682 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003683 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003684
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003685eoc_worker_stop:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003686 /* set the vbatdet back, in case it was changed to trigger charging */
3687 set_appropriate_vbatdet(chip);
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303688 wake_unlock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003689}
3690
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003691/**
3692 * set_disable_status_param -
3693 *
3694 * Internal function to disable battery charging and also disable drawing
3695 * any current from the source. The device is forced to run on a battery
3696 * after this.
3697 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003698static int set_disable_status_param(const char *val, struct kernel_param *kp)
3699{
3700 int ret;
3701 struct pm8921_chg_chip *chip = the_chip;
3702
3703 ret = param_set_int(val, kp);
3704 if (ret) {
3705 pr_err("error setting value %d\n", ret);
3706 return ret;
3707 }
3708 pr_info("factory set disable param to %d\n", charging_disabled);
3709 if (chip) {
3710 pm_chg_auto_enable(chip, !charging_disabled);
3711 pm_chg_charge_dis(chip, charging_disabled);
3712 }
3713 return 0;
3714}
3715module_param_call(disabled, set_disable_status_param, param_get_uint,
3716 &charging_disabled, 0644);
3717
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003718static int rconn_mohm;
3719static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3720{
3721 int ret;
3722 struct pm8921_chg_chip *chip = the_chip;
3723
3724 ret = param_set_int(val, kp);
3725 if (ret) {
3726 pr_err("error setting value %d\n", ret);
3727 return ret;
3728 }
3729 if (chip)
3730 chip->rconn_mohm = rconn_mohm;
3731 return 0;
3732}
3733module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3734 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003735/**
3736 * set_thermal_mitigation_level -
3737 *
3738 * Internal function to control battery charging current to reduce
3739 * temperature
3740 */
3741static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3742{
3743 int ret;
3744 struct pm8921_chg_chip *chip = the_chip;
3745
3746 ret = param_set_int(val, kp);
3747 if (ret) {
3748 pr_err("error setting value %d\n", ret);
3749 return ret;
3750 }
3751
3752 if (!chip) {
3753 pr_err("called before init\n");
3754 return -EINVAL;
3755 }
3756
3757 if (!chip->thermal_mitigation) {
3758 pr_err("no thermal mitigation\n");
3759 return -EINVAL;
3760 }
3761
3762 if (thermal_mitigation < 0
3763 || thermal_mitigation >= chip->thermal_levels) {
3764 pr_err("out of bound level selected\n");
3765 return -EINVAL;
3766 }
3767
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003768 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003769 return ret;
3770}
3771module_param_call(thermal_mitigation, set_therm_mitigation_level,
3772 param_get_uint,
3773 &thermal_mitigation, 0644);
3774
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003775static int set_usb_max_current(const char *val, struct kernel_param *kp)
3776{
3777 int ret, mA;
3778 struct pm8921_chg_chip *chip = the_chip;
3779
3780 ret = param_set_int(val, kp);
3781 if (ret) {
3782 pr_err("error setting value %d\n", ret);
3783 return ret;
3784 }
3785 if (chip) {
3786 pr_warn("setting current max to %d\n", usb_max_current);
3787 pm_chg_iusbmax_get(chip, &mA);
3788 if (mA > usb_max_current)
3789 pm8921_charger_vbus_draw(usb_max_current);
3790 return 0;
3791 }
3792 return -EINVAL;
3793}
David Keitelacf57c82012-03-07 18:48:50 -08003794module_param_call(usb_max_current, set_usb_max_current,
3795 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003797static void free_irqs(struct pm8921_chg_chip *chip)
3798{
3799 int i;
3800
3801 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3802 if (chip->pmic_chg_irq[i]) {
3803 free_irq(chip->pmic_chg_irq[i], chip);
3804 chip->pmic_chg_irq[i] = 0;
3805 }
3806}
3807
David Keitel88e1b572012-01-11 11:57:14 -08003808/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3810{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003811 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003812 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003813
3814 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3815 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3816
3817 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003818 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003819 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003820 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003821 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05303822
3823 if (chip->btc_override)
3824 schedule_delayed_work(&chip->btc_override_work,
3825 round_jiffies_relative(msecs_to_jiffies
3826 (chip->btc_delay_ms)));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003828
3829 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3830 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3831 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003832 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003833 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3834 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003835 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003836 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3837 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003838 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003840 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3841 if (usb_chg_current)
3842 /*
3843 * Reissue a vbus draw call only if a battery
3844 * or DC is present. We don't want to brown out the
3845 * device if usb is its only source
3846 */
3847 __pm8921_charger_vbus_draw(usb_chg_current);
3848 usb_chg_current = 0;
3849
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003850 /*
3851 * The bootloader could have started charging, a fastchg interrupt
3852 * might not happen. Check the real time status and if it is fast
3853 * charging invoke the handler so that the eoc worker could be
3854 * started
3855 */
3856 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3857 if (is_fast_chg)
3858 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003859
3860 fsm_state = pm_chg_get_fsm_state(chip);
3861 if (is_battery_charging(fsm_state)) {
3862 chip->bms_notify.is_charging = 1;
3863 pm8921_bms_charging_began();
3864 }
3865
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003866 check_battery_valid(chip);
3867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003868 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3869 chip->usb_present,
3870 chip->dc_present,
3871 get_prop_batt_present(chip),
3872 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003873
3874 /* Determine which USB trim column to use */
3875 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3876 chip->usb_trim_table = usb_trim_8917_table;
3877 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3878 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879}
3880
3881struct pm_chg_irq_init_data {
3882 unsigned int irq_id;
3883 char *name;
3884 unsigned long flags;
3885 irqreturn_t (*handler)(int, void *);
3886};
3887
3888#define CHG_IRQ(_id, _flags, _handler) \
3889{ \
3890 .irq_id = _id, \
3891 .name = #_id, \
3892 .flags = _flags, \
3893 .handler = _handler, \
3894}
3895struct pm_chg_irq_init_data chg_irq_data[] = {
3896 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3897 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3899 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003900 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3901 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003902 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3903 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3904 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3905 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3906 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3907 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3908 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3909 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003910 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3911 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003912 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3913 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3914 batt_removed_irq_handler),
3915 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3916 batttemp_hot_irq_handler),
3917 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3918 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3919 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003920 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3921 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003922 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3923 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003924 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3925 coarse_det_low_irq_handler),
3926 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3927 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3928 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3929 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3930 batfet_irq_handler),
3931 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3932 dcin_valid_irq_handler),
3933 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3934 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003935 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003936};
3937
3938static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3939 struct platform_device *pdev)
3940{
3941 struct resource *res;
3942 int ret, i;
3943
3944 ret = 0;
3945 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3946
3947 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3948 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3949 chg_irq_data[i].name);
3950 if (res == NULL) {
3951 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3952 goto err_out;
3953 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003954 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 ret = request_irq(res->start, chg_irq_data[i].handler,
3956 chg_irq_data[i].flags,
3957 chg_irq_data[i].name, chip);
3958 if (ret < 0) {
3959 pr_err("couldn't request %d (%s) %d\n", res->start,
3960 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003961 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003962 goto err_out;
3963 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003964 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3965 }
3966 return 0;
3967
3968err_out:
3969 free_irqs(chip);
3970 return -EINVAL;
3971}
3972
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003973static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3974{
3975 int err;
3976 u8 temp;
3977
3978 temp = 0xD1;
3979 err = pm_chg_write(chip, CHG_TEST, temp);
3980 if (err) {
3981 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3982 return;
3983 }
3984
3985 temp = 0xD3;
3986 err = pm_chg_write(chip, CHG_TEST, temp);
3987 if (err) {
3988 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3989 return;
3990 }
3991
3992 temp = 0xD1;
3993 err = pm_chg_write(chip, CHG_TEST, temp);
3994 if (err) {
3995 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3996 return;
3997 }
3998
3999 temp = 0xD5;
4000 err = pm_chg_write(chip, CHG_TEST, temp);
4001 if (err) {
4002 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4003 return;
4004 }
4005
4006 udelay(183);
4007
4008 temp = 0xD1;
4009 err = pm_chg_write(chip, CHG_TEST, temp);
4010 if (err) {
4011 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4012 return;
4013 }
4014
4015 temp = 0xD0;
4016 err = pm_chg_write(chip, CHG_TEST, temp);
4017 if (err) {
4018 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4019 return;
4020 }
4021 udelay(32);
4022
4023 temp = 0xD1;
4024 err = pm_chg_write(chip, CHG_TEST, temp);
4025 if (err) {
4026 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4027 return;
4028 }
4029
4030 temp = 0xD3;
4031 err = pm_chg_write(chip, CHG_TEST, temp);
4032 if (err) {
4033 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4034 return;
4035 }
4036}
4037
4038static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
4039{
4040 int err;
4041 u8 temp;
4042
4043 temp = 0xD1;
4044 err = pm_chg_write(chip, CHG_TEST, temp);
4045 if (err) {
4046 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4047 return;
4048 }
4049
4050 temp = 0xD0;
4051 err = pm_chg_write(chip, CHG_TEST, temp);
4052 if (err) {
4053 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
4054 return;
4055 }
4056}
4057
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004058#define VREF_BATT_THERM_FORCE_ON BIT(7)
4059static void detect_battery_removal(struct pm8921_chg_chip *chip)
4060{
4061 u8 temp;
4062
4063 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4064 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4065
4066 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4067 /*
4068 * batt therm force on bit is battery backed and is default 0
4069 * The charger sets this bit at init time. If this bit is found
4070 * 0 that means the battery was removed. Tell the bms about it
4071 */
4072 pm8921_bms_invalidate_shutdown_soc();
4073}
4074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004075#define ENUM_TIMER_STOP_BIT BIT(1)
4076#define BOOT_DONE_BIT BIT(6)
4077#define CHG_BATFET_ON_BIT BIT(3)
4078#define CHG_VCP_EN BIT(0)
4079#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4080#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004081#define PM_SUB_REV 0x001
4082#define MIN_CHARGE_CURRENT_MA 350
4083#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4085{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004086 u8 subrev;
4087 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004089 /* forcing 19p2mhz before accessing any charger registers */
4090 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004091
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004092 detect_battery_removal(chip);
4093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004094 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004095 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004096 if (rc) {
4097 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4098 return rc;
4099 }
4100
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004101 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4102
4103 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4104 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4105
4106 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 if (rc) {
4109 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004110 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 return rc;
4112 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004113 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004114 chip->max_voltage_mv
4115 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 if (rc) {
4117 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004118 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004119 return rc;
4120 }
4121
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004122 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004123 if (rc) {
4124 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004125 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126 return rc;
4127 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004128
4129 if (chip->safe_current_ma == 0)
4130 chip->safe_current_ma = SAFE_CURRENT_MA;
4131
4132 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004133 if (rc) {
4134 pr_err("Failed to set max voltage to %d rc=%d\n",
4135 SAFE_CURRENT_MA, rc);
4136 return rc;
4137 }
4138
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004139 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 if (rc) {
4141 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4142 return rc;
4143 }
4144
4145 rc = pm_chg_iterm_set(chip, chip->term_current);
4146 if (rc) {
4147 pr_err("Failed to set term current to %d rc=%d\n",
4148 chip->term_current, rc);
4149 return rc;
4150 }
4151
4152 /* Disable the ENUM TIMER */
4153 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4154 ENUM_TIMER_STOP_BIT);
4155 if (rc) {
4156 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4157 return rc;
4158 }
4159
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004160 fcc_uah = pm8921_bms_get_fcc();
4161 if (fcc_uah > 0) {
4162 safety_time = div_s64((s64)fcc_uah * 60,
4163 1000 * MIN_CHARGE_CURRENT_MA);
4164 /* add 20 minutes of buffer time */
4165 safety_time += 20;
4166
4167 /* make sure we do not exceed the maximum programmable time */
4168 if (safety_time > PM8921_CHG_TCHG_MAX)
4169 safety_time = PM8921_CHG_TCHG_MAX;
4170 }
4171
4172 rc = pm_chg_tchg_max_set(chip, safety_time);
4173 if (rc) {
4174 pr_err("Failed to set max time to %d minutes rc=%d\n",
4175 safety_time, rc);
4176 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004177 }
4178
4179 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004180 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004181 if (rc) {
4182 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004183 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004184 return rc;
4185 }
4186 }
4187
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004188 if (chip->vin_min != 0) {
4189 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4190 if (rc) {
4191 pr_err("Failed to set vin min to %d mV rc=%d\n",
4192 chip->vin_min, rc);
4193 return rc;
4194 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004195 } else {
4196 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004197 }
4198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 rc = pm_chg_disable_wd(chip);
4200 if (rc) {
4201 pr_err("Failed to disable wd rc=%d\n", rc);
4202 return rc;
4203 }
4204
4205 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4206 CHG_BAT_TEMP_DIS_BIT, 0);
4207 if (rc) {
4208 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4209 return rc;
4210 }
4211 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004212 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4213 rc = pm_chg_write(chip,
4214 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4215 else
4216 rc = pm_chg_write(chip,
4217 CHG_BUCK_CLOCK_CTRL, 0x15);
4218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004219 if (rc) {
4220 pr_err("Failed to switch buck clk rc=%d\n", rc);
4221 return rc;
4222 }
4223
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004224 if (chip->trkl_voltage != 0) {
4225 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4226 if (rc) {
4227 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4228 chip->trkl_voltage, rc);
4229 return rc;
4230 }
4231 }
4232
4233 if (chip->weak_voltage != 0) {
4234 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4235 if (rc) {
4236 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4237 chip->weak_voltage, rc);
4238 return rc;
4239 }
4240 }
4241
4242 if (chip->trkl_current != 0) {
4243 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4244 if (rc) {
4245 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4246 chip->trkl_voltage, rc);
4247 return rc;
4248 }
4249 }
4250
4251 if (chip->weak_current != 0) {
4252 rc = pm_chg_iweak_set(chip, chip->weak_current);
4253 if (rc) {
4254 pr_err("Failed to set weak current to %dmA rc=%d\n",
4255 chip->weak_current, rc);
4256 return rc;
4257 }
4258 }
4259
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004260 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4261 if (rc) {
4262 pr_err("Failed to set cold config %d rc=%d\n",
4263 chip->cold_thr, rc);
4264 }
4265
4266 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4267 if (rc) {
4268 pr_err("Failed to set hot config %d rc=%d\n",
4269 chip->hot_thr, rc);
4270 }
4271
Jay Chokshid674a512012-03-15 14:06:04 -07004272 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4273 if (rc) {
4274 pr_err("Failed to set charger LED src config %d rc=%d\n",
4275 chip->led_src_config, rc);
4276 }
4277
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004278 /* Workarounds for die 3.0 */
4279 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4280 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4281 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4282 if (rc) {
4283 pr_err("read failed: addr=%03X, rc=%d\n",
4284 PM_SUB_REV, rc);
4285 return rc;
4286 }
4287 /* Check if die 3.0.1 is present */
4288 if (subrev & 0x1)
4289 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4290 else
4291 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004292 }
4293
David Keitel0789fc62012-06-07 17:43:27 -07004294 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004295 /* Set PM8917 USB_OVP debounce time to 15 ms */
4296 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4297 OVP_DEBOUNCE_TIME, 0x6);
4298 if (rc) {
4299 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4300 return rc;
4301 }
4302
4303 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004304 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004305 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004306 rc = pm_chg_uvd_threshold_set(chip,
4307 chip->uvd_voltage_mv);
4308 if (rc) {
4309 pr_err("Failed to set UVD threshold %drc=%d\n",
4310 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004311 return rc;
4312 }
David Keitel0789fc62012-06-07 17:43:27 -07004313 }
4314 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004315
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004316 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004317
David Keitela3c0d822011-11-03 14:18:52 -07004318 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004319 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004320
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004321 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4322 VREF_BATT_THERM_FORCE_ON);
4323 if (rc)
4324 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326 rc = pm_chg_charge_dis(chip, charging_disabled);
4327 if (rc) {
4328 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4329 return rc;
4330 }
4331
4332 rc = pm_chg_auto_enable(chip, !charging_disabled);
4333 if (rc) {
4334 pr_err("Failed to enable charging rc=%d\n", rc);
4335 return rc;
4336 }
4337
4338 return 0;
4339}
4340
4341static int get_rt_status(void *data, u64 * val)
4342{
4343 int i = (int)data;
4344 int ret;
4345
4346 /* global irq number is passed in via data */
4347 ret = pm_chg_get_rt_status(the_chip, i);
4348 *val = ret;
4349 return 0;
4350}
4351DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4352
4353static int get_fsm_status(void *data, u64 * val)
4354{
4355 u8 temp;
4356
4357 temp = pm_chg_get_fsm_state(the_chip);
4358 *val = temp;
4359 return 0;
4360}
4361DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4362
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004363static int get_reg_loop(void *data, u64 * val)
4364{
4365 u8 temp;
4366
4367 if (!the_chip) {
4368 pr_err("%s called before init\n", __func__);
4369 return -EINVAL;
4370 }
4371 temp = pm_chg_get_regulation_loop(the_chip);
4372 *val = temp;
4373 return 0;
4374}
4375DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4376
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004377static int get_reg(void *data, u64 * val)
4378{
4379 int addr = (int)data;
4380 int ret;
4381 u8 temp;
4382
4383 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4384 if (ret) {
4385 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4386 addr, temp, ret);
4387 return -EAGAIN;
4388 }
4389 *val = temp;
4390 return 0;
4391}
4392
4393static int set_reg(void *data, u64 val)
4394{
4395 int addr = (int)data;
4396 int ret;
4397 u8 temp;
4398
4399 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004400 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004401 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004402 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004403 addr, temp, ret);
4404 return -EAGAIN;
4405 }
4406 return 0;
4407}
4408DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4409
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004410static int reg_loop;
4411#define MAX_REG_LOOP_CHAR 10
4412static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4413{
4414 u8 temp;
4415
4416 if (!the_chip) {
4417 pr_err("called before init\n");
4418 return -EINVAL;
4419 }
4420 temp = pm_chg_get_regulation_loop(the_chip);
4421 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4422}
4423module_param_call(reg_loop, NULL, get_reg_loop_param,
4424 &reg_loop, 0644);
4425
4426static int max_chg_ma;
4427#define MAX_MA_CHAR 10
4428static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4429{
4430 if (!the_chip) {
4431 pr_err("called before init\n");
4432 return -EINVAL;
4433 }
4434 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4435}
4436module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4437 &max_chg_ma, 0644);
4438static int ibatmax_ma;
4439static int set_ibat_max(const char *val, struct kernel_param *kp)
4440{
4441 int rc;
4442
4443 if (!the_chip) {
4444 pr_err("called before init\n");
4445 return -EINVAL;
4446 }
4447
4448 rc = param_set_int(val, kp);
4449 if (rc) {
4450 pr_err("error setting value %d\n", rc);
4451 return rc;
4452 }
4453
4454 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4455 <= the_chip->ibatmax_max_adj_ma) {
4456 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4457 if (rc) {
4458 pr_err("Failed to set ibatmax rc = %d\n", rc);
4459 return rc;
4460 }
4461 }
4462
4463 return 0;
4464}
4465static int get_ibat_max(char *buf, struct kernel_param *kp)
4466{
4467 int ibat_ma;
4468 int rc;
4469
4470 if (!the_chip) {
4471 pr_err("called before init\n");
4472 return -EINVAL;
4473 }
4474
4475 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4476 if (rc) {
4477 pr_err("ibatmax_get error = %d\n", rc);
4478 return rc;
4479 }
4480
4481 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4482}
4483module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4484 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004485enum {
4486 BAT_WARM_ZONE,
4487 BAT_COOL_ZONE,
4488};
4489static int get_warm_cool(void *data, u64 * val)
4490{
4491 if (!the_chip) {
4492 pr_err("%s called before init\n", __func__);
4493 return -EINVAL;
4494 }
4495 if ((int)data == BAT_WARM_ZONE)
4496 *val = the_chip->is_bat_warm;
4497 if ((int)data == BAT_COOL_ZONE)
4498 *val = the_chip->is_bat_cool;
4499 return 0;
4500}
4501DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4504{
4505 int i;
4506
4507 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4508
4509 if (IS_ERR(chip->dent)) {
4510 pr_err("pmic charger couldnt create debugfs dir\n");
4511 return;
4512 }
4513
4514 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4515 (void *)CHG_CNTRL, &reg_fops);
4516 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4517 (void *)CHG_CNTRL_2, &reg_fops);
4518 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4519 (void *)CHG_CNTRL_3, &reg_fops);
4520 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4521 (void *)PBL_ACCESS1, &reg_fops);
4522 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4523 (void *)PBL_ACCESS2, &reg_fops);
4524 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4525 (void *)SYS_CONFIG_1, &reg_fops);
4526 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4527 (void *)SYS_CONFIG_2, &reg_fops);
4528 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4529 (void *)CHG_VDD_MAX, &reg_fops);
4530 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4531 (void *)CHG_VDD_SAFE, &reg_fops);
4532 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4533 (void *)CHG_VBAT_DET, &reg_fops);
4534 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4535 (void *)CHG_IBAT_MAX, &reg_fops);
4536 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4537 (void *)CHG_IBAT_SAFE, &reg_fops);
4538 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4539 (void *)CHG_VIN_MIN, &reg_fops);
4540 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4541 (void *)CHG_VTRICKLE, &reg_fops);
4542 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4543 (void *)CHG_ITRICKLE, &reg_fops);
4544 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4545 (void *)CHG_ITERM, &reg_fops);
4546 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4547 (void *)CHG_TCHG_MAX, &reg_fops);
4548 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4549 (void *)CHG_TWDOG, &reg_fops);
4550 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4551 (void *)CHG_TEMP_THRESH, &reg_fops);
4552 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4553 (void *)CHG_COMP_OVR, &reg_fops);
4554 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4555 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4556 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4557 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4558 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4559 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4560 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4561 (void *)CHG_TEST, &reg_fops);
4562
4563 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4564 &fsm_fops);
4565
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004566 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4567 &reg_loop_fops);
4568
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004569 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4570 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4571 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4572 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004574 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4575 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4576 debugfs_create_file(chg_irq_data[i].name, 0444,
4577 chip->dent,
4578 (void *)chg_irq_data[i].irq_id,
4579 &rt_fops);
4580 }
4581}
4582
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004583static int pm8921_charger_suspend_noirq(struct device *dev)
4584{
4585 int rc;
4586 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4587
4588 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4589 if (rc)
4590 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004591
4592 rc = pm8921_chg_set_lpm(chip, 1);
4593 if (rc)
4594 pr_err("Failed to set lpm rc=%d\n", rc);
4595
4596 pm8921_chg_set_hw_clk_switching(chip);
4597
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004598 return 0;
4599}
4600
4601static int pm8921_charger_resume_noirq(struct device *dev)
4602{
4603 int rc;
4604 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4605
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004606 rc = pm8921_chg_set_lpm(chip, 0);
4607 if (rc)
4608 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004609
Abhijeet Dharmapurikarc74a7742013-04-10 11:27:51 -07004610 pm8921_chg_force_19p2mhz_clk(chip);
4611
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004612 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4613 VREF_BATT_THERM_FORCE_ON);
4614 if (rc)
4615 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4616 return 0;
4617}
4618
David Keitelf2226022011-12-13 15:55:50 -08004619static int pm8921_charger_resume(struct device *dev)
4620{
David Keitelf2226022011-12-13 15:55:50 -08004621 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4622
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004623 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4624 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4625 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4626 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004627
4628 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4629 is_usb_chg_plugged_in(the_chip)))
4630 schedule_delayed_work(&chip->btc_override_work, 0);
4631
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05304632 schedule_delayed_work(&chip->update_heartbeat_work, 0);
4633
David Keitelf2226022011-12-13 15:55:50 -08004634 return 0;
4635}
4636
4637static int pm8921_charger_suspend(struct device *dev)
4638{
David Keitelf2226022011-12-13 15:55:50 -08004639 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4640
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05304641 cancel_delayed_work_sync(&chip->update_heartbeat_work);
4642
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004643 if (chip->btc_override)
4644 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004645
4646 if (is_usb_chg_plugged_in(chip)) {
4647 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4648 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4649 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004650
David Keitelf2226022011-12-13 15:55:50 -08004651 return 0;
4652}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004653static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4654{
4655 int rc = 0;
4656 struct pm8921_chg_chip *chip;
4657 const struct pm8921_charger_platform_data *pdata
4658 = pdev->dev.platform_data;
4659
4660 if (!pdata) {
4661 pr_err("missing platform data\n");
4662 return -EINVAL;
4663 }
4664
4665 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4666 GFP_KERNEL);
4667 if (!chip) {
4668 pr_err("Cannot allocate pm_chg_chip\n");
4669 return -ENOMEM;
4670 }
4671
4672 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004673 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004674 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004675 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004676 chip->alarm_low_mv = pdata->alarm_low_mv;
4677 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004678 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004679 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004680 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004681 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004682 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004683 chip->term_current = pdata->term_current;
4684 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004685 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004686 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4687 chip->batt_id_min = pdata->batt_id_min;
4688 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004689 if (pdata->cool_temp != INT_MIN)
4690 chip->cool_temp_dc = pdata->cool_temp * 10;
4691 else
4692 chip->cool_temp_dc = INT_MIN;
4693
4694 if (pdata->warm_temp != INT_MIN)
4695 chip->warm_temp_dc = pdata->warm_temp * 10;
4696 else
4697 chip->warm_temp_dc = INT_MIN;
4698
Anirudh Ghayale747b7e2013-04-04 12:18:18 +05304699 if (pdata->hysteresis_temp)
4700 chip->hysteresis_temp_dc = pdata->hysteresis_temp * 10;
4701 else
4702 chip->hysteresis_temp_dc = TEMP_HYSTERISIS_DECIDEGC;
4703
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004704 chip->temp_check_period = pdata->temp_check_period;
4705 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004706 /* Assign to corresponding module parameter */
4707 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004708 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4709 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4710 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4711 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004712 chip->trkl_voltage = pdata->trkl_voltage;
4713 chip->weak_voltage = pdata->weak_voltage;
4714 chip->trkl_current = pdata->trkl_current;
4715 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004716 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004717 chip->thermal_mitigation = pdata->thermal_mitigation;
4718 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304719 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004720
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004721 chip->cold_thr = pdata->cold_thr;
4722 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004723 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004724 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004725 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004726 chip->battery_less_hardware = pdata->battery_less_hardware;
4727 chip->btc_override = pdata->btc_override;
4728 if (chip->btc_override) {
4729 chip->btc_delay_ms = pdata->btc_delay_ms;
4730 chip->btc_override_cold_decidegc
4731 = pdata->btc_override_cold_degc * 10;
4732 chip->btc_override_hot_decidegc
4733 = pdata->btc_override_hot_degc * 10;
4734 chip->btc_panic_if_cant_stop_chg
4735 = pdata->btc_panic_if_cant_stop_chg;
4736 }
4737
4738 if (chip->battery_less_hardware)
4739 charging_disabled = 1;
4740
4741 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4742 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004744 rc = pm8921_chg_hw_init(chip);
4745 if (rc) {
4746 pr_err("couldn't init hardware rc=%d\n", rc);
4747 goto free_chip;
4748 }
4749
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004750 if (chip->btc_override)
4751 pm8921_chg_btc_override_init(chip);
4752
4753 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304754 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004755
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004756 chip->usb_psy.name = "usb";
4757 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4758 chip->usb_psy.supplied_to = pm_power_supplied_to;
4759 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4760 chip->usb_psy.properties = pm_power_props_usb;
4761 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4762 chip->usb_psy.get_property = pm_power_get_property_usb;
4763 chip->usb_psy.set_property = pm_power_set_property_usb;
4764 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004766 chip->dc_psy.name = "pm8921-dc";
4767 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4768 chip->dc_psy.supplied_to = pm_power_supplied_to;
4769 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4770 chip->dc_psy.properties = pm_power_props_mains;
4771 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4772 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004773
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004774 chip->batt_psy.name = "battery";
4775 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4776 chip->batt_psy.properties = msm_batt_power_props;
4777 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4778 chip->batt_psy.get_property = pm_batt_power_get_property;
4779 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004780 rc = power_supply_register(chip->dev, &chip->usb_psy);
4781 if (rc < 0) {
4782 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004783 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004784 }
4785
David Keitel6ed71a52012-01-30 12:42:18 -08004786 rc = power_supply_register(chip->dev, &chip->dc_psy);
4787 if (rc < 0) {
4788 pr_err("power_supply_register usb failed rc = %d\n", rc);
4789 goto unregister_usb;
4790 }
4791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004792 rc = power_supply_register(chip->dev, &chip->batt_psy);
4793 if (rc < 0) {
4794 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004795 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796 }
4797
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004798 platform_set_drvdata(pdev, chip);
4799 the_chip = chip;
4800
4801 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004802 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004803 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4804 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004805 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004806
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004807 INIT_WORK(&chip->bms_notify.work, bms_notify);
4808 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4809
4810 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4811 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813 rc = request_irqs(chip, pdev);
4814 if (rc) {
4815 pr_err("couldn't register interrupts rc=%d\n", rc);
4816 goto unregister_batt;
4817 }
4818
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004819 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004820 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004821 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004822 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004824 create_debugfs_entries(chip);
4825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004826 /* determine what state the charger is in */
4827 determine_initial_state(chip);
4828
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004829 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004830 schedule_delayed_work(&chip->update_heartbeat_work,
4831 round_jiffies_relative(msecs_to_jiffies
4832 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 return 0;
4834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004835unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004836 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004837 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004838unregister_dc:
4839 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004840unregister_usb:
4841 power_supply_unregister(&chip->usb_psy);
4842free_chip:
4843 kfree(chip);
4844 return rc;
4845}
4846
4847static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4848{
4849 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4850
4851 free_irqs(chip);
4852 platform_set_drvdata(pdev, NULL);
4853 the_chip = NULL;
4854 kfree(chip);
4855 return 0;
4856}
David Keitelf2226022011-12-13 15:55:50 -08004857static const struct dev_pm_ops pm8921_pm_ops = {
4858 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004859 .suspend_noirq = pm8921_charger_suspend_noirq,
4860 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004861 .resume = pm8921_charger_resume,
4862};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004863static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004864 .probe = pm8921_charger_probe,
4865 .remove = __devexit_p(pm8921_charger_remove),
4866 .driver = {
4867 .name = PM8921_CHARGER_DEV_NAME,
4868 .owner = THIS_MODULE,
4869 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 },
4871};
4872
4873static int __init pm8921_charger_init(void)
4874{
4875 return platform_driver_register(&pm8921_charger_driver);
4876}
4877
4878static void __exit pm8921_charger_exit(void)
4879{
4880 platform_driver_unregister(&pm8921_charger_driver);
4881}
4882
4883late_initcall(pm8921_charger_init);
4884module_exit(pm8921_charger_exit);
4885
4886MODULE_LICENSE("GPL v2");
4887MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4888MODULE_VERSION("1.0");
4889MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);