blob: 9c896b35a8f0cd16ad5a84a98c2bcd29e98b0133 [file] [log] [blame]
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070024#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/delay.h>
27#include <linux/bitops.h>
28#include <linux/workqueue.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
Ajay Dudani11aeb7b2012-06-28 19:14:30 -070031#include <linux/mfd/pm8xxx/batt-alarm.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070032#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033
34#include <mach/msm_xo.h>
35#include <mach/msm_hsusb.h>
36
37#define CHG_BUCK_CLOCK_CTRL 0x14
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070038#define CHG_BUCK_CLOCK_CTRL_8038 0xD
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#define PBL_ACCESS1 0x04
41#define PBL_ACCESS2 0x05
42#define SYS_CONFIG_1 0x06
43#define SYS_CONFIG_2 0x07
44#define CHG_CNTRL 0x204
45#define CHG_IBAT_MAX 0x205
46#define CHG_TEST 0x206
47#define CHG_BUCK_CTRL_TEST1 0x207
48#define CHG_BUCK_CTRL_TEST2 0x208
49#define CHG_BUCK_CTRL_TEST3 0x209
50#define COMPARATOR_OVERRIDE 0x20A
51#define PSI_TXRX_SAMPLE_DATA_0 0x20B
52#define PSI_TXRX_SAMPLE_DATA_1 0x20C
53#define PSI_TXRX_SAMPLE_DATA_2 0x20D
54#define PSI_TXRX_SAMPLE_DATA_3 0x20E
55#define PSI_CONFIG_STATUS 0x20F
56#define CHG_IBAT_SAFE 0x210
57#define CHG_ITRICKLE 0x211
58#define CHG_CNTRL_2 0x212
59#define CHG_VBAT_DET 0x213
60#define CHG_VTRICKLE 0x214
61#define CHG_ITERM 0x215
62#define CHG_CNTRL_3 0x216
63#define CHG_VIN_MIN 0x217
64#define CHG_TWDOG 0x218
65#define CHG_TTRKL_MAX 0x219
66#define CHG_TEMP_THRESH 0x21A
67#define CHG_TCHG_MAX 0x21B
68#define USB_OVP_CONTROL 0x21C
69#define DC_OVP_CONTROL 0x21D
70#define USB_OVP_TEST 0x21E
71#define DC_OVP_TEST 0x21F
72#define CHG_VDD_MAX 0x220
73#define CHG_VDD_SAFE 0x221
74#define CHG_VBAT_BOOT_THRESH 0x222
75#define USB_OVP_TRIM 0x355
76#define BUCK_CONTROL_TRIM1 0x356
77#define BUCK_CONTROL_TRIM2 0x357
78#define BUCK_CONTROL_TRIM3 0x358
79#define BUCK_CONTROL_TRIM4 0x359
80#define CHG_DEFAULTS_TRIM 0x35A
81#define CHG_ITRIM 0x35B
82#define CHG_TTRIM 0x35C
83#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070084#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070085#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070087/* check EOC every 10 seconds */
88#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080089/* check for USB unplug every 200 msecs */
90#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070091#define UNPLUG_CHECK_RAMP_MS 25
92#define USB_TRIM_ENTRIES 16
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094enum chg_fsm_state {
95 FSM_STATE_OFF_0 = 0,
96 FSM_STATE_BATFETDET_START_12 = 12,
97 FSM_STATE_BATFETDET_END_16 = 16,
98 FSM_STATE_ON_CHG_HIGHI_1 = 1,
99 FSM_STATE_ATC_2A = 2,
100 FSM_STATE_ATC_2B = 18,
101 FSM_STATE_ON_BAT_3 = 3,
102 FSM_STATE_ATC_FAIL_4 = 4 ,
103 FSM_STATE_DELAY_5 = 5,
104 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
105 FSM_STATE_FAST_CHG_7 = 7,
106 FSM_STATE_TRKL_CHG_8 = 8,
107 FSM_STATE_CHG_FAIL_9 = 9,
108 FSM_STATE_EOC_10 = 10,
109 FSM_STATE_ON_CHG_VREGOK_11 = 11,
110 FSM_STATE_ATC_PAUSE_13 = 13,
111 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
112 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
113 FSM_STATE_START_BOOT = 20,
114 FSM_STATE_FLCB_VREGOK = 21,
115 FSM_STATE_FLCB = 22,
116};
117
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700118struct fsm_state_to_batt_status {
119 enum chg_fsm_state fsm_state;
120 int batt_state;
121};
122
123static struct fsm_state_to_batt_status map[] = {
124 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
125 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
126 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
127 /*
128 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
129 * too hot/cold, charger too hot
130 */
131 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
132 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
134 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
135 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
136 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
137 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
138 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
139 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
140 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
141 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
142 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
143 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
144 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
146 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
147 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
149};
150
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700151enum chg_regulation_loop {
152 VDD_LOOP = BIT(3),
153 BAT_CURRENT_LOOP = BIT(2),
154 INPUT_CURRENT_LOOP = BIT(1),
155 INPUT_VOLTAGE_LOOP = BIT(0),
156 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
157 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160enum pmic_chg_interrupts {
161 USBIN_VALID_IRQ = 0,
162 USBIN_OV_IRQ,
163 BATT_INSERTED_IRQ,
164 VBATDET_LOW_IRQ,
165 USBIN_UV_IRQ,
166 VBAT_OV_IRQ,
167 CHGWDOG_IRQ,
168 VCP_IRQ,
169 ATCDONE_IRQ,
170 ATCFAIL_IRQ,
171 CHGDONE_IRQ,
172 CHGFAIL_IRQ,
173 CHGSTATE_IRQ,
174 LOOP_CHANGE_IRQ,
175 FASTCHG_IRQ,
176 TRKLCHG_IRQ,
177 BATT_REMOVED_IRQ,
178 BATTTEMP_HOT_IRQ,
179 CHGHOT_IRQ,
180 BATTTEMP_COLD_IRQ,
181 CHG_GONE_IRQ,
182 BAT_TEMP_OK_IRQ,
183 COARSE_DET_LOW_IRQ,
184 VDD_LOOP_IRQ,
185 VREG_OV_IRQ,
186 VBATDET_IRQ,
187 BATFET_IRQ,
188 PSI_IRQ,
189 DCIN_VALID_IRQ,
190 DCIN_OV_IRQ,
191 DCIN_UV_IRQ,
192 PM_CHG_MAX_INTS,
193};
194
195struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700196 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 int is_charging;
198 struct work_struct work;
199};
200
201/**
202 * struct pm8921_chg_chip -device information
203 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 * @usb_present: present status of usb
205 * @dc_present: present status of dc
206 * @usb_charger_current: usb current to charge the battery with used when
207 * the usb path is enabled or charging is resumed
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800209 * @max_voltage_mv: the max volts the batt should be charged up to
210 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700211 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700212 * @alarm_low_mv: the battery alarm voltage low
213 * @alarm_high_mv: the battery alarm voltage high
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800214 * @cool_temp_dc: the cool temp threshold in deciCelcius
215 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700216 * @resume_voltage_delta: the voltage delta from vdd max at which the
217 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 * @term_current: The charging based term current
219 *
220 */
221struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700222 struct device *dev;
223 unsigned int usb_present;
224 unsigned int dc_present;
225 unsigned int usb_charger_current;
226 unsigned int max_bat_chg_current;
227 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700228 unsigned int ttrkl_time;
229 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800230 unsigned int max_voltage_mv;
231 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700232 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700233 unsigned int safe_current_ma;
234 unsigned int alarm_low_mv;
235 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800236 int cool_temp_dc;
237 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700238 unsigned int temp_check_period;
239 unsigned int cool_bat_chg_current;
240 unsigned int warm_bat_chg_current;
241 unsigned int cool_bat_voltage;
242 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700243 unsigned int is_bat_cool;
244 unsigned int is_bat_warm;
245 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700246 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 unsigned int term_current;
248 unsigned int vbat_channel;
249 unsigned int batt_temp_channel;
250 unsigned int batt_id_channel;
251 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800252 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800253 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700254 struct power_supply batt_psy;
255 struct dentry *dent;
256 struct bms_notify bms_notify;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700257 int *usb_trim_table;
258 struct regulator *vreg_xoadc;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200259 bool ext_charging;
260 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700261 bool iusb_fine_res;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700262 bool final_kickstart;
263 bool lockup_lpm_wrkarnd;
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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298};
299
David Keitelacf57c82012-03-07 18:48:50 -0800300/* user space parameter to limit usb current */
301static unsigned int usb_max_current;
302/*
303 * usb_target_ma is used for wall charger
304 * adaptive input current limiting only. Use
305 * pm_iusbmax_get() to get current maximum usb current setting.
306 */
307static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700309static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310
311static struct pm8921_chg_chip *the_chip;
312
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700313static DEFINE_SPINLOCK(lpm_lock);
314#define LPM_ENABLE_BIT BIT(2)
315static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
316{
317 int rc;
318 u8 reg;
319
320 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
321 if (rc) {
322 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
323 CHG_CNTRL, rc);
324 return rc;
325 }
326 reg &= ~LPM_ENABLE_BIT;
327 reg |= (enable ? LPM_ENABLE_BIT : 0);
328
329 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
330 if (rc) {
331 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
332 CHG_CNTRL, rc);
333 return rc;
334 }
335
336 return rc;
337}
338
339static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
340{
341 int rc;
342 unsigned long flags = 0;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800343 u8 temp;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700344
345 /* Disable LPM */
346 if (chip->lockup_lpm_wrkarnd) {
347 spin_lock_irqsave(&lpm_lock, flags);
348
349 /*
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800350 * This delay is to prevent exit out of 32khz mode within
351 * 200uS. It could be that chg was removed just few uS before
352 * this gets called.
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700353 */
354 udelay(200);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800355 /* no clks */
356 temp = 0xD1;
357 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
358 if (rc) {
359 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
360 goto release_lpm_lock;
361 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700362
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800363 /* force 19.2Mhz before reading */
364 temp = 0xD3;
365 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
366 if (rc) {
367 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
368 goto release_lpm_lock;
369 }
370
371 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
372 if (rc) {
373 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
374 goto release_lpm_lock;
375 }
376
377 /* no clks */
378 temp = 0xD1;
379 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
380 if (rc) {
381 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
382 goto release_lpm_lock;
383 }
384
385 /* switch to hw clk selection */
386 temp = 0xD0;
387 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
388 if (rc) {
389 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
390 goto release_lpm_lock;
391 }
392
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700393 udelay(200);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700394
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800395release_lpm_lock:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700396 spin_unlock_irqrestore(&lpm_lock, flags);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800397 } else {
398 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
399 if (rc)
400 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
401 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700402 return rc;
403}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
406 u8 mask, u8 val)
407{
408 int rc;
409 u8 reg;
410
411 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
412 if (rc) {
413 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
414 return rc;
415 }
416 reg &= ~mask;
417 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700418 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700420 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 return rc;
422 }
423 return 0;
424}
425
David Keitelcf867232012-01-27 18:40:12 -0800426static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
427{
428 return pm8xxx_read_irq_stat(chip->dev->parent,
429 chip->pmic_chg_irq[irq_id]);
430}
431
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700432static int is_chg_on_bat(struct pm8921_chg_chip *chip)
433{
434 return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
435 || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
436}
437
438static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
439 int bypass)
440{
441 int rc;
442
443 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
444 if (rc) {
445 pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
446 }
447}
448
David Keitelcf867232012-01-27 18:40:12 -0800449/* Treat OverVoltage/UnderVoltage as source missing */
450static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
451{
452 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
453}
454
455/* Treat OverVoltage/UnderVoltage as source missing */
456static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
457{
458 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
459}
460
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700461static int is_batfet_closed(struct pm8921_chg_chip *chip)
462{
463 return pm_chg_get_rt_status(chip, BATFET_IRQ);
464}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465#define CAPTURE_FSM_STATE_CMD 0xC2
466#define READ_BANK_7 0x70
467#define READ_BANK_4 0x40
468static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
469{
470 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800471 unsigned long flags = 0;
472 int err = 0, ret = 0;
473
474 if (chip->lockup_lpm_wrkarnd) {
475 spin_lock_irqsave(&lpm_lock, flags);
476
477 /*
478 * This delay is to prevent exit out of 32khz mode within
479 * 200uS. It could be that chg was removed just few uS before
480 * this gets called.
481 */
482 udelay(200);
483 /* no clks */
484 temp = 0xD1;
485 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
486 if (err) {
487 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
488 goto err_out;
489 }
490
491 /* force 19.2Mhz before reading */
492 temp = 0xD3;
493 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
494 if (err) {
495 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
496 goto err_out;
497 }
498 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499
500 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800501 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 if (err) {
503 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800504 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505 }
506
507 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800508 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 if (err) {
510 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800511 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 }
513
514 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
515 if (err) {
516 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800517 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 }
519 /* get the lower 4 bits */
520 ret = temp & 0xF;
521
522 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800523 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524 if (err) {
525 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800526 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 }
528
529 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
530 if (err) {
531 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800532 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533 }
534 /* get the upper 1 bit */
535 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800536
537 if (chip->lockup_lpm_wrkarnd) {
538 /* no clks */
539 temp = 0xD1;
540 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
541 if (err) {
542 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
543 goto err_out;
544 }
545
546 /* switch to hw clk selection */
547 temp = 0xD0;
548 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
549 if (err) {
550 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
551 goto err_out;
552 }
553
554 udelay(200);
555 }
556
557err_out:
558 if (chip->lockup_lpm_wrkarnd)
559 spin_unlock_irqrestore(&lpm_lock, flags);
560 if (err)
561 return err;
562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 return ret;
564}
565
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700566#define READ_BANK_6 0x60
567static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
568{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800569 u8 temp, data;
570 unsigned long flags = 0;
571 int err = 0;
572
573 if (chip->lockup_lpm_wrkarnd) {
574 spin_lock_irqsave(&lpm_lock, flags);
575
576 /*
577 * This delay is to prevent exit out of 32khz mode within
578 * 200uS. It could be that chg was removed just few uS before
579 * this gets called.
580 */
581 udelay(200);
582 /* no clks */
583 temp = 0xD1;
584 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
585 if (err) {
586 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
587 goto err_out;
588 }
589
590 /* force 19.2Mhz before reading */
591 temp = 0xD3;
592 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
593 if (err) {
594 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
595 goto err_out;
596 }
597 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700598
599 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800600 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700601 if (err) {
602 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800603 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700604 }
605
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800606 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700607 if (err) {
608 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800609 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700610 }
611
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800612 if (chip->lockup_lpm_wrkarnd) {
613 /* no clks */
614 temp = 0xD1;
615 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
616 if (err) {
617 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
618 goto err_out;
619 }
620
621 /* switch to hw clk selection */
622 temp = 0xD0;
623 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
624 if (err) {
625 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
626 goto err_out;
627 }
628
629 udelay(200);
630 }
631
632err_out:
633 if (chip->lockup_lpm_wrkarnd)
634 spin_unlock_irqrestore(&lpm_lock, flags);
635 if (err)
636 return err;
637
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700638 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800639 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700640}
641
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642#define CHG_USB_SUSPEND_BIT BIT(2)
643static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
644{
645 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
646 enable ? CHG_USB_SUSPEND_BIT : 0);
647}
648
649#define CHG_EN_BIT BIT(7)
650static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
651{
652 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
653 enable ? CHG_EN_BIT : 0);
654}
655
David Keitel753ec8d2011-11-02 10:56:37 -0700656#define CHG_FAILED_CLEAR BIT(0)
657#define ATC_FAILED_CLEAR BIT(1)
658static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
659{
660 int rc;
661
662 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
663 clear ? ATC_FAILED_CLEAR : 0);
664 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
665 clear ? CHG_FAILED_CLEAR : 0);
666 return rc;
667}
668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669#define CHG_CHARGE_DIS_BIT BIT(1)
670static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
671{
672 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
673 disable ? CHG_CHARGE_DIS_BIT : 0);
674}
675
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800676static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
677{
678 u8 temp;
679
680 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
681 return temp & CHG_CHARGE_DIS_BIT;
682}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683#define PM8921_CHG_V_MIN_MV 3240
684#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800685#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686#define PM8921_CHG_VDDMAX_MAX 4500
687#define PM8921_CHG_VDDMAX_MIN 3400
688#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800689static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800691 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800692 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700693
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800694 if (voltage < PM8921_CHG_VDDMAX_MIN
695 || voltage > PM8921_CHG_VDDMAX_MAX) {
696 pr_err("bad mV=%d asked to set\n", voltage);
697 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700698 }
David Keitelcf867232012-01-27 18:40:12 -0800699
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800700 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
701
702 remainder = voltage % 20;
703 if (remainder >= 10) {
704 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
705 }
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700708 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709}
710
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700711static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
712{
713 u8 temp;
714 int rc;
715
716 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
717 if (rc) {
718 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700719 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700720 return rc;
721 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800722 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
723 + PM8921_CHG_V_MIN_MV;
724 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
725 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700726 return 0;
727}
728
David Keitelcf867232012-01-27 18:40:12 -0800729static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
730{
731 int current_mv, ret, steps, i;
732 bool increase;
733
734 ret = 0;
735
736 if (voltage < PM8921_CHG_VDDMAX_MIN
737 || voltage > PM8921_CHG_VDDMAX_MAX) {
738 pr_err("bad mV=%d asked to set\n", voltage);
739 return -EINVAL;
740 }
741
742 ret = pm_chg_vddmax_get(chip, &current_mv);
743 if (ret) {
744 pr_err("Failed to read vddmax rc=%d\n", ret);
745 return -EINVAL;
746 }
747 if (current_mv == voltage)
748 return 0;
749
750 /* Only change in increments when USB is present */
751 if (is_usb_chg_plugged_in(chip)) {
752 if (current_mv < voltage) {
753 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
754 increase = true;
755 } else {
756 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
757 increase = false;
758 }
759 for (i = 0; i < steps; i++) {
760 if (increase)
761 current_mv += PM8921_CHG_V_STEP_MV;
762 else
763 current_mv -= PM8921_CHG_V_STEP_MV;
764 ret |= __pm_chg_vddmax_set(chip, current_mv);
765 }
766 }
767 ret |= __pm_chg_vddmax_set(chip, voltage);
768 return ret;
769}
770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771#define PM8921_CHG_VDDSAFE_MIN 3400
772#define PM8921_CHG_VDDSAFE_MAX 4500
773static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
774{
775 u8 temp;
776
777 if (voltage < PM8921_CHG_VDDSAFE_MIN
778 || voltage > PM8921_CHG_VDDSAFE_MAX) {
779 pr_err("bad mV=%d asked to set\n", voltage);
780 return -EINVAL;
781 }
782 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
783 pr_debug("voltage=%d setting %02x\n", voltage, temp);
784 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
785}
786
787#define PM8921_CHG_VBATDET_MIN 3240
788#define PM8921_CHG_VBATDET_MAX 5780
789static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
790{
791 u8 temp;
792
793 if (voltage < PM8921_CHG_VBATDET_MIN
794 || voltage > PM8921_CHG_VBATDET_MAX) {
795 pr_err("bad mV=%d asked to set\n", voltage);
796 return -EINVAL;
797 }
798 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
799 pr_debug("voltage=%d setting %02x\n", voltage, temp);
800 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
801}
802
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700803#define PM8921_CHG_VINMIN_MIN_MV 3800
804#define PM8921_CHG_VINMIN_STEP_MV 100
805#define PM8921_CHG_VINMIN_USABLE_MAX 6500
806#define PM8921_CHG_VINMIN_USABLE_MIN 4300
807#define PM8921_CHG_VINMIN_MASK 0x1F
808static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
809{
810 u8 temp;
811
812 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
813 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
814 pr_err("bad mV=%d asked to set\n", voltage);
815 return -EINVAL;
816 }
817 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
818 pr_debug("voltage=%d setting %02x\n", voltage, temp);
819 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
820 temp);
821}
822
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800823static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
824{
825 u8 temp;
826 int rc, voltage_mv;
827
828 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
829 temp &= PM8921_CHG_VINMIN_MASK;
830
831 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
832 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
833
834 return voltage_mv;
835}
836
David Keitel0789fc62012-06-07 17:43:27 -0700837#define PM8917_USB_UVD_MIN_MV 3850
838#define PM8917_USB_UVD_MAX_MV 4350
839#define PM8917_USB_UVD_STEP_MV 100
840#define PM8917_USB_UVD_MASK 0x7
841static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
842{
843 u8 temp;
844
845 if (thresh_mv < PM8917_USB_UVD_MIN_MV
846 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
847 pr_err("bad mV=%d asked to set\n", thresh_mv);
848 return -EINVAL;
849 }
850 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
851 return pm_chg_masked_write(chip, OVP_USB_UVD,
852 PM8917_USB_UVD_MASK, temp);
853}
854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700856#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857#define PM8921_CHG_I_MIN_MA 225
858#define PM8921_CHG_I_STEP_MA 50
859#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700860static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
861{
862 u8 temp;
863 int rc;
864
865 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
866 if (rc) {
867 pr_err("rc = %d while reading ibat max\n", rc);
868 *ibat_ma = 0;
869 return rc;
870 }
871 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
872 + PM8921_CHG_I_MIN_MA;
873 return 0;
874}
875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
877{
878 u8 temp;
879
880 if (chg_current < PM8921_CHG_IBATMAX_MIN
881 || chg_current > PM8921_CHG_IBATMAX_MAX) {
882 pr_err("bad mA=%d asked to set\n", chg_current);
883 return -EINVAL;
884 }
885 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
886 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
887}
888
889#define PM8921_CHG_IBATSAFE_MIN 225
890#define PM8921_CHG_IBATSAFE_MAX 3375
891static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
892{
893 u8 temp;
894
895 if (chg_current < PM8921_CHG_IBATSAFE_MIN
896 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
897 pr_err("bad mA=%d asked to set\n", chg_current);
898 return -EINVAL;
899 }
900 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
901 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
902 PM8921_CHG_I_MASK, temp);
903}
904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700906#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907#define PM8921_CHG_ITERM_STEP_MA 10
908#define PM8921_CHG_ITERM_MASK 0xF
909static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
910{
911 u8 temp;
912
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700913 if (chg_current < PM8921_CHG_ITERM_MIN_MA
914 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 pr_err("bad mA=%d asked to set\n", chg_current);
916 return -EINVAL;
917 }
918
919 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
920 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700921 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922 temp);
923}
924
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700925static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
926{
927 u8 temp;
928 int rc;
929
930 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
931 if (rc) {
932 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700933 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700934 return rc;
935 }
936 temp &= PM8921_CHG_ITERM_MASK;
937 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
938 + PM8921_CHG_ITERM_MIN_MA;
939 return 0;
940}
941
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800942struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700943 int usb_ma;
944 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800945};
946
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700947/* USB Trim tables */
948static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
949 0x0,
950 0x0,
951 -0x9,
952 0x0,
953 -0xD,
954 0x0,
955 -0x10,
956 -0x11,
957 0x0,
958 0x0,
959 -0x25,
960 0x0,
961 -0x28,
962 0x0,
963 -0x32,
964 0x0
965};
966
967static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
968 0x0,
969 0x0,
970 0xA,
971 0xC,
972 0x10,
973 0x10,
974 0x13,
975 0x14,
976 0x13,
977 0x3,
978 0x1A,
979 0x1D,
980 0x1D,
981 0x21,
982 0x24,
983 0x26
984};
985
986/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800987static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700988 {100, 0x0},
989 {200, 0x1},
990 {500, 0x2},
991 {600, 0x3},
992 {700, 0x4},
993 {800, 0x5},
994 {850, 0x6},
995 {900, 0x8},
996 {950, 0x7},
997 {1000, 0x9},
998 {1100, 0xA},
999 {1200, 0xB},
1000 {1300, 0xC},
1001 {1400, 0xD},
1002 {1500, 0xE},
1003 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001004};
1005
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001006#define REG_SBI_CONFIG 0x04F
1007#define PAGE3_ENABLE_MASK 0x6
1008#define USB_OVP_TRIM_MASK 0x3F
1009#define USB_OVP_TRIM_PM8917_MASK 0x7F
1010#define USB_OVP_TRIM_MIN 0x00
1011#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
1012#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
1013#define REG_USB_OVP_TRIM_PM8917 0x2B5
1014#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
1015static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
1016{
1017 u8 temp, sbi_config, msb, lsb, mask;
1018 s8 trim;
1019 int rc = 0;
1020 static u8 usb_trim_reg_orig = 0xFF;
1021
1022 /* No trim data for PM8921 */
1023 if (!chip->usb_trim_table)
1024 return 0;
1025
1026 if (usb_trim_reg_orig == 0xFF) {
1027 rc = pm8xxx_readb(chip->dev->parent,
1028 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
1029 if (rc) {
1030 pr_err("error = %d reading sbi config reg\n", rc);
1031 return rc;
1032 }
1033
1034 rc = pm8xxx_readb(chip->dev->parent,
1035 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
1036 if (rc) {
1037 pr_err("error = %d reading sbi config reg\n", rc);
1038 return rc;
1039 }
1040
1041 msb = msb >> 5;
1042 lsb = lsb >> 5;
1043 usb_trim_reg_orig = msb << 3 | lsb;
1044
1045 if (pm8xxx_get_version(chip->dev->parent)
1046 == PM8XXX_VERSION_8917) {
1047 rc = pm8xxx_readb(chip->dev->parent,
1048 REG_USB_OVP_TRIM_PM8917, &msb);
1049 if (rc) {
1050 pr_err("error = %d reading config reg\n", rc);
1051 return rc;
1052 }
1053
1054 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
1055 usb_trim_reg_orig |= msb << 6;
1056 }
1057 }
1058
1059 /* use the original trim value */
1060 trim = usb_trim_reg_orig;
1061
1062 trim += chip->usb_trim_table[index];
1063 if (trim < 0)
1064 trim = 0;
1065
1066 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
1067 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
1068
1069 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
1070 if (rc) {
1071 pr_err("error = %d reading sbi config reg\n", rc);
1072 return rc;
1073 }
1074
1075 temp = sbi_config | PAGE3_ENABLE_MASK;
1076 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
1077 if (rc) {
1078 pr_err("error = %d writing sbi config reg\n", rc);
1079 return rc;
1080 }
1081
1082 mask = USB_OVP_TRIM_MASK;
1083
1084 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
1085 mask = USB_OVP_TRIM_PM8917_MASK;
1086
1087 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
1088 if (rc) {
1089 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
1090 return rc;
1091 }
1092
1093 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
1094 if (rc) {
1095 pr_err("error = %d writing sbi config reg\n", rc);
1096 return rc;
1097 }
1098 return rc;
1099}
1100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -07001102#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103#define PM8921_CHG_IUSB_MAX 7
1104#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -07001105#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001106static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001108 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -07001109 int rc;
1110
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001111 reg_val = usb_ma_table[index].value >> 1;
1112 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001114 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
1115 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 return -EINVAL;
1117 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001118 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
1119
1120 /* IUSB_FINE_RES */
1121 if (chip->iusb_fine_res) {
1122 /* Clear IUSB_FINE_RES bit to avoid overshoot */
1123 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1124 PM8917_IUSB_FINE_RES, 0);
1125
1126 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
1127 PM8921_CHG_IUSB_MASK, temp);
1128
1129 if (rc) {
1130 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
1131 return rc;
1132 }
1133
1134 if (fineres) {
1135 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1136 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001137 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001138 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
1139 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001140 return rc;
1141 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001142 }
1143 } else {
1144 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
1145 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001146 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001147 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001148 return rc;
1149 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001150 }
1151
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001152 rc = pm_chg_usb_trim(chip, index);
1153 if (rc)
1154 pr_err("unable to set usb trim rc = %d\n", rc);
1155
David Keitel38bdd4f2012-04-19 15:39:13 -07001156 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157}
1158
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001159static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
1160{
David Keitel38bdd4f2012-04-19 15:39:13 -07001161 u8 temp, fineres;
1162 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001163
David Keitel38bdd4f2012-04-19 15:39:13 -07001164 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001165 *mA = 0;
1166 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
1167 if (rc) {
1168 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1169 return rc;
1170 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001171
1172 if (chip->iusb_fine_res) {
1173 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1174 if (rc) {
1175 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1176 return rc;
1177 }
1178 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001179 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001180 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1181
1182 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1183 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1184 if (usb_ma_table[i].value == temp)
1185 break;
1186 }
1187
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001188 if (i < 0) {
1189 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1190 i = 0;
1191 }
1192
Willie Ruan13c972d2012-11-15 11:56:36 -08001193 if (i < 0) {
1194 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1195 i = 0;
1196 }
1197
David Keitel38bdd4f2012-04-19 15:39:13 -07001198 *mA = usb_ma_table[i].usb_ma;
1199
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001200 return rc;
1201}
1202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203#define PM8921_CHG_WD_MASK 0x1F
1204static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1205{
1206 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001207 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1208}
1209
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001210#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001211#define PM8921_CHG_TCHG_MIN 4
1212#define PM8921_CHG_TCHG_MAX 512
1213#define PM8921_CHG_TCHG_STEP 4
1214static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1215{
1216 u8 temp;
1217
1218 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1219 pr_err("bad max minutes =%d asked to set\n", minutes);
1220 return -EINVAL;
1221 }
1222
1223 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1224 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1225 temp);
1226}
1227
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001228#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001229#define PM8921_CHG_TTRKL_MIN 1
1230#define PM8921_CHG_TTRKL_MAX 64
1231static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1232{
1233 u8 temp;
1234
1235 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1236 pr_err("bad max minutes =%d asked to set\n", minutes);
1237 return -EINVAL;
1238 }
1239
1240 temp = minutes - 1;
1241 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1242 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243}
1244
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001245#define PM8921_CHG_VTRKL_MIN_MV 2050
1246#define PM8921_CHG_VTRKL_MAX_MV 2800
1247#define PM8921_CHG_VTRKL_STEP_MV 50
1248#define PM8921_CHG_VTRKL_SHIFT 4
1249#define PM8921_CHG_VTRKL_MASK 0xF0
1250static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1251{
1252 u8 temp;
1253
1254 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1255 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1256 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1257 return -EINVAL;
1258 }
1259
1260 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1261 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1262 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1263 temp);
1264}
1265
1266#define PM8921_CHG_VWEAK_MIN_MV 2100
1267#define PM8921_CHG_VWEAK_MAX_MV 3600
1268#define PM8921_CHG_VWEAK_STEP_MV 100
1269#define PM8921_CHG_VWEAK_MASK 0x0F
1270static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1271{
1272 u8 temp;
1273
1274 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1275 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1276 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1277 return -EINVAL;
1278 }
1279
1280 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1281 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1282 temp);
1283}
1284
1285#define PM8921_CHG_ITRKL_MIN_MA 50
1286#define PM8921_CHG_ITRKL_MAX_MA 200
1287#define PM8921_CHG_ITRKL_MASK 0x0F
1288#define PM8921_CHG_ITRKL_STEP_MA 10
1289static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1290{
1291 u8 temp;
1292
1293 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1294 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1295 pr_err("bad current = %dmA asked to set\n", milliamps);
1296 return -EINVAL;
1297 }
1298
1299 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1300
1301 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1302 temp);
1303}
1304
1305#define PM8921_CHG_IWEAK_MIN_MA 325
1306#define PM8921_CHG_IWEAK_MAX_MA 525
1307#define PM8921_CHG_IWEAK_SHIFT 7
1308#define PM8921_CHG_IWEAK_MASK 0x80
1309static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1310{
1311 u8 temp;
1312
1313 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1314 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1315 pr_err("bad current = %dmA asked to set\n", milliamps);
1316 return -EINVAL;
1317 }
1318
1319 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1320 temp = 0;
1321 else
1322 temp = 1;
1323
1324 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1325 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1326 temp);
1327}
1328
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001329#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1330#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1331static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1332 enum pm8921_chg_cold_thr cold_thr)
1333{
1334 u8 temp;
1335
1336 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1337 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1338 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1339 PM8921_CHG_BATT_TEMP_THR_COLD,
1340 temp);
1341}
1342
1343#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1344#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1345static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1346 enum pm8921_chg_hot_thr hot_thr)
1347{
1348 u8 temp;
1349
1350 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1351 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1352 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1353 PM8921_CHG_BATT_TEMP_THR_HOT,
1354 temp);
1355}
1356
Jay Chokshid674a512012-03-15 14:06:04 -07001357#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1358#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1359static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1360 enum pm8921_chg_led_src_config led_src_config)
1361{
1362 u8 temp;
1363
1364 if (led_src_config < LED_SRC_GND ||
1365 led_src_config > LED_SRC_BYPASS)
1366 return -EINVAL;
1367
1368 if (led_src_config == LED_SRC_BYPASS)
1369 return 0;
1370
1371 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1372
1373 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1374 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1375}
1376
David Keitel8c5201a2012-02-24 16:08:54 -08001377
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001378static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1379{
1380 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001381 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001382
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001383 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001384 if (rc) {
1385 pr_err("error reading batt id channel = %d, rc = %d\n",
1386 chip->vbat_channel, rc);
1387 return rc;
1388 }
1389 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1390 result.measurement);
1391 return result.physical;
1392}
1393
1394static int is_battery_valid(struct pm8921_chg_chip *chip)
1395{
1396 int64_t rc;
1397
1398 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1399 return 1;
1400
1401 rc = read_battery_id(chip);
1402 if (rc < 0) {
1403 pr_err("error reading batt id channel = %d, rc = %lld\n",
1404 chip->vbat_channel, rc);
1405 /* assume battery id is valid when adc error happens */
1406 return 1;
1407 }
1408
1409 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1410 pr_err("batt_id phy =%lld is not valid\n", rc);
1411 return 0;
1412 }
1413 return 1;
1414}
1415
1416static void check_battery_valid(struct pm8921_chg_chip *chip)
1417{
1418 if (is_battery_valid(chip) == 0) {
1419 pr_err("batt_id not valid, disbling charging\n");
1420 pm_chg_auto_enable(chip, 0);
1421 } else {
1422 pm_chg_auto_enable(chip, !charging_disabled);
1423 }
1424}
1425
1426static void battery_id_valid(struct work_struct *work)
1427{
1428 struct pm8921_chg_chip *chip = container_of(work,
1429 struct pm8921_chg_chip, battery_id_valid_work);
1430
1431 check_battery_valid(chip);
1432}
1433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1435{
1436 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1437 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1438 enable_irq(chip->pmic_chg_irq[interrupt]);
1439 }
1440}
1441
1442static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1443{
1444 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1445 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1446 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1447 }
1448}
1449
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001450static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1451{
1452 return test_bit(interrupt, chip->enabled_irqs);
1453}
1454
Amir Samuelovd31ef502011-10-26 14:41:36 +02001455static bool is_ext_charging(struct pm8921_chg_chip *chip)
1456{
David Keitel88e1b572012-01-11 11:57:14 -08001457 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001458
David Keitel88e1b572012-01-11 11:57:14 -08001459 if (!chip->ext_psy)
1460 return false;
1461 if (chip->ext_psy->get_property(chip->ext_psy,
1462 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1463 return false;
1464 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1465 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001466
1467 return false;
1468}
1469
1470static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1471{
David Keitel88e1b572012-01-11 11:57:14 -08001472 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001473
David Keitel88e1b572012-01-11 11:57:14 -08001474 if (!chip->ext_psy)
1475 return false;
1476 if (chip->ext_psy->get_property(chip->ext_psy,
1477 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1478 return false;
1479 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001480 return true;
1481
1482 return false;
1483}
1484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485static int is_battery_charging(int fsm_state)
1486{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001487 if (is_ext_charging(the_chip))
1488 return 1;
1489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 switch (fsm_state) {
1491 case FSM_STATE_ATC_2A:
1492 case FSM_STATE_ATC_2B:
1493 case FSM_STATE_ON_CHG_AND_BAT_6:
1494 case FSM_STATE_FAST_CHG_7:
1495 case FSM_STATE_TRKL_CHG_8:
1496 return 1;
1497 }
1498 return 0;
1499}
1500
1501static void bms_notify(struct work_struct *work)
1502{
1503 struct bms_notify *n = container_of(work, struct bms_notify, work);
1504
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001505 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001507 } else {
1508 pm8921_bms_charging_end(n->is_battery_full);
1509 n->is_battery_full = 0;
1510 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511}
1512
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001513static void bms_notify_check(struct pm8921_chg_chip *chip)
1514{
1515 int fsm_state, new_is_charging;
1516
1517 fsm_state = pm_chg_get_fsm_state(chip);
1518 new_is_charging = is_battery_charging(fsm_state);
1519
1520 if (chip->bms_notify.is_charging ^ new_is_charging) {
1521 chip->bms_notify.is_charging = new_is_charging;
1522 schedule_work(&(chip->bms_notify.work));
1523 }
1524}
1525
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001526static enum power_supply_property pm_power_props_usb[] = {
1527 POWER_SUPPLY_PROP_PRESENT,
1528 POWER_SUPPLY_PROP_ONLINE,
1529 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001530 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001531 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001532};
1533
1534static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001536 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537};
1538
1539static char *pm_power_supplied_to[] = {
1540 "battery",
1541};
1542
David Keitel6ed71a52012-01-30 12:42:18 -08001543#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001544static int pm_power_get_property_mains(struct power_supply *psy,
1545 enum power_supply_property psp,
1546 union power_supply_propval *val)
1547{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001548 int type;
1549
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001550 /* Check if called before init */
1551 if (!the_chip)
1552 return -EINVAL;
1553
1554 switch (psp) {
1555 case POWER_SUPPLY_PROP_PRESENT:
1556 case POWER_SUPPLY_PROP_ONLINE:
1557 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001558
1559 if (the_chip->has_dc_supply) {
1560 val->intval = 1;
1561 return 0;
1562 }
1563
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001564 if (the_chip->dc_present) {
1565 val->intval = 1;
1566 return 0;
1567 }
1568
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001569 type = the_chip->usb_psy.type;
1570 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1571 type == POWER_SUPPLY_TYPE_USB_ACA ||
1572 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001573 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001574
1575 break;
1576 default:
1577 return -EINVAL;
1578 }
1579 return 0;
1580}
1581
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001582static int disable_aicl(int disable)
1583{
1584 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1585 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1586 pr_err("called with invalid param :%d\n", disable);
1587 return -EINVAL;
1588 }
1589
1590 if (!the_chip) {
1591 pr_err("%s called before init\n", __func__);
1592 return -EINVAL;
1593 }
1594
1595 pr_debug("Disable AICL = %d\n", disable);
1596 the_chip->disable_aicl = disable;
1597 return 0;
1598}
1599
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001600static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1601{
1602 int rc;
1603
1604 if (!chip->host_mode)
1605 return 0;
1606
1607 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001608 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001609 if (rc < 0) {
1610 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1611 return rc;
1612 }
1613
1614 chip->host_mode = 0;
1615
1616 return 0;
1617}
1618
1619static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1620{
1621 int rc;
1622
1623 if (chip->host_mode)
1624 return 0;
1625
1626 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001627 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001628 if (rc < 0) {
1629 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1630 return rc;
1631 }
1632
1633 chip->host_mode = 1;
1634
1635 return 0;
1636}
1637
1638static int pm_power_set_property_usb(struct power_supply *psy,
1639 enum power_supply_property psp,
1640 const union power_supply_propval *val)
1641{
1642 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001643 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001644 return -EINVAL;
1645
1646 switch (psp) {
1647 case POWER_SUPPLY_PROP_SCOPE:
1648 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001649 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001650 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001651 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001652 else
1653 return -EINVAL;
1654 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001655 case POWER_SUPPLY_PROP_TYPE:
1656 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001657 case POWER_SUPPLY_PROP_HEALTH:
1658 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1659 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001660 default:
1661 return -EINVAL;
1662 }
1663 return 0;
1664}
1665
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001666static int usb_property_is_writeable(struct power_supply *psy,
1667 enum power_supply_property psp)
1668{
1669 switch (psp) {
1670 case POWER_SUPPLY_PROP_HEALTH:
1671 return 1;
1672 default:
1673 break;
1674 }
1675
1676 return 0;
1677}
1678
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001679static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 enum power_supply_property psp,
1681 union power_supply_propval *val)
1682{
David Keitel6ed71a52012-01-30 12:42:18 -08001683 int current_max;
1684
1685 /* Check if called before init */
1686 if (!the_chip)
1687 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688
1689 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001690 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001691 if (pm_is_chg_charge_dis(the_chip)) {
1692 val->intval = 0;
1693 } else {
1694 pm_chg_iusbmax_get(the_chip, &current_max);
1695 val->intval = current_max;
1696 }
David Keitel6ed71a52012-01-30 12:42:18 -08001697 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001699 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001700 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001701
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001702 if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001703 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001706
1707 case POWER_SUPPLY_PROP_SCOPE:
1708 if (the_chip->host_mode)
1709 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1710 else
1711 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1712 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001713 case POWER_SUPPLY_PROP_HEALTH:
1714 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1715 val->intval = the_chip->disable_aicl;
1716 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 default:
1718 return -EINVAL;
1719 }
1720 return 0;
1721}
1722
1723static enum power_supply_property msm_batt_power_props[] = {
1724 POWER_SUPPLY_PROP_STATUS,
1725 POWER_SUPPLY_PROP_CHARGE_TYPE,
1726 POWER_SUPPLY_PROP_HEALTH,
1727 POWER_SUPPLY_PROP_PRESENT,
1728 POWER_SUPPLY_PROP_TECHNOLOGY,
1729 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1730 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1731 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1732 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001733 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001734 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001735 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001736 POWER_SUPPLY_PROP_CHARGE_FULL,
1737 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738};
1739
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001740static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001741{
1742 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001743 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001745 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 if (rc) {
1747 pr_err("error reading adc channel = %d, rc = %d\n",
1748 chip->vbat_channel, rc);
1749 return rc;
1750 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001751 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 result.measurement);
1753 return (int)result.physical;
1754}
1755
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001756static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1757{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001758 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1759 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1760 unsigned int low_voltage = chip->min_voltage_mv;
1761 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001762
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001763 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001764 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001765 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001766 return 100;
1767 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001768 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001769 / (high_voltage - low_voltage);
1770}
1771
David Keitel4f9397b2012-04-16 11:46:16 -07001772static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1773{
1774 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1775}
1776
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001777static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1778{
1779 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1780 int fsm_state = pm_chg_get_fsm_state(chip);
1781 int i;
1782
1783 if (chip->ext_psy) {
1784 if (chip->ext_charge_done)
1785 return POWER_SUPPLY_STATUS_FULL;
1786 if (chip->ext_charging)
1787 return POWER_SUPPLY_STATUS_CHARGING;
1788 }
1789
1790 for (i = 0; i < ARRAY_SIZE(map); i++)
1791 if (map[i].fsm_state == fsm_state)
1792 batt_state = map[i].batt_state;
1793
1794 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1795 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1796 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1797 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1798 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1799
1800 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1801 }
1802 return batt_state;
1803}
1804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1806{
David Keitel4f9397b2012-04-16 11:46:16 -07001807 int percent_soc;
1808
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001809 if (chip->battery_less_hardware)
1810 return 100;
1811
David Keitel4f9397b2012-04-16 11:46:16 -07001812 if (!get_prop_batt_present(chip))
1813 percent_soc = voltage_based_capacity(chip);
1814 else
1815 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001816
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001817 if (percent_soc == -ENXIO)
1818 percent_soc = voltage_based_capacity(chip);
1819
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001820 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001821 pr_warn_ratelimited("low battery charge = %d%%\n",
1822 percent_soc);
1823
1824 if (percent_soc <= chip->resume_charge_percent
1825 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1826 pr_debug("soc fell below %d. charging enabled.\n",
1827 chip->resume_charge_percent);
1828 if (chip->is_bat_warm)
1829 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1830 chip->is_bat_warm,
1831 chip->resume_charge_percent);
1832 else if (chip->is_bat_cool)
1833 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1834 chip->is_bat_cool,
1835 chip->resume_charge_percent);
1836 else
1837 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1838 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001839
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001840 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001841 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842}
1843
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001844static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1845{
1846 return pm8921_bms_get_current_max();
1847}
1848
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001849static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1850{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001851 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001852
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001853 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001854 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001855 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001856 }
1857
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001858 if (rc) {
1859 pr_err("unable to get batt current rc = %d\n", rc);
1860 return rc;
1861 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001862 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001863 }
1864}
1865
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001866static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1867{
1868 int rc;
1869
1870 rc = pm8921_bms_get_fcc();
1871 if (rc < 0)
1872 pr_err("unable to get batt fcc rc = %d\n", rc);
1873 return rc;
1874}
1875
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001876static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1877{
1878 int rc;
1879 int cc_uah;
1880
1881 rc = pm8921_bms_cc_uah(&cc_uah);
1882
1883 if (rc == 0)
1884 return cc_uah;
1885
1886 pr_err("unable to get batt fcc rc = %d\n", rc);
1887 return rc;
1888}
1889
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001890static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1891{
1892 int temp;
1893
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001894 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1895 if (temp)
1896 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001897
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001898 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1899 if (temp)
1900 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001901
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001902 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903}
1904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1906{
1907 int temp;
1908
Amir Samuelovd31ef502011-10-26 14:41:36 +02001909 if (!get_prop_batt_present(chip))
1910 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1911
1912 if (is_ext_trickle_charging(chip))
1913 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1914
1915 if (is_ext_charging(chip))
1916 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1919 if (temp)
1920 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1921
1922 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1923 if (temp)
1924 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1925
1926 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1927}
1928
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001929#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001930static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1931{
1932 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001933 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001934
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001935 if (chip->battery_less_hardware)
1936 return 300;
1937
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001938 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001939 if (rc) {
1940 pr_err("error reading adc channel = %d, rc = %d\n",
1941 chip->vbat_channel, rc);
1942 return rc;
1943 }
1944 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1945 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001946 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1947 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1948 (int) result.physical);
1949
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001950 return (int)result.physical;
1951}
1952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953static int pm_batt_power_get_property(struct power_supply *psy,
1954 enum power_supply_property psp,
1955 union power_supply_propval *val)
1956{
1957 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1958 batt_psy);
1959
1960 switch (psp) {
1961 case POWER_SUPPLY_PROP_STATUS:
1962 val->intval = get_prop_batt_status(chip);
1963 break;
1964 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1965 val->intval = get_prop_charge_type(chip);
1966 break;
1967 case POWER_SUPPLY_PROP_HEALTH:
1968 val->intval = get_prop_batt_health(chip);
1969 break;
1970 case POWER_SUPPLY_PROP_PRESENT:
1971 val->intval = get_prop_batt_present(chip);
1972 break;
1973 case POWER_SUPPLY_PROP_TECHNOLOGY:
1974 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1975 break;
1976 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001977 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978 break;
1979 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001980 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 break;
1982 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001983 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001984 break;
1985 case POWER_SUPPLY_PROP_CAPACITY:
1986 val->intval = get_prop_batt_capacity(chip);
1987 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001988 case POWER_SUPPLY_PROP_CURRENT_NOW:
1989 val->intval = get_prop_batt_current(chip);
1990 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001991 case POWER_SUPPLY_PROP_CURRENT_MAX:
1992 val->intval = get_prop_batt_current_max(chip);
1993 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001994 case POWER_SUPPLY_PROP_TEMP:
1995 val->intval = get_prop_batt_temp(chip);
1996 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001997 case POWER_SUPPLY_PROP_CHARGE_FULL:
1998 val->intval = get_prop_batt_fcc(chip);
1999 break;
2000 case POWER_SUPPLY_PROP_CHARGE_NOW:
2001 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07002002 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002003 default:
2004 return -EINVAL;
2005 }
2006
2007 return 0;
2008}
2009
2010static void (*notify_vbus_state_func_ptr)(int);
2011static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012
2013int pm8921_charger_register_vbus_sn(void (*callback)(int))
2014{
2015 pr_debug("%p\n", callback);
2016 notify_vbus_state_func_ptr = callback;
2017 return 0;
2018}
2019EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
2020
2021/* this is passed to the hsusb via platform_data msm_otg_pdata */
2022void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
2023{
2024 pr_debug("%p\n", callback);
2025 notify_vbus_state_func_ptr = NULL;
2026}
2027EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
2028
2029static void notify_usb_of_the_plugin_event(int plugin)
2030{
2031 plugin = !!plugin;
2032 if (notify_vbus_state_func_ptr) {
2033 pr_debug("notifying plugin\n");
2034 (*notify_vbus_state_func_ptr) (plugin);
2035 } else {
2036 pr_debug("unable to notify plugin\n");
2037 }
2038}
2039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040static void __pm8921_charger_vbus_draw(unsigned int mA)
2041{
2042 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07002043 if (!the_chip) {
2044 pr_err("called before init\n");
2045 return;
2046 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002048 if (usb_max_current && mA > usb_max_current) {
2049 pr_debug("restricting usb current to %d instead of %d\n",
2050 usb_max_current, mA);
2051 mA = usb_max_current;
2052 }
2053
2054 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002055 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08002056 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08002058 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 }
2060 rc = pm_chg_usb_suspend_enable(the_chip, 1);
2061 if (rc)
2062 pr_err("fail to set suspend bit rc=%d\n", rc);
2063 } else {
2064 rc = pm_chg_usb_suspend_enable(the_chip, 0);
2065 if (rc)
2066 pr_err("fail to reset suspend bit rc=%d\n", rc);
2067 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2068 if (usb_ma_table[i].usb_ma <= mA)
2069 break;
2070 }
David Keitel38bdd4f2012-04-19 15:39:13 -07002071
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002072 if (i < 0) {
2073 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2074 mA);
2075 i = 0;
2076 }
2077
Willie Ruan13c972d2012-11-15 11:56:36 -08002078 if (i < 0) {
2079 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2080 mA);
2081 i = 0;
2082 }
2083
David Keitel38bdd4f2012-04-19 15:39:13 -07002084 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07002085 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07002086 && !the_chip->iusb_fine_res)
2087 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 if (i < 0)
2089 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08002090 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002091 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08002092 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 }
2094}
2095
2096/* USB calls these to tell us how much max usb current the system can draw */
2097void pm8921_charger_vbus_draw(unsigned int mA)
2098{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002099 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100
2101 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08002102
David Keitel62c6a4b2012-05-17 12:54:59 -07002103 /*
2104 * Reject VBUS requests if USB connection is the only available
2105 * power source. This makes sure that if booting without
2106 * battery the iusb_max value is not decreased avoiding potential
2107 * brown_outs.
2108 *
2109 * This would also apply when the battery has been
2110 * removed from the running system.
2111 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002112 if (the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07002113 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07002114 if (!the_chip->has_dc_supply) {
2115 pr_err("rejected: no other power source connected\n");
2116 return;
2117 }
David Keitel62c6a4b2012-05-17 12:54:59 -07002118 }
2119
David Keitelacf57c82012-03-07 18:48:50 -08002120 if (usb_max_current && mA > usb_max_current) {
2121 pr_warn("restricting usb current to %d instead of %d\n",
2122 usb_max_current, mA);
2123 mA = usb_max_current;
2124 }
Devin Kim2073afb2012-09-05 13:01:51 -07002125 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
2126 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08002127
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302128 if (usb_target_ma)
2129 usb_target_ma = mA;
2130
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002131
2132 if (mA > USB_WALL_THRESHOLD_MA)
2133 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
2134 else
2135 set_usb_now_ma = mA;
2136
2137 if (the_chip && the_chip->disable_aicl)
2138 set_usb_now_ma = mA;
2139
2140 if (the_chip)
2141 __pm8921_charger_vbus_draw(set_usb_now_ma);
2142 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 /*
2144 * called before pmic initialized,
2145 * save this value and use it at probe
2146 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002147 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002148}
2149EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
2150
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002151int pm8921_is_usb_chg_plugged_in(void)
2152{
2153 if (!the_chip) {
2154 pr_err("called before init\n");
2155 return -EINVAL;
2156 }
2157 return is_usb_chg_plugged_in(the_chip);
2158}
2159EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
2160
2161int pm8921_is_dc_chg_plugged_in(void)
2162{
2163 if (!the_chip) {
2164 pr_err("called before init\n");
2165 return -EINVAL;
2166 }
2167 return is_dc_chg_plugged_in(the_chip);
2168}
2169EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
2170
2171int pm8921_is_battery_present(void)
2172{
2173 if (!the_chip) {
2174 pr_err("called before init\n");
2175 return -EINVAL;
2176 }
2177 return get_prop_batt_present(the_chip);
2178}
2179EXPORT_SYMBOL(pm8921_is_battery_present);
2180
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002181int pm8921_is_batfet_closed(void)
2182{
2183 if (!the_chip) {
2184 pr_err("called before init\n");
2185 return -EINVAL;
2186 }
2187 return is_batfet_closed(the_chip);
2188}
2189EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002190/*
2191 * Disabling the charge current limit causes current
2192 * current limits to have no monitoring. An adequate charger
2193 * capable of supplying high current while sustaining VIN_MIN
2194 * is required if the limiting is disabled.
2195 */
2196int pm8921_disable_input_current_limit(bool disable)
2197{
2198 if (!the_chip) {
2199 pr_err("called before init\n");
2200 return -EINVAL;
2201 }
2202 if (disable) {
2203 pr_warn("Disabling input current limit!\n");
2204
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002205 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002206 }
2207 return 0;
2208}
2209EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2210
David Keitel0789fc62012-06-07 17:43:27 -07002211int pm8917_set_under_voltage_detection_threshold(int mv)
2212{
2213 if (!the_chip) {
2214 pr_err("called before init\n");
2215 return -EINVAL;
2216 }
2217 return pm_chg_uvd_threshold_set(the_chip, mv);
2218}
2219EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2220
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002221int pm8921_set_max_battery_charge_current(int ma)
2222{
2223 if (!the_chip) {
2224 pr_err("called before init\n");
2225 return -EINVAL;
2226 }
2227 return pm_chg_ibatmax_set(the_chip, ma);
2228}
2229EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2230
2231int pm8921_disable_source_current(bool disable)
2232{
2233 if (!the_chip) {
2234 pr_err("called before init\n");
2235 return -EINVAL;
2236 }
2237 if (disable)
2238 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002239
2240 pm_chg_usb_suspend_enable(the_chip, disable);
2241
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002242 return pm_chg_charge_dis(the_chip, disable);
2243}
2244EXPORT_SYMBOL(pm8921_disable_source_current);
2245
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002246int pm8921_regulate_input_voltage(int voltage)
2247{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002248 int rc;
2249
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002250 if (!the_chip) {
2251 pr_err("called before init\n");
2252 return -EINVAL;
2253 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002254 rc = pm_chg_vinmin_set(the_chip, voltage);
2255
2256 if (rc == 0)
2257 the_chip->vin_min = voltage;
2258
2259 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002260}
2261
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002262#define USB_OV_THRESHOLD_MASK 0x60
2263#define USB_OV_THRESHOLD_SHIFT 5
2264int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2265{
2266 u8 temp;
2267
2268 if (!the_chip) {
2269 pr_err("called before init\n");
2270 return -EINVAL;
2271 }
2272
2273 if (ov > PM_USB_OV_7V) {
2274 pr_err("limiting to over voltage threshold to 7volts\n");
2275 ov = PM_USB_OV_7V;
2276 }
2277
2278 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2279
2280 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2281 USB_OV_THRESHOLD_MASK, temp);
2282}
2283EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2284
2285#define USB_DEBOUNCE_TIME_MASK 0x06
2286#define USB_DEBOUNCE_TIME_SHIFT 1
2287int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2288{
2289 u8 temp;
2290
2291 if (!the_chip) {
2292 pr_err("called before init\n");
2293 return -EINVAL;
2294 }
2295
2296 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2297 pr_err("limiting debounce to 80.5ms\n");
2298 ms = PM_USB_DEBOUNCE_80P5MS;
2299 }
2300
2301 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2302
2303 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2304 USB_DEBOUNCE_TIME_MASK, temp);
2305}
2306EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2307
2308#define USB_OVP_DISABLE_MASK 0x80
2309int pm8921_usb_ovp_disable(int disable)
2310{
2311 u8 temp = 0;
2312
2313 if (!the_chip) {
2314 pr_err("called before init\n");
2315 return -EINVAL;
2316 }
2317
2318 if (disable)
2319 temp = USB_OVP_DISABLE_MASK;
2320
2321 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2322 USB_OVP_DISABLE_MASK, temp);
2323}
2324
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002325bool pm8921_is_battery_charging(int *source)
2326{
2327 int fsm_state, is_charging, dc_present, usb_present;
2328
2329 if (!the_chip) {
2330 pr_err("called before init\n");
2331 return -EINVAL;
2332 }
2333 fsm_state = pm_chg_get_fsm_state(the_chip);
2334 is_charging = is_battery_charging(fsm_state);
2335 if (is_charging == 0) {
2336 *source = PM8921_CHG_SRC_NONE;
2337 return is_charging;
2338 }
2339
2340 if (source == NULL)
2341 return is_charging;
2342
2343 /* the battery is charging, the source is requested, find it */
2344 dc_present = is_dc_chg_plugged_in(the_chip);
2345 usb_present = is_usb_chg_plugged_in(the_chip);
2346
2347 if (dc_present && !usb_present)
2348 *source = PM8921_CHG_SRC_DC;
2349
2350 if (usb_present && !dc_present)
2351 *source = PM8921_CHG_SRC_USB;
2352
2353 if (usb_present && dc_present)
2354 /*
2355 * The system always chooses dc for charging since it has
2356 * higher priority.
2357 */
2358 *source = PM8921_CHG_SRC_DC;
2359
2360 return is_charging;
2361}
2362EXPORT_SYMBOL(pm8921_is_battery_charging);
2363
David Keitel86034022012-04-18 12:33:58 -07002364int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2365{
2366 if (!the_chip) {
2367 pr_err("called before init\n");
2368 return -EINVAL;
2369 }
2370
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002371 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002372 return -EINVAL;
2373
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002374 the_chip->usb_psy.type = type;
David Keitel86034022012-04-18 12:33:58 -07002375 power_supply_changed(&the_chip->usb_psy);
2376 power_supply_changed(&the_chip->dc_psy);
2377 return 0;
2378}
2379EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2380
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002381int pm8921_batt_temperature(void)
2382{
2383 if (!the_chip) {
2384 pr_err("called before init\n");
2385 return -EINVAL;
2386 }
2387 return get_prop_batt_temp(the_chip);
2388}
2389
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002390static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002391{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002392 int err;
2393 u8 temp;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002394
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002395
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002396 temp = 0xD1;
2397 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2398 if (err) {
2399 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002400 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002401 }
2402
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002403 temp = 0xD3;
2404 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2405 if (err) {
2406 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002407 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002408 }
2409
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002410 temp = 0xD1;
2411 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2412 if (err) {
2413 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002414 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002415 }
2416
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002417 temp = 0xD5;
2418 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2419 if (err) {
2420 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002421 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002422 }
2423
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002424 /* Wait a few clock cycles before re-enabling hw clock switching */
2425 udelay(183);
2426
2427 temp = 0xD1;
2428 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2429 if (err) {
2430 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002431 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002432 }
2433
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002434 temp = 0xD0;
2435 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2436 if (err) {
2437 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002438 return err;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002439 }
2440
2441 /* Wait for few clock cycles before re-enabling LPM */
2442 udelay(32);
2443
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002444 return 0;
2445}
2446
2447static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
2448{
2449 int err;
2450 unsigned long flags = 0;
2451
2452 spin_lock_irqsave(&lpm_lock, flags);
2453 err = pm8921_chg_set_lpm(chip, 0);
2454 if (err) {
2455 pr_err("Error settig LPM rc=%d\n", err);
2456 goto kick_err;
2457 }
2458
2459 __pm8921_apply_19p2mhz_kickstart(chip);
2460
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002461kick_err:
2462 err = pm8921_chg_set_lpm(chip, 1);
2463 if (err)
2464 pr_err("Error settig LPM rc=%d\n", err);
2465
2466 spin_unlock_irqrestore(&lpm_lock, flags);
2467
2468 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002469}
2470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002471static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2472{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002473 int usb_present, rc = 0;
2474
2475 if (chip->lockup_lpm_wrkarnd) {
2476 rc = pm8921_apply_19p2mhz_kickstart(chip);
2477 if (rc)
2478 pr_err("Failed to apply kickstart rc=%d\n", rc);
2479 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002481 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 usb_present = is_usb_chg_plugged_in(chip);
2483 if (chip->usb_present ^ usb_present) {
2484 notify_usb_of_the_plugin_event(usb_present);
2485 chip->usb_present = usb_present;
2486 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002487 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002488 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002489
2490 /* Enable/disable bypass if charger is on battery */
2491 if (chip->lockup_lpm_wrkarnd)
2492 pm8921_chg_bypass_bat_gone_debounce(chip,
2493 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002495 if (usb_present) {
2496 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002497 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002498 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2499 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002500 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002501 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002502 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002503 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002504 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505}
2506
Amir Samuelovd31ef502011-10-26 14:41:36 +02002507static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2508{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002509 if (chip->lockup_lpm_wrkarnd)
2510 /* Enable bypass if charger is on battery */
2511 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2512
David Keitel88e1b572012-01-11 11:57:14 -08002513 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002514 pr_debug("external charger not registered.\n");
2515 return;
2516 }
2517
2518 if (!chip->ext_charging) {
2519 pr_debug("already not charging.\n");
2520 return;
2521 }
2522
David Keitel88e1b572012-01-11 11:57:14 -08002523 power_supply_set_charge_type(chip->ext_psy,
2524 POWER_SUPPLY_CHARGE_TYPE_NONE);
2525 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002526 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002527 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002528 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002529 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002530 /* Update battery charging LEDs and user space battery info */
2531 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002532}
2533
2534static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2535{
2536 int dc_present;
2537 int batt_present;
2538 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002539 unsigned long delay =
2540 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2541
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002542 /* Disable bypass if charger connected and not running on bat */
2543 if (chip->lockup_lpm_wrkarnd)
2544 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2545
David Keitel88e1b572012-01-11 11:57:14 -08002546 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002547 pr_debug("external charger not registered.\n");
2548 return;
2549 }
2550
2551 if (chip->ext_charging) {
2552 pr_debug("already charging.\n");
2553 return;
2554 }
2555
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002556 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002557 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2558 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002559
2560 if (!dc_present) {
2561 pr_warn("%s. dc not present.\n", __func__);
2562 return;
2563 }
2564 if (!batt_present) {
2565 pr_warn("%s. battery not present.\n", __func__);
2566 return;
2567 }
2568 if (!batt_temp_ok) {
2569 pr_warn("%s. battery temperature not ok.\n", __func__);
2570 return;
2571 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002572
2573 /* Force BATFET=ON */
2574 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002575
David Keitel6ccbf132012-05-30 14:21:24 -07002576 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002577 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002578
David Keitel63f71662012-02-08 20:30:00 -08002579 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002580 power_supply_set_charge_type(chip->ext_psy,
2581 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002582 chip->ext_charging = true;
2583 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002584 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002585 /*
2586 * since we wont get a fastchg irq from external charger
2587 * use eoc worker to detect end of charging
2588 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002589 schedule_delayed_work(&chip->eoc_work, delay);
2590 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002591 if (chip->btc_override)
2592 schedule_delayed_work(&chip->btc_override_work,
2593 round_jiffies_relative(msecs_to_jiffies
2594 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002595 /* Update battery charging LEDs and user space battery info */
2596 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002597}
2598
David Keitel6ccbf132012-05-30 14:21:24 -07002599static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002600{
2601 u8 temp;
2602 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002603
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002604 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002605 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002606 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002607 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002608 }
David Keitel6ccbf132012-05-30 14:21:24 -07002609 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002610 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002611 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002612 return;
2613 }
2614 /* set ovp fet disable bit and the write bit */
2615 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002616 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002617 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002618 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002619 return;
2620 }
2621}
2622
David Keitel6ccbf132012-05-30 14:21:24 -07002623static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002624{
2625 u8 temp;
2626 int rc;
2627
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002628 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002629 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002630 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002631 return;
2632 }
David Keitel6ccbf132012-05-30 14:21:24 -07002633 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002634 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002635 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002636 return;
2637 }
2638 /* unset ovp fet disable bit and set the write bit */
2639 temp &= 0xFE;
2640 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002641 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002642 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002643 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002644 temp, rc);
2645 return;
2646 }
2647}
2648
2649static int param_open_ovp_counter = 10;
2650module_param(param_open_ovp_counter, int, 0644);
2651
David Keitel6ccbf132012-05-30 14:21:24 -07002652#define USB_ACTIVE_BIT BIT(5)
2653#define DC_ACTIVE_BIT BIT(6)
2654static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2655 u8 active_chg_mask)
2656{
2657 if (active_chg_mask & USB_ACTIVE_BIT)
2658 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2659 else if (active_chg_mask & DC_ACTIVE_BIT)
2660 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2661 else
2662 return 0;
2663}
2664
David Keitel8c5201a2012-02-24 16:08:54 -08002665#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002666#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002667static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002668{
David Keitel6ccbf132012-05-30 14:21:24 -07002669 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002670 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002671 u8 active_mask = 0;
2672 u16 ovpreg, ovptestreg;
2673
2674 if (is_usb_chg_plugged_in(chip) &&
2675 (chip->active_path & USB_ACTIVE_BIT)) {
2676 ovpreg = USB_OVP_CONTROL;
2677 ovptestreg = USB_OVP_TEST;
2678 active_mask = USB_ACTIVE_BIT;
2679 } else if (is_dc_chg_plugged_in(chip) &&
2680 (chip->active_path & DC_ACTIVE_BIT)) {
2681 ovpreg = DC_OVP_CONTROL;
2682 ovptestreg = DC_OVP_TEST;
2683 active_mask = DC_ACTIVE_BIT;
2684 } else {
2685 return;
2686 }
David Keitel8c5201a2012-02-24 16:08:54 -08002687
2688 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002689 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002690 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002691 active_chg_plugged_in
2692 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002693 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002694 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2695 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002696
2697 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002698 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002699 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002700 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002701
2702 msleep(20);
2703
David Keitel6ccbf132012-05-30 14:21:24 -07002704 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002705 } else {
David Keitel712782e2012-03-29 14:11:47 -07002706 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002707 }
2708 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002709 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2710 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2711 else
2712 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2713
David Keitel6ccbf132012-05-30 14:21:24 -07002714 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2715 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002716 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002717}
David Keitelacf57c82012-03-07 18:48:50 -08002718
2719static int find_usb_ma_value(int value)
2720{
2721 int i;
2722
2723 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2724 if (value >= usb_ma_table[i].usb_ma)
2725 break;
2726 }
2727
2728 return i;
2729}
2730
2731static void decrease_usb_ma_value(int *value)
2732{
2733 int i;
2734
2735 if (value) {
2736 i = find_usb_ma_value(*value);
2737 if (i > 0)
2738 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002739 while (!the_chip->iusb_fine_res && i > 0
2740 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2741 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002742
2743 if (i < 0) {
2744 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2745 *value);
2746 i = 0;
2747 }
2748
David Keitelacf57c82012-03-07 18:48:50 -08002749 *value = usb_ma_table[i].usb_ma;
2750 }
2751}
2752
2753static void increase_usb_ma_value(int *value)
2754{
2755 int i;
2756
2757 if (value) {
2758 i = find_usb_ma_value(*value);
2759
2760 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2761 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002762 /* Get next correct entry if IUSB_FINE_RES is not available */
2763 while (!the_chip->iusb_fine_res
2764 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2765 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2766 i++;
2767
David Keitelacf57c82012-03-07 18:48:50 -08002768 *value = usb_ma_table[i].usb_ma;
2769 }
2770}
2771
2772static void vin_collapse_check_worker(struct work_struct *work)
2773{
2774 struct delayed_work *dwork = to_delayed_work(work);
2775 struct pm8921_chg_chip *chip = container_of(dwork,
2776 struct pm8921_chg_chip, vin_collapse_check_work);
2777
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002778 /*
2779 * AICL only for wall-chargers. If the charger appears to be plugged
2780 * back in now, the corresponding unplug must have been because of we
2781 * were trying to draw more current than the charger can support. In
2782 * such a case reset usb current to 500mA and decrease the target.
2783 * The AICL algorithm will step up the current from 500mA to target
2784 */
2785 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002786 && usb_target_ma > USB_WALL_THRESHOLD_MA
2787 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002788 /* decrease usb_target_ma */
2789 decrease_usb_ma_value(&usb_target_ma);
2790 /* reset here, increase in unplug_check_worker */
2791 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2792 pr_debug("usb_now=%d, usb_target = %d\n",
2793 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002794 if (!delayed_work_pending(&chip->unplug_check_work))
2795 schedule_delayed_work(&chip->unplug_check_work,
2796 msecs_to_jiffies
2797 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002798 } else {
2799 handle_usb_insertion_removal(chip);
2800 }
2801}
2802
2803#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002804static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2805{
David Keitelacf57c82012-03-07 18:48:50 -08002806 if (usb_target_ma)
2807 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2808 round_jiffies_relative(msecs_to_jiffies
2809 (VIN_MIN_COLLAPSE_CHECK_MS)));
2810 else
2811 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 return IRQ_HANDLED;
2813}
2814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2816{
2817 struct pm8921_chg_chip *chip = data;
2818 int status;
2819
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002820 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2821 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002822 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 pr_debug("battery present=%d", status);
2824 power_supply_changed(&chip->batt_psy);
2825 return IRQ_HANDLED;
2826}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002827
2828/*
2829 * this interrupt used to restart charging a battery.
2830 *
2831 * Note: When DC-inserted the VBAT can't go low.
2832 * VPH_PWR is provided by the ext-charger.
2833 * After End-Of-Charging from DC, charging can be resumed only
2834 * if DC is removed and then inserted after the battery was in use.
2835 * Therefore the handle_start_ext_chg() is not called.
2836 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002837static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2838{
2839 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002840 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002841
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002842 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002843
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002844 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002845 /* enable auto charging */
2846 pm_chg_auto_enable(chip, !charging_disabled);
2847 pr_info("batt fell below resume voltage %s\n",
2848 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 power_supply_changed(&chip->batt_psy);
2853 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002854 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856 return IRQ_HANDLED;
2857}
2858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002859static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2860{
2861 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2862 return IRQ_HANDLED;
2863}
2864
2865static irqreturn_t vcp_irq_handler(int irq, void *data)
2866{
David Keitel8c5201a2012-02-24 16:08:54 -08002867 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002868 return IRQ_HANDLED;
2869}
2870
2871static irqreturn_t atcdone_irq_handler(int irq, void *data)
2872{
2873 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2874 return IRQ_HANDLED;
2875}
2876
2877static irqreturn_t atcfail_irq_handler(int irq, void *data)
2878{
2879 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2880 return IRQ_HANDLED;
2881}
2882
2883static irqreturn_t chgdone_irq_handler(int irq, void *data)
2884{
2885 struct pm8921_chg_chip *chip = data;
2886
2887 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002888
2889 handle_stop_ext_chg(chip);
2890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891 power_supply_changed(&chip->batt_psy);
2892 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002893 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002894
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002895 bms_notify_check(chip);
2896
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002897 return IRQ_HANDLED;
2898}
2899
2900static irqreturn_t chgfail_irq_handler(int irq, void *data)
2901{
2902 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002903 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002904
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002905 if (!chip->stop_chg_upon_expiry) {
2906 ret = pm_chg_failed_clear(chip, 1);
2907 if (ret)
2908 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2909 }
David Keitel753ec8d2011-11-02 10:56:37 -07002910
2911 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2912 get_prop_batt_present(chip),
2913 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2914 pm_chg_get_fsm_state(data));
2915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 power_supply_changed(&chip->batt_psy);
2917 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002918 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002919 return IRQ_HANDLED;
2920}
2921
2922static irqreturn_t chgstate_irq_handler(int irq, void *data)
2923{
2924 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002925
2926 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2927 power_supply_changed(&chip->batt_psy);
2928 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002929 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002930
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002931 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933 return IRQ_HANDLED;
2934}
2935
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002936enum {
2937 PON_TIME_25NS = 0x04,
2938 PON_TIME_50NS = 0x08,
2939 PON_TIME_100NS = 0x0C,
2940};
David Keitel8c5201a2012-02-24 16:08:54 -08002941
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002942static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002943{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002944 u8 temp;
2945 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002946
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002947 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2948 if (rc) {
2949 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2950 return;
2951 }
2952 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2953 if (rc) {
2954 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2955 return;
2956 }
2957 /* clear the min pon time select bit */
2958 temp &= 0xF3;
2959 /* set the pon time */
2960 temp |= (u8)pon_time_ns;
2961 /* write enable bank 4 */
2962 temp |= 0x80;
2963 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2964 if (rc) {
2965 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2966 return;
2967 }
2968}
David Keitel8c5201a2012-02-24 16:08:54 -08002969
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002970static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2971{
2972 pr_debug("Start\n");
2973 set_min_pon_time(chip, PON_TIME_100NS);
2974 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2975 msleep(250);
2976 pm_chg_vinmin_set(chip, chip->vin_min);
2977 set_min_pon_time(chip, PON_TIME_25NS);
2978 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002979}
2980
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002981#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002982#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2983#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002984static void unplug_check_worker(struct work_struct *work)
2985{
2986 struct delayed_work *dwork = to_delayed_work(work);
2987 struct pm8921_chg_chip *chip = container_of(dwork,
2988 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002989 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002990 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002991 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002992 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002993
2994 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2995 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002996 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2997 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002998 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002999
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003000 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003001 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07003002 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
3003 active_path, active_chg_plugged_in);
3004 if (active_path & USB_ACTIVE_BIT) {
3005 pr_debug("USB charger active\n");
3006
3007 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07003008
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003009 if (usb_ma <= 100) {
3010 pr_debug(
3011 "Unenumerated or suspended usb_ma = %d skip\n",
3012 usb_ma);
3013 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07003014 }
3015 } else if (active_path & DC_ACTIVE_BIT) {
3016 pr_debug("DC charger active\n");
3017 } else {
3018 /* No charger active */
3019 if (!(is_usb_chg_plugged_in(chip)
3020 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003021 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07003022 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
3023 pm_chg_get_regulation_loop(chip),
3024 pm_chg_get_fsm_state(chip),
3025 get_prop_batt_current(chip)
3026 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003027 if (chip->lockup_lpm_wrkarnd) {
3028 rc = pm8921_apply_19p2mhz_kickstart(chip);
3029 if (rc)
3030 pr_err("Failed kickstart rc=%d\n", rc);
3031
3032 /*
3033 * Make sure kickstart happens at least 200 ms
3034 * after charger has been removed.
3035 */
3036 if (chip->final_kickstart) {
3037 chip->final_kickstart = false;
3038 goto check_again_later;
3039 }
3040 }
3041 return;
3042 } else {
3043 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07003044 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003045 }
David Keitel8c5201a2012-02-24 16:08:54 -08003046
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003047 chip->final_kickstart = true;
3048
3049 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003050 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
3051 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07003052 reg_loop = pm_chg_get_regulation_loop(chip);
3053 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
3054 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003055 (usb_ma > USB_WALL_THRESHOLD_MA)
3056 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07003057 decrease_usb_ma_value(&usb_ma);
3058 usb_target_ma = usb_ma;
3059 /* end AICL here */
3060 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003061 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07003062 usb_ma, usb_target_ma);
3063 }
David Keitelacf57c82012-03-07 18:48:50 -08003064 }
3065
3066 reg_loop = pm_chg_get_regulation_loop(chip);
3067 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
3068
David Keitel6ccbf132012-05-30 14:21:24 -07003069 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08003070 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003071 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003072 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
3073 ibat, pm_chg_get_fsm_state(chip), reg_loop);
3074 attempt_reverse_boost_fix(chip);
3075 /* after reverse boost fix check if the active
3076 * charger was detected as removed */
3077 active_chg_plugged_in
3078 = is_active_chg_plugged_in(chip,
3079 active_path);
3080 pr_debug("revboost post: active_chg_plugged_in = %d\n",
3081 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003082 }
3083 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003084
3085 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07003086 pr_debug("active_path = 0x%x, active_chg = %d\n",
3087 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08003088 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3089
David Keitel6ccbf132012-05-30 14:21:24 -07003090 if (chg_gone == 1 && active_chg_plugged_in == 1) {
3091 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
3092 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07003093 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08003094 }
3095
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003096 /* AICL only for usb wall charger */
3097 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
3098 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003099 && !charging_disabled
3100 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08003101 /* only increase iusb_max if vin loop not active */
3102 if (usb_ma < usb_target_ma) {
3103 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05303104 if (usb_ma > usb_target_ma)
3105 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08003106 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003107 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08003108 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003109 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07003110 } else {
3111 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08003112 }
3113 }
Devin Kim2073afb2012-09-05 13:01:51 -07003114check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003115 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08003116 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003117 if (ramp)
3118 schedule_delayed_work(&chip->unplug_check_work,
3119 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
3120 else
3121 schedule_delayed_work(&chip->unplug_check_work,
3122 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003123}
3124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003125static irqreturn_t loop_change_irq_handler(int irq, void *data)
3126{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003127 struct pm8921_chg_chip *chip = data;
3128
3129 pr_debug("fsm_state=%d reg_loop=0x%x\n",
3130 pm_chg_get_fsm_state(data),
3131 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07003132 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133 return IRQ_HANDLED;
3134}
3135
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003136struct ibatmax_max_adj_entry {
3137 int ibat_max_ma;
3138 int max_adj_ma;
3139};
3140
3141static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
3142 {975, 300},
3143 {1475, 150},
3144 {1975, 200},
3145 {2475, 250},
3146};
3147
3148static int find_ibat_max_adj_ma(int ibat_target_ma)
3149{
3150 int i = 0;
3151
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08003152 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
3153 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003154 break;
3155 }
3156
3157 return ibatmax_adj_table[i].max_adj_ma;
3158}
3159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003160static irqreturn_t fastchg_irq_handler(int irq, void *data)
3161{
3162 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003163 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003164
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003165 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3166 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
3167 wake_lock(&chip->eoc_wake_lock);
3168 schedule_delayed_work(&chip->eoc_work,
3169 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003170 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003171 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003172 if (high_transition
3173 && chip->btc_override
3174 && !delayed_work_pending(&chip->btc_override_work)) {
3175 schedule_delayed_work(&chip->btc_override_work,
3176 round_jiffies_relative(msecs_to_jiffies
3177 (chip->btc_delay_ms)));
3178 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003179 power_supply_changed(&chip->batt_psy);
3180 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 return IRQ_HANDLED;
3182}
3183
3184static irqreturn_t trklchg_irq_handler(int irq, void *data)
3185{
3186 struct pm8921_chg_chip *chip = data;
3187
3188 power_supply_changed(&chip->batt_psy);
3189 return IRQ_HANDLED;
3190}
3191
3192static irqreturn_t batt_removed_irq_handler(int irq, void *data)
3193{
3194 struct pm8921_chg_chip *chip = data;
3195 int status;
3196
3197 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3198 pr_debug("battery present=%d state=%d", !status,
3199 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003200 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201 power_supply_changed(&chip->batt_psy);
3202 return IRQ_HANDLED;
3203}
3204
3205static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3206{
3207 struct pm8921_chg_chip *chip = data;
3208
Amir Samuelovd31ef502011-10-26 14:41:36 +02003209 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003210 power_supply_changed(&chip->batt_psy);
3211 return IRQ_HANDLED;
3212}
3213
3214static irqreturn_t chghot_irq_handler(int irq, void *data)
3215{
3216 struct pm8921_chg_chip *chip = data;
3217
3218 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3219 power_supply_changed(&chip->batt_psy);
3220 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003221 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003222 return IRQ_HANDLED;
3223}
3224
3225static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3226{
3227 struct pm8921_chg_chip *chip = data;
3228
3229 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003230 handle_stop_ext_chg(chip);
3231
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003232 power_supply_changed(&chip->batt_psy);
3233 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234 return IRQ_HANDLED;
3235}
3236
3237static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3238{
3239 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003240 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003241
3242 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3243 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3244
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003245 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3246 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003248 power_supply_changed(&chip->batt_psy);
3249 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003250 return IRQ_HANDLED;
3251}
David Keitel52fda532011-11-10 10:43:44 -08003252/*
3253 *
3254 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3255 * fire for two cases:
3256 *
3257 * If the interrupt line switches to high temperature is okay
3258 * and thus charging begins.
3259 * If bat_temp_ok is low this means the temperature is now
3260 * too hot or cold, so charging is stopped.
3261 *
3262 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3264{
David Keitel52fda532011-11-10 10:43:44 -08003265 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266 struct pm8921_chg_chip *chip = data;
3267
David Keitel52fda532011-11-10 10:43:44 -08003268 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3269
3270 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3271 bat_temp_ok, pm_chg_get_fsm_state(data));
3272
3273 if (bat_temp_ok)
3274 handle_start_ext_chg(chip);
3275 else
3276 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278 power_supply_changed(&chip->batt_psy);
3279 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003280 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003281 return IRQ_HANDLED;
3282}
3283
3284static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3285{
3286 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3287 return IRQ_HANDLED;
3288}
3289
3290static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3291{
3292 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3293 return IRQ_HANDLED;
3294}
3295
3296static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3297{
3298 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3299 return IRQ_HANDLED;
3300}
3301
3302static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3303{
3304 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3305 return IRQ_HANDLED;
3306}
3307
3308static irqreturn_t batfet_irq_handler(int irq, void *data)
3309{
3310 struct pm8921_chg_chip *chip = data;
3311
3312 pr_debug("vreg ov\n");
3313 power_supply_changed(&chip->batt_psy);
3314 return IRQ_HANDLED;
3315}
3316
3317static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3318{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003319 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003320 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003321
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003322 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003323 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003324
3325 if (chip->dc_present ^ dc_present)
3326 pm8921_bms_calibrate_hkadc();
3327
David Keitel88e1b572012-01-11 11:57:14 -08003328 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003329 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003330 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003331 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3332
3333 chip->dc_present = dc_present;
3334
3335 if (chip->ext_psy) {
3336 if (dc_present)
3337 handle_start_ext_chg(chip);
3338 else
3339 handle_stop_ext_chg(chip);
3340 } else {
3341 if (chip->lockup_lpm_wrkarnd)
3342 /* if no external supply call bypass debounce here */
3343 pm8921_chg_bypass_bat_gone_debounce(chip,
3344 is_chg_on_bat(chip));
3345
3346 if (dc_present)
3347 schedule_delayed_work(&chip->unplug_check_work,
3348 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3349 power_supply_changed(&chip->dc_psy);
3350 }
3351
3352 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353 return IRQ_HANDLED;
3354}
3355
3356static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3357{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003358 struct pm8921_chg_chip *chip = data;
3359
Amir Samuelovd31ef502011-10-26 14:41:36 +02003360 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003361 return IRQ_HANDLED;
3362}
3363
3364static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3365{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003366 struct pm8921_chg_chip *chip = data;
3367
Amir Samuelovd31ef502011-10-26 14:41:36 +02003368 handle_stop_ext_chg(chip);
3369
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003370 return IRQ_HANDLED;
3371}
3372
David Keitel88e1b572012-01-11 11:57:14 -08003373static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3374{
3375 struct power_supply *psy = &the_chip->batt_psy;
3376 struct power_supply *epsy = dev_get_drvdata(dev);
3377 int i, dcin_irq;
3378
3379 /* Only search for external supply if none is registered */
3380 if (!the_chip->ext_psy) {
3381 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3382 for (i = 0; i < epsy->num_supplicants; i++) {
3383 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3384 if (!strncmp(epsy->name, "dc", 2)) {
3385 the_chip->ext_psy = epsy;
3386 dcin_valid_irq_handler(dcin_irq,
3387 the_chip);
3388 }
3389 }
3390 }
3391 }
3392 return 0;
3393}
3394
3395static void pm_batt_external_power_changed(struct power_supply *psy)
3396{
3397 /* Only look for an external supply if it hasn't been registered */
3398 if (!the_chip->ext_psy)
3399 class_for_each_device(power_supply_class, NULL, psy,
3400 __pm_batt_external_power_changed_work);
3401}
3402
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003403/**
3404 * update_heartbeat - internal function to update userspace
3405 * per update_time minutes
3406 *
3407 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003408#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003409static void update_heartbeat(struct work_struct *work)
3410{
3411 struct delayed_work *dwork = to_delayed_work(work);
3412 struct pm8921_chg_chip *chip = container_of(dwork,
3413 struct pm8921_chg_chip, update_heartbeat_work);
3414
3415 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003416 if (chip->recent_reported_soc <= 20)
3417 schedule_delayed_work(&chip->update_heartbeat_work,
3418 round_jiffies_relative(msecs_to_jiffies
3419 (LOW_SOC_HEARTBEAT_MS)));
3420 else
3421 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003422 round_jiffies_relative(msecs_to_jiffies
3423 (chip->update_time)));
3424}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003425#define VDD_LOOP_ACTIVE_BIT BIT(3)
3426#define VDD_MAX_INCREASE_MV 400
3427static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3428module_param(vdd_max_increase_mv, int, 0644);
3429
3430static int ichg_threshold_ua = -400000;
3431module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003432
3433#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003434static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3435 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003436{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003437 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003438 int vbat_batt_terminal_mv;
3439 int reg_loop;
3440 int delta_mv = 0;
3441
3442 if (chip->rconn_mohm == 0) {
3443 pr_debug("Exiting as rconn_mohm is 0\n");
3444 return;
3445 }
3446 /* adjust vdd_max only in normal temperature zone */
3447 if (chip->is_bat_cool || chip->is_bat_warm) {
3448 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3449 chip->is_bat_cool, chip->is_bat_warm);
3450 return;
3451 }
3452
3453 reg_loop = pm_chg_get_regulation_loop(chip);
3454 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3455 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3456 reg_loop);
3457 return;
3458 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003459 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3460 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3461
3462 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3463
3464 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3465 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3466 delta_mv,
3467 programmed_vdd_max,
3468 adj_vdd_max_mv);
3469
3470 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3471 pr_debug("adj vdd_max lower than default max voltage\n");
3472 return;
3473 }
3474
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003475 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3476 * PM8921_CHG_VDDMAX_RES_MV;
3477
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003478 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3479 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003480 pr_debug("adjusting vdd_max_mv to %d to make "
3481 "vbat_batt_termial_uv = %d to %d\n",
3482 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3483 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3484}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003485
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003486static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3487{
3488 if (chip->is_bat_cool)
3489 pm_chg_vbatdet_set(the_chip,
3490 the_chip->cool_bat_voltage
3491 - the_chip->resume_voltage_delta);
3492 else if (chip->is_bat_warm)
3493 pm_chg_vbatdet_set(the_chip,
3494 the_chip->warm_bat_voltage
3495 - the_chip->resume_voltage_delta);
3496 else
3497 pm_chg_vbatdet_set(the_chip,
3498 the_chip->max_voltage_mv
3499 - the_chip->resume_voltage_delta);
3500}
3501
3502static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3503{
3504 unsigned int chg_current = chip->max_bat_chg_current;
3505
3506 if (chip->is_bat_cool)
3507 chg_current = min(chg_current, chip->cool_bat_chg_current);
3508
3509 if (chip->is_bat_warm)
3510 chg_current = min(chg_current, chip->warm_bat_chg_current);
3511
3512 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3513 chg_current = min(chg_current,
3514 chip->thermal_mitigation[thermal_mitigation]);
3515
3516 pm_chg_ibatmax_set(the_chip, chg_current);
3517}
3518
3519#define TEMP_HYSTERISIS_DECIDEGC 20
3520static void battery_cool(bool enter)
3521{
3522 pr_debug("enter = %d\n", enter);
3523 if (enter == the_chip->is_bat_cool)
3524 return;
3525 the_chip->is_bat_cool = enter;
3526 if (enter)
3527 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3528 else
3529 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3530 set_appropriate_battery_current(the_chip);
3531 set_appropriate_vbatdet(the_chip);
3532}
3533
3534static void battery_warm(bool enter)
3535{
3536 pr_debug("enter = %d\n", enter);
3537 if (enter == the_chip->is_bat_warm)
3538 return;
3539 the_chip->is_bat_warm = enter;
3540 if (enter)
3541 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3542 else
3543 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3544
3545 set_appropriate_battery_current(the_chip);
3546 set_appropriate_vbatdet(the_chip);
3547}
3548
3549static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3550{
3551 int temp = 0;
3552
3553 temp = get_prop_batt_temp(chip);
3554 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3555 temp, chip->warm_temp_dc,
3556 chip->cool_temp_dc);
3557
3558 if (chip->warm_temp_dc != INT_MIN) {
3559 if (chip->is_bat_warm
3560 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3561 battery_warm(false);
3562 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3563 battery_warm(true);
3564 }
3565
3566 if (chip->cool_temp_dc != INT_MIN) {
3567 if (chip->is_bat_cool
3568 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3569 battery_cool(false);
3570 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3571 battery_cool(true);
3572 }
3573}
3574
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003575enum {
3576 CHG_IN_PROGRESS,
3577 CHG_NOT_IN_PROGRESS,
3578 CHG_FINISHED,
3579};
3580
3581#define VBAT_TOLERANCE_MV 70
3582#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003583static int is_charging_finished(struct pm8921_chg_chip *chip,
3584 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003585{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003586 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003587 int regulation_loop, fast_chg, vcp;
3588 int rc;
3589 static int last_vbat_programmed = -EINVAL;
3590
3591 if (!is_ext_charging(chip)) {
3592 /* return if the battery is not being fastcharged */
3593 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3594 pr_debug("fast_chg = %d\n", fast_chg);
3595 if (fast_chg == 0)
3596 return CHG_NOT_IN_PROGRESS;
3597
3598 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3599 pr_debug("vcp = %d\n", vcp);
3600 if (vcp == 1)
3601 return CHG_IN_PROGRESS;
3602
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003603 /* reset count if battery is hot/cold */
3604 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3605 pr_debug("batt_temp_ok = %d\n", rc);
3606 if (rc == 0)
3607 return CHG_IN_PROGRESS;
3608
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003609 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3610 if (rc) {
3611 pr_err("couldnt read vddmax rc = %d\n", rc);
3612 return CHG_IN_PROGRESS;
3613 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003614 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3615 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003616
3617 if (last_vbat_programmed == -EINVAL)
3618 last_vbat_programmed = vbat_programmed;
3619 if (last_vbat_programmed != vbat_programmed) {
3620 /* vddmax changed, reset and check again */
3621 pr_debug("vddmax = %d last_vdd_max=%d\n",
3622 vbat_programmed, last_vbat_programmed);
3623 last_vbat_programmed = vbat_programmed;
3624 return CHG_IN_PROGRESS;
3625 }
3626
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003627 if (chip->is_bat_cool)
3628 vbat_intended = chip->cool_bat_voltage;
3629 else if (chip->is_bat_warm)
3630 vbat_intended = chip->warm_bat_voltage;
3631 else
3632 vbat_intended = chip->max_voltage_mv;
3633
3634 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3635 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3636 vbat_batt_terminal_uv,
3637 vbat_intended);
3638 return CHG_IN_PROGRESS;
3639 }
3640
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003641 regulation_loop = pm_chg_get_regulation_loop(chip);
3642 if (regulation_loop < 0) {
3643 pr_err("couldnt read the regulation loop err=%d\n",
3644 regulation_loop);
3645 return CHG_IN_PROGRESS;
3646 }
3647 pr_debug("regulation_loop=%d\n", regulation_loop);
3648
3649 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3650 return CHG_IN_PROGRESS;
3651 } /* !is_ext_charging */
3652
3653 /* reset count if battery chg current is more than iterm */
3654 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3655 if (rc) {
3656 pr_err("couldnt read iterm rc = %d\n", rc);
3657 return CHG_IN_PROGRESS;
3658 }
3659
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003660 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3661 iterm_programmed, ichg_meas_ma);
3662 /*
3663 * ichg_meas_ma < 0 means battery is drawing current
3664 * ichg_meas_ma > 0 means battery is providing current
3665 */
3666 if (ichg_meas_ma > 0)
3667 return CHG_IN_PROGRESS;
3668
3669 if (ichg_meas_ma * -1 > iterm_programmed)
3670 return CHG_IN_PROGRESS;
3671
3672 return CHG_FINISHED;
3673}
3674
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003675#define COMP_OVERRIDE_HOT_BANK 6
3676#define COMP_OVERRIDE_COLD_BANK 7
3677#define COMP_OVERRIDE_BIT BIT(1)
3678static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3679{
3680 u8 val;
3681 int rc = 0;
3682
3683 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3684
3685 if (flag)
3686 val |= 0x01;
3687
3688 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3689 if (rc < 0)
3690 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3691
3692 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3693 return rc;
3694}
3695
3696static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3697{
3698 u8 val;
3699 int rc = 0;
3700
3701 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3702
3703 if (flag)
3704 val |= 0x01;
3705
3706 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3707 if (rc < 0)
3708 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3709
3710 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3711 return rc;
3712}
3713
3714static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3715{
3716 int rc = 0;
3717 u8 reg;
3718 u8 val;
3719
3720 val = COMP_OVERRIDE_HOT_BANK << 2;
3721 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3722 if (rc < 0) {
3723 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3724 goto cold_init;
3725 }
3726 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3727 if (rc < 0) {
3728 pr_err("Could not read bank %d of override rc = %d\n",
3729 COMP_OVERRIDE_HOT_BANK, rc);
3730 goto cold_init;
3731 }
3732 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3733 /* for now override it as not hot */
3734 rc = pm_chg_override_hot(chip, 0);
3735 if (rc < 0)
3736 pr_err("Could not override hot rc = %d\n", rc);
3737 }
3738
3739cold_init:
3740 val = COMP_OVERRIDE_COLD_BANK << 2;
3741 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3742 if (rc < 0) {
3743 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3744 return;
3745 }
3746 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3747 if (rc < 0) {
3748 pr_err("Could not read bank %d of override rc = %d\n",
3749 COMP_OVERRIDE_COLD_BANK, rc);
3750 return;
3751 }
3752 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3753 /* for now override it as not cold */
3754 rc = pm_chg_override_cold(chip, 0);
3755 if (rc < 0)
3756 pr_err("Could not override cold rc = %d\n", rc);
3757 }
3758}
3759
3760static void btc_override_worker(struct work_struct *work)
3761{
3762 int decidegc;
3763 int temp;
3764 int rc = 0;
3765 struct delayed_work *dwork = to_delayed_work(work);
3766 struct pm8921_chg_chip *chip = container_of(dwork,
3767 struct pm8921_chg_chip, btc_override_work);
3768
3769 if (!chip->btc_override) {
3770 pr_err("called when not enabled\n");
3771 return;
3772 }
3773
3774 decidegc = get_prop_batt_temp(chip);
3775
3776 pr_debug("temp=%d\n", decidegc);
3777
3778 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3779 if (temp) {
3780 if (decidegc < chip->btc_override_hot_decidegc)
3781 /* stop forcing batt hot */
3782 rc = pm_chg_override_hot(chip, 0);
3783 if (rc)
3784 pr_err("Couldnt write 0 to hot comp\n");
3785 } else {
3786 if (decidegc >= chip->btc_override_hot_decidegc)
3787 /* start forcing batt hot */
3788 rc = pm_chg_override_hot(chip, 1);
3789 if (rc && chip->btc_panic_if_cant_stop_chg)
3790 panic("Couldnt override comps to stop chg\n");
3791 }
3792
3793 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3794 if (temp) {
3795 if (decidegc > chip->btc_override_cold_decidegc)
3796 /* stop forcing batt cold */
3797 rc = pm_chg_override_cold(chip, 0);
3798 if (rc)
3799 pr_err("Couldnt write 0 to cold comp\n");
3800 } else {
3801 if (decidegc <= chip->btc_override_cold_decidegc)
3802 /* start forcing batt cold */
3803 rc = pm_chg_override_cold(chip, 1);
3804 if (rc && chip->btc_panic_if_cant_stop_chg)
3805 panic("Couldnt override comps to stop chg\n");
3806 }
3807
3808 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3809 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3810 schedule_delayed_work(&chip->btc_override_work,
3811 round_jiffies_relative(msecs_to_jiffies
3812 (chip->btc_delay_ms)));
3813 return;
3814 }
3815
3816 rc = pm_chg_override_hot(chip, 0);
3817 if (rc)
3818 pr_err("Couldnt write 0 to hot comp\n");
3819 rc = pm_chg_override_cold(chip, 0);
3820 if (rc)
3821 pr_err("Couldnt write 0 to cold comp\n");
3822}
3823
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003824/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003825 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003826 * has happened
3827 *
3828 * If all conditions favouring, if the charge current is
3829 * less than the term current for three consecutive times
3830 * an EOC has happened.
3831 * The wakelock is released if there is no need to reshedule
3832 * - this happens when the battery is removed or EOC has
3833 * happened
3834 */
3835#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003836static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003837{
3838 struct delayed_work *dwork = to_delayed_work(work);
3839 struct pm8921_chg_chip *chip = container_of(dwork,
3840 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003841 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003842 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003843 int vbat_meas_uv, vbat_meas_mv;
3844 int ichg_meas_ua, ichg_meas_ma;
3845 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003846
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003847 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3848 &ichg_meas_ua, &vbat_meas_uv);
3849 vbat_meas_mv = vbat_meas_uv / 1000;
3850 /* rconn_mohm is in milliOhms */
3851 ichg_meas_ma = ichg_meas_ua / 1000;
3852 vbat_batt_terminal_uv = vbat_meas_uv
3853 + ichg_meas_ma
3854 * the_chip->rconn_mohm;
3855
3856 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003857
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003858 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003859 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003860 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003861 }
3862
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003863 if (end == CHG_FINISHED) {
3864 count++;
3865 } else {
3866 count = 0;
3867 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003868
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003869 if (count == CONSECUTIVE_COUNT) {
3870 count = 0;
3871 pr_info("End of Charging\n");
3872
3873 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003874
Amir Samuelovd31ef502011-10-26 14:41:36 +02003875 if (is_ext_charging(chip))
3876 chip->ext_charge_done = true;
3877
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003878 if (chip->is_bat_warm || chip->is_bat_cool)
3879 chip->bms_notify.is_battery_full = 0;
3880 else
3881 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003882 /* declare end of charging by invoking chgdone interrupt */
3883 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003884 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003885 check_temp_thresholds(chip);
3886 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003887 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003888 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003889 round_jiffies_relative(msecs_to_jiffies
3890 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003891 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003892 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003893
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003894eoc_worker_stop:
3895 wake_unlock(&chip->eoc_wake_lock);
3896 /* set the vbatdet back, in case it was changed to trigger charging */
3897 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003898}
3899
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003900/**
3901 * set_disable_status_param -
3902 *
3903 * Internal function to disable battery charging and also disable drawing
3904 * any current from the source. The device is forced to run on a battery
3905 * after this.
3906 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003907static int set_disable_status_param(const char *val, struct kernel_param *kp)
3908{
3909 int ret;
3910 struct pm8921_chg_chip *chip = the_chip;
3911
3912 ret = param_set_int(val, kp);
3913 if (ret) {
3914 pr_err("error setting value %d\n", ret);
3915 return ret;
3916 }
3917 pr_info("factory set disable param to %d\n", charging_disabled);
3918 if (chip) {
3919 pm_chg_auto_enable(chip, !charging_disabled);
3920 pm_chg_charge_dis(chip, charging_disabled);
3921 }
3922 return 0;
3923}
3924module_param_call(disabled, set_disable_status_param, param_get_uint,
3925 &charging_disabled, 0644);
3926
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003927static int rconn_mohm;
3928static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3929{
3930 int ret;
3931 struct pm8921_chg_chip *chip = the_chip;
3932
3933 ret = param_set_int(val, kp);
3934 if (ret) {
3935 pr_err("error setting value %d\n", ret);
3936 return ret;
3937 }
3938 if (chip)
3939 chip->rconn_mohm = rconn_mohm;
3940 return 0;
3941}
3942module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3943 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003944/**
3945 * set_thermal_mitigation_level -
3946 *
3947 * Internal function to control battery charging current to reduce
3948 * temperature
3949 */
3950static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3951{
3952 int ret;
3953 struct pm8921_chg_chip *chip = the_chip;
3954
3955 ret = param_set_int(val, kp);
3956 if (ret) {
3957 pr_err("error setting value %d\n", ret);
3958 return ret;
3959 }
3960
3961 if (!chip) {
3962 pr_err("called before init\n");
3963 return -EINVAL;
3964 }
3965
3966 if (!chip->thermal_mitigation) {
3967 pr_err("no thermal mitigation\n");
3968 return -EINVAL;
3969 }
3970
3971 if (thermal_mitigation < 0
3972 || thermal_mitigation >= chip->thermal_levels) {
3973 pr_err("out of bound level selected\n");
3974 return -EINVAL;
3975 }
3976
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003977 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003978 return ret;
3979}
3980module_param_call(thermal_mitigation, set_therm_mitigation_level,
3981 param_get_uint,
3982 &thermal_mitigation, 0644);
3983
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003984static int set_usb_max_current(const char *val, struct kernel_param *kp)
3985{
3986 int ret, mA;
3987 struct pm8921_chg_chip *chip = the_chip;
3988
3989 ret = param_set_int(val, kp);
3990 if (ret) {
3991 pr_err("error setting value %d\n", ret);
3992 return ret;
3993 }
3994 if (chip) {
3995 pr_warn("setting current max to %d\n", usb_max_current);
3996 pm_chg_iusbmax_get(chip, &mA);
3997 if (mA > usb_max_current)
3998 pm8921_charger_vbus_draw(usb_max_current);
3999 return 0;
4000 }
4001 return -EINVAL;
4002}
David Keitelacf57c82012-03-07 18:48:50 -08004003module_param_call(usb_max_current, set_usb_max_current,
4004 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006static void free_irqs(struct pm8921_chg_chip *chip)
4007{
4008 int i;
4009
4010 for (i = 0; i < PM_CHG_MAX_INTS; i++)
4011 if (chip->pmic_chg_irq[i]) {
4012 free_irq(chip->pmic_chg_irq[i], chip);
4013 chip->pmic_chg_irq[i] = 0;
4014 }
4015}
4016
David Keitel88e1b572012-01-11 11:57:14 -08004017/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
4019{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07004021 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004022
4023 chip->dc_present = !!is_dc_chg_plugged_in(chip);
4024 chip->usb_present = !!is_usb_chg_plugged_in(chip);
4025
4026 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004027 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004028 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004029 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08004030 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004031 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032
4033 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
4034 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
4035 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004036 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004037 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
4038 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07004039 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004040 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
4041 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004042 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004044 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
4045 if (usb_chg_current)
4046 /*
4047 * Reissue a vbus draw call only if a battery
4048 * or DC is present. We don't want to brown out the
4049 * device if usb is its only source
4050 */
4051 __pm8921_charger_vbus_draw(usb_chg_current);
4052 usb_chg_current = 0;
4053
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07004054 /*
4055 * The bootloader could have started charging, a fastchg interrupt
4056 * might not happen. Check the real time status and if it is fast
4057 * charging invoke the handler so that the eoc worker could be
4058 * started
4059 */
4060 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
4061 if (is_fast_chg)
4062 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063
4064 fsm_state = pm_chg_get_fsm_state(chip);
4065 if (is_battery_charging(fsm_state)) {
4066 chip->bms_notify.is_charging = 1;
4067 pm8921_bms_charging_began();
4068 }
4069
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004070 check_battery_valid(chip);
4071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004072 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
4073 chip->usb_present,
4074 chip->dc_present,
4075 get_prop_batt_present(chip),
4076 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004077
4078 /* Determine which USB trim column to use */
4079 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
4080 chip->usb_trim_table = usb_trim_8917_table;
4081 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
4082 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004083}
4084
4085struct pm_chg_irq_init_data {
4086 unsigned int irq_id;
4087 char *name;
4088 unsigned long flags;
4089 irqreturn_t (*handler)(int, void *);
4090};
4091
4092#define CHG_IRQ(_id, _flags, _handler) \
4093{ \
4094 .irq_id = _id, \
4095 .name = #_id, \
4096 .flags = _flags, \
4097 .handler = _handler, \
4098}
4099struct pm_chg_irq_init_data chg_irq_data[] = {
4100 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4101 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4103 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07004104 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4105 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
4107 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
4108 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
4109 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
4110 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
4111 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
4112 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
4113 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07004114 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4115 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
4117 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
4118 batt_removed_irq_handler),
4119 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
4120 batttemp_hot_irq_handler),
4121 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
4122 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
4123 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08004124 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4125 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07004126 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4127 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004128 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
4129 coarse_det_low_irq_handler),
4130 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
4131 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
4132 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
4133 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4134 batfet_irq_handler),
4135 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4136 dcin_valid_irq_handler),
4137 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4138 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07004139 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140};
4141
4142static int __devinit request_irqs(struct pm8921_chg_chip *chip,
4143 struct platform_device *pdev)
4144{
4145 struct resource *res;
4146 int ret, i;
4147
4148 ret = 0;
4149 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
4150
4151 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4152 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
4153 chg_irq_data[i].name);
4154 if (res == NULL) {
4155 pr_err("couldn't find %s\n", chg_irq_data[i].name);
4156 goto err_out;
4157 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004158 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004159 ret = request_irq(res->start, chg_irq_data[i].handler,
4160 chg_irq_data[i].flags,
4161 chg_irq_data[i].name, chip);
4162 if (ret < 0) {
4163 pr_err("couldn't request %d (%s) %d\n", res->start,
4164 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004165 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004166 goto err_out;
4167 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
4169 }
4170 return 0;
4171
4172err_out:
4173 free_irqs(chip);
4174 return -EINVAL;
4175}
4176
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004177#define VREF_BATT_THERM_FORCE_ON BIT(7)
4178static void detect_battery_removal(struct pm8921_chg_chip *chip)
4179{
4180 u8 temp;
4181
4182 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4183 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4184
4185 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4186 /*
4187 * batt therm force on bit is battery backed and is default 0
4188 * The charger sets this bit at init time. If this bit is found
4189 * 0 that means the battery was removed. Tell the bms about it
4190 */
4191 pm8921_bms_invalidate_shutdown_soc();
4192}
4193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004194#define ENUM_TIMER_STOP_BIT BIT(1)
4195#define BOOT_DONE_BIT BIT(6)
4196#define CHG_BATFET_ON_BIT BIT(3)
4197#define CHG_VCP_EN BIT(0)
4198#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4199#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004200#define PM_SUB_REV 0x001
4201#define MIN_CHARGE_CURRENT_MA 350
4202#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004203static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4204{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004205 u8 subrev;
4206 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004208 spin_lock_init(&lpm_lock);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08004209
4210 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4211 rc = __pm8921_apply_19p2mhz_kickstart(chip);
4212 if (rc) {
4213 pr_err("Failed to apply kickstart rc=%d\n", rc);
4214 return rc;
4215 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004216 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004217
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004218 detect_battery_removal(chip);
4219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004221 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004222 if (rc) {
4223 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4224 return rc;
4225 }
4226
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004227 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4228
4229 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4230 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4231
4232 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 if (rc) {
4235 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004236 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 return rc;
4238 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004239 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004240 chip->max_voltage_mv
4241 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242 if (rc) {
4243 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004244 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245 return rc;
4246 }
4247
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004248 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249 if (rc) {
4250 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004251 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004252 return rc;
4253 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004254
4255 if (chip->safe_current_ma == 0)
4256 chip->safe_current_ma = SAFE_CURRENT_MA;
4257
4258 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 if (rc) {
4260 pr_err("Failed to set max voltage to %d rc=%d\n",
4261 SAFE_CURRENT_MA, rc);
4262 return rc;
4263 }
4264
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004265 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004266 if (rc) {
4267 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4268 return rc;
4269 }
4270
4271 rc = pm_chg_iterm_set(chip, chip->term_current);
4272 if (rc) {
4273 pr_err("Failed to set term current to %d rc=%d\n",
4274 chip->term_current, rc);
4275 return rc;
4276 }
4277
4278 /* Disable the ENUM TIMER */
4279 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4280 ENUM_TIMER_STOP_BIT);
4281 if (rc) {
4282 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4283 return rc;
4284 }
4285
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004286 fcc_uah = pm8921_bms_get_fcc();
4287 if (fcc_uah > 0) {
4288 safety_time = div_s64((s64)fcc_uah * 60,
4289 1000 * MIN_CHARGE_CURRENT_MA);
4290 /* add 20 minutes of buffer time */
4291 safety_time += 20;
4292
4293 /* make sure we do not exceed the maximum programmable time */
4294 if (safety_time > PM8921_CHG_TCHG_MAX)
4295 safety_time = PM8921_CHG_TCHG_MAX;
4296 }
4297
4298 rc = pm_chg_tchg_max_set(chip, safety_time);
4299 if (rc) {
4300 pr_err("Failed to set max time to %d minutes rc=%d\n",
4301 safety_time, rc);
4302 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004303 }
4304
4305 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004306 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004307 if (rc) {
4308 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004309 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004310 return rc;
4311 }
4312 }
4313
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004314 if (chip->vin_min != 0) {
4315 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4316 if (rc) {
4317 pr_err("Failed to set vin min to %d mV rc=%d\n",
4318 chip->vin_min, rc);
4319 return rc;
4320 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004321 } else {
4322 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004323 }
4324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004325 rc = pm_chg_disable_wd(chip);
4326 if (rc) {
4327 pr_err("Failed to disable wd rc=%d\n", rc);
4328 return rc;
4329 }
4330
4331 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4332 CHG_BAT_TEMP_DIS_BIT, 0);
4333 if (rc) {
4334 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4335 return rc;
4336 }
4337 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004338 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4339 rc = pm_chg_write(chip,
4340 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4341 else
4342 rc = pm_chg_write(chip,
4343 CHG_BUCK_CLOCK_CTRL, 0x15);
4344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 if (rc) {
4346 pr_err("Failed to switch buck clk rc=%d\n", rc);
4347 return rc;
4348 }
4349
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004350 if (chip->trkl_voltage != 0) {
4351 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4352 if (rc) {
4353 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4354 chip->trkl_voltage, rc);
4355 return rc;
4356 }
4357 }
4358
4359 if (chip->weak_voltage != 0) {
4360 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4361 if (rc) {
4362 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4363 chip->weak_voltage, rc);
4364 return rc;
4365 }
4366 }
4367
4368 if (chip->trkl_current != 0) {
4369 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4370 if (rc) {
4371 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4372 chip->trkl_voltage, rc);
4373 return rc;
4374 }
4375 }
4376
4377 if (chip->weak_current != 0) {
4378 rc = pm_chg_iweak_set(chip, chip->weak_current);
4379 if (rc) {
4380 pr_err("Failed to set weak current to %dmA rc=%d\n",
4381 chip->weak_current, rc);
4382 return rc;
4383 }
4384 }
4385
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004386 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4387 if (rc) {
4388 pr_err("Failed to set cold config %d rc=%d\n",
4389 chip->cold_thr, rc);
4390 }
4391
4392 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4393 if (rc) {
4394 pr_err("Failed to set hot config %d rc=%d\n",
4395 chip->hot_thr, rc);
4396 }
4397
Jay Chokshid674a512012-03-15 14:06:04 -07004398 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4399 if (rc) {
4400 pr_err("Failed to set charger LED src config %d rc=%d\n",
4401 chip->led_src_config, rc);
4402 }
4403
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004404 /* Workarounds for die 3.0 */
4405 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4406 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4407 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4408 if (rc) {
4409 pr_err("read failed: addr=%03X, rc=%d\n",
4410 PM_SUB_REV, rc);
4411 return rc;
4412 }
4413 /* Check if die 3.0.1 is present */
4414 if (subrev & 0x1)
4415 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4416 else
4417 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004418 }
4419
David Keitel0789fc62012-06-07 17:43:27 -07004420 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004421 /* Set PM8917 USB_OVP debounce time to 15 ms */
4422 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4423 OVP_DEBOUNCE_TIME, 0x6);
4424 if (rc) {
4425 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4426 return rc;
4427 }
4428
4429 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004430 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004431 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004432 rc = pm_chg_uvd_threshold_set(chip,
4433 chip->uvd_voltage_mv);
4434 if (rc) {
4435 pr_err("Failed to set UVD threshold %drc=%d\n",
4436 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004437 return rc;
4438 }
David Keitel0789fc62012-06-07 17:43:27 -07004439 }
4440 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004441
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004442 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004443
David Keitela3c0d822011-11-03 14:18:52 -07004444 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004445 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004446
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004447 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4448 VREF_BATT_THERM_FORCE_ON);
4449 if (rc)
4450 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004452 rc = pm_chg_charge_dis(chip, charging_disabled);
4453 if (rc) {
4454 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4455 return rc;
4456 }
4457
4458 rc = pm_chg_auto_enable(chip, !charging_disabled);
4459 if (rc) {
4460 pr_err("Failed to enable charging rc=%d\n", rc);
4461 return rc;
4462 }
4463
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004464 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4465 /* Clear kickstart */
4466 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4467 if (rc) {
4468 pr_err("Failed to clear kickstart rc=%d\n", rc);
4469 return rc;
4470 }
4471
4472 /* From here the lpm_workaround will be active */
4473 chip->lockup_lpm_wrkarnd = true;
4474
4475 /* Enable LPM */
4476 pm8921_chg_set_lpm(chip, 1);
4477 }
4478
4479 if (chip->lockup_lpm_wrkarnd) {
4480 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4481 if (IS_ERR(chip->vreg_xoadc))
4482 return -ENODEV;
4483
4484 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4485 if (rc < 0) {
4486 pr_err("Failed to set configure HPM rc=%d\n", rc);
4487 return rc;
4488 }
4489
4490 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4491 if (rc) {
4492 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4493 return rc;
4494 }
4495
4496 rc = regulator_enable(chip->vreg_xoadc);
4497 if (rc) {
4498 pr_err("Failed to enable L14 rc=%d\n", rc);
4499 return rc;
4500 }
4501 }
4502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004503 return 0;
4504}
4505
4506static int get_rt_status(void *data, u64 * val)
4507{
4508 int i = (int)data;
4509 int ret;
4510
4511 /* global irq number is passed in via data */
4512 ret = pm_chg_get_rt_status(the_chip, i);
4513 *val = ret;
4514 return 0;
4515}
4516DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4517
4518static int get_fsm_status(void *data, u64 * val)
4519{
4520 u8 temp;
4521
4522 temp = pm_chg_get_fsm_state(the_chip);
4523 *val = temp;
4524 return 0;
4525}
4526DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4527
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004528static int get_reg_loop(void *data, u64 * val)
4529{
4530 u8 temp;
4531
4532 if (!the_chip) {
4533 pr_err("%s called before init\n", __func__);
4534 return -EINVAL;
4535 }
4536 temp = pm_chg_get_regulation_loop(the_chip);
4537 *val = temp;
4538 return 0;
4539}
4540DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004542static int get_reg(void *data, u64 * val)
4543{
4544 int addr = (int)data;
4545 int ret;
4546 u8 temp;
4547
4548 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4549 if (ret) {
4550 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4551 addr, temp, ret);
4552 return -EAGAIN;
4553 }
4554 *val = temp;
4555 return 0;
4556}
4557
4558static int set_reg(void *data, u64 val)
4559{
4560 int addr = (int)data;
4561 int ret;
4562 u8 temp;
4563
4564 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004565 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004567 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 addr, temp, ret);
4569 return -EAGAIN;
4570 }
4571 return 0;
4572}
4573DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4574
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004575static int reg_loop;
4576#define MAX_REG_LOOP_CHAR 10
4577static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4578{
4579 u8 temp;
4580
4581 if (!the_chip) {
4582 pr_err("called before init\n");
4583 return -EINVAL;
4584 }
4585 temp = pm_chg_get_regulation_loop(the_chip);
4586 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4587}
4588module_param_call(reg_loop, NULL, get_reg_loop_param,
4589 &reg_loop, 0644);
4590
4591static int max_chg_ma;
4592#define MAX_MA_CHAR 10
4593static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4594{
4595 if (!the_chip) {
4596 pr_err("called before init\n");
4597 return -EINVAL;
4598 }
4599 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4600}
4601module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4602 &max_chg_ma, 0644);
4603static int ibatmax_ma;
4604static int set_ibat_max(const char *val, struct kernel_param *kp)
4605{
4606 int rc;
4607
4608 if (!the_chip) {
4609 pr_err("called before init\n");
4610 return -EINVAL;
4611 }
4612
4613 rc = param_set_int(val, kp);
4614 if (rc) {
4615 pr_err("error setting value %d\n", rc);
4616 return rc;
4617 }
4618
4619 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4620 <= the_chip->ibatmax_max_adj_ma) {
4621 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4622 if (rc) {
4623 pr_err("Failed to set ibatmax rc = %d\n", rc);
4624 return rc;
4625 }
4626 }
4627
4628 return 0;
4629}
4630static int get_ibat_max(char *buf, struct kernel_param *kp)
4631{
4632 int ibat_ma;
4633 int rc;
4634
4635 if (!the_chip) {
4636 pr_err("called before init\n");
4637 return -EINVAL;
4638 }
4639
4640 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4641 if (rc) {
4642 pr_err("ibatmax_get error = %d\n", rc);
4643 return rc;
4644 }
4645
4646 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4647}
4648module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4649 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004650enum {
4651 BAT_WARM_ZONE,
4652 BAT_COOL_ZONE,
4653};
4654static int get_warm_cool(void *data, u64 * val)
4655{
4656 if (!the_chip) {
4657 pr_err("%s called before init\n", __func__);
4658 return -EINVAL;
4659 }
4660 if ((int)data == BAT_WARM_ZONE)
4661 *val = the_chip->is_bat_warm;
4662 if ((int)data == BAT_COOL_ZONE)
4663 *val = the_chip->is_bat_cool;
4664 return 0;
4665}
4666DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4669{
4670 int i;
4671
4672 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4673
4674 if (IS_ERR(chip->dent)) {
4675 pr_err("pmic charger couldnt create debugfs dir\n");
4676 return;
4677 }
4678
4679 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4680 (void *)CHG_CNTRL, &reg_fops);
4681 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4682 (void *)CHG_CNTRL_2, &reg_fops);
4683 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4684 (void *)CHG_CNTRL_3, &reg_fops);
4685 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4686 (void *)PBL_ACCESS1, &reg_fops);
4687 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4688 (void *)PBL_ACCESS2, &reg_fops);
4689 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4690 (void *)SYS_CONFIG_1, &reg_fops);
4691 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4692 (void *)SYS_CONFIG_2, &reg_fops);
4693 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4694 (void *)CHG_VDD_MAX, &reg_fops);
4695 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4696 (void *)CHG_VDD_SAFE, &reg_fops);
4697 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4698 (void *)CHG_VBAT_DET, &reg_fops);
4699 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4700 (void *)CHG_IBAT_MAX, &reg_fops);
4701 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4702 (void *)CHG_IBAT_SAFE, &reg_fops);
4703 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4704 (void *)CHG_VIN_MIN, &reg_fops);
4705 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4706 (void *)CHG_VTRICKLE, &reg_fops);
4707 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4708 (void *)CHG_ITRICKLE, &reg_fops);
4709 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4710 (void *)CHG_ITERM, &reg_fops);
4711 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4712 (void *)CHG_TCHG_MAX, &reg_fops);
4713 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4714 (void *)CHG_TWDOG, &reg_fops);
4715 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4716 (void *)CHG_TEMP_THRESH, &reg_fops);
4717 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4718 (void *)CHG_COMP_OVR, &reg_fops);
4719 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4720 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4721 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4722 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4723 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4724 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4725 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4726 (void *)CHG_TEST, &reg_fops);
4727
4728 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4729 &fsm_fops);
4730
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004731 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4732 &reg_loop_fops);
4733
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004734 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4735 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4736 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4737 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004739 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4740 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4741 debugfs_create_file(chg_irq_data[i].name, 0444,
4742 chip->dent,
4743 (void *)chg_irq_data[i].irq_id,
4744 &rt_fops);
4745 }
4746}
4747
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004748static int pm8921_charger_suspend_noirq(struct device *dev)
4749{
4750 int rc;
4751 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4752
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004753 if (chip->lockup_lpm_wrkarnd) {
4754 rc = regulator_disable(chip->vreg_xoadc);
4755 if (rc)
4756 pr_err("Failed to disable L14 rc=%d\n", rc);
4757
4758 rc = pm8921_apply_19p2mhz_kickstart(chip);
4759 if (rc)
4760 pr_err("Failed to apply kickstart rc=%d\n", rc);
4761 }
4762
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004763 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4764 if (rc)
4765 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004766 return 0;
4767}
4768
4769static int pm8921_charger_resume_noirq(struct device *dev)
4770{
4771 int rc;
4772 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4773
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004774 if (chip->lockup_lpm_wrkarnd) {
4775 rc = regulator_enable(chip->vreg_xoadc);
4776 if (rc)
4777 pr_err("Failed to enable L14 rc=%d\n", rc);
4778
4779 rc = pm8921_apply_19p2mhz_kickstart(chip);
4780 if (rc)
4781 pr_err("Failed to apply kickstart rc=%d\n", rc);
4782 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004783
4784 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4785 VREF_BATT_THERM_FORCE_ON);
4786 if (rc)
4787 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4788 return 0;
4789}
4790
David Keitelf2226022011-12-13 15:55:50 -08004791static int pm8921_charger_resume(struct device *dev)
4792{
David Keitelf2226022011-12-13 15:55:50 -08004793 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4794
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004795 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4796 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4797 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4798 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004799
4800 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4801 is_usb_chg_plugged_in(the_chip)))
4802 schedule_delayed_work(&chip->btc_override_work, 0);
4803
David Keitelf2226022011-12-13 15:55:50 -08004804 return 0;
4805}
4806
4807static int pm8921_charger_suspend(struct device *dev)
4808{
David Keitelf2226022011-12-13 15:55:50 -08004809 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4810
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004811 if (chip->btc_override)
4812 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004813
4814 if (is_usb_chg_plugged_in(chip)) {
4815 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4816 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4817 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004818
David Keitelf2226022011-12-13 15:55:50 -08004819 return 0;
4820}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4822{
4823 int rc = 0;
4824 struct pm8921_chg_chip *chip;
4825 const struct pm8921_charger_platform_data *pdata
4826 = pdev->dev.platform_data;
4827
4828 if (!pdata) {
4829 pr_err("missing platform data\n");
4830 return -EINVAL;
4831 }
4832
4833 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4834 GFP_KERNEL);
4835 if (!chip) {
4836 pr_err("Cannot allocate pm_chg_chip\n");
4837 return -ENOMEM;
4838 }
4839
4840 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004841 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004842 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004843 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004844 chip->alarm_low_mv = pdata->alarm_low_mv;
4845 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004846 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004847 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004848 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004849 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004850 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004851 chip->term_current = pdata->term_current;
4852 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004853 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004854 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4855 chip->batt_id_min = pdata->batt_id_min;
4856 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004857 if (pdata->cool_temp != INT_MIN)
4858 chip->cool_temp_dc = pdata->cool_temp * 10;
4859 else
4860 chip->cool_temp_dc = INT_MIN;
4861
4862 if (pdata->warm_temp != INT_MIN)
4863 chip->warm_temp_dc = pdata->warm_temp * 10;
4864 else
4865 chip->warm_temp_dc = INT_MIN;
4866
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004867 chip->temp_check_period = pdata->temp_check_period;
4868 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004869 /* Assign to corresponding module parameter */
4870 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004871 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4872 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4873 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4874 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004875 chip->trkl_voltage = pdata->trkl_voltage;
4876 chip->weak_voltage = pdata->weak_voltage;
4877 chip->trkl_current = pdata->trkl_current;
4878 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004879 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004880 chip->thermal_mitigation = pdata->thermal_mitigation;
4881 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004882
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004883 chip->cold_thr = pdata->cold_thr;
4884 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004885 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004886 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004887 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004888 chip->battery_less_hardware = pdata->battery_less_hardware;
4889 chip->btc_override = pdata->btc_override;
4890 if (chip->btc_override) {
4891 chip->btc_delay_ms = pdata->btc_delay_ms;
4892 chip->btc_override_cold_decidegc
4893 = pdata->btc_override_cold_degc * 10;
4894 chip->btc_override_hot_decidegc
4895 = pdata->btc_override_hot_degc * 10;
4896 chip->btc_panic_if_cant_stop_chg
4897 = pdata->btc_panic_if_cant_stop_chg;
4898 }
4899
4900 if (chip->battery_less_hardware)
4901 charging_disabled = 1;
4902
4903 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4904 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004906 rc = pm8921_chg_hw_init(chip);
4907 if (rc) {
4908 pr_err("couldn't init hardware rc=%d\n", rc);
4909 goto free_chip;
4910 }
4911
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004912 if (chip->btc_override)
4913 pm8921_chg_btc_override_init(chip);
4914
4915 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
4916
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004917 chip->usb_psy.name = "usb";
4918 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4919 chip->usb_psy.supplied_to = pm_power_supplied_to;
4920 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4921 chip->usb_psy.properties = pm_power_props_usb;
4922 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4923 chip->usb_psy.get_property = pm_power_get_property_usb;
4924 chip->usb_psy.set_property = pm_power_set_property_usb;
4925 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004926
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004927 chip->dc_psy.name = "pm8921-dc";
4928 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4929 chip->dc_psy.supplied_to = pm_power_supplied_to;
4930 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4931 chip->dc_psy.properties = pm_power_props_mains;
4932 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4933 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004934
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004935 chip->batt_psy.name = "battery";
4936 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4937 chip->batt_psy.properties = msm_batt_power_props;
4938 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4939 chip->batt_psy.get_property = pm_batt_power_get_property;
4940 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004941 rc = power_supply_register(chip->dev, &chip->usb_psy);
4942 if (rc < 0) {
4943 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004944 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945 }
4946
David Keitel6ed71a52012-01-30 12:42:18 -08004947 rc = power_supply_register(chip->dev, &chip->dc_psy);
4948 if (rc < 0) {
4949 pr_err("power_supply_register usb failed rc = %d\n", rc);
4950 goto unregister_usb;
4951 }
4952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953 rc = power_supply_register(chip->dev, &chip->batt_psy);
4954 if (rc < 0) {
4955 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004956 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004957 }
4958
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004959 platform_set_drvdata(pdev, chip);
4960 the_chip = chip;
4961
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004962 /* set initial state of the USB charger type to UNKNOWN */
4963 power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
4964
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004965 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004966 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004967 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4968 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004969 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004970
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004971 INIT_WORK(&chip->bms_notify.work, bms_notify);
4972 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4973
4974 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4975 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004977 rc = request_irqs(chip, pdev);
4978 if (rc) {
4979 pr_err("couldn't register interrupts rc=%d\n", rc);
4980 goto unregister_batt;
4981 }
4982
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004983 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004984 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004985 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004986 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004988 create_debugfs_entries(chip);
4989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004990 /* determine what state the charger is in */
4991 determine_initial_state(chip);
4992
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004993 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004994 schedule_delayed_work(&chip->update_heartbeat_work,
4995 round_jiffies_relative(msecs_to_jiffies
4996 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004997 return 0;
4998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004999unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07005000 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005001 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08005002unregister_dc:
5003 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005004unregister_usb:
5005 power_supply_unregister(&chip->usb_psy);
5006free_chip:
5007 kfree(chip);
5008 return rc;
5009}
5010
5011static int __devexit pm8921_charger_remove(struct platform_device *pdev)
5012{
5013 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
5014
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07005015 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005016 free_irqs(chip);
5017 platform_set_drvdata(pdev, NULL);
5018 the_chip = NULL;
5019 kfree(chip);
5020 return 0;
5021}
David Keitelf2226022011-12-13 15:55:50 -08005022static const struct dev_pm_ops pm8921_pm_ops = {
5023 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08005024 .suspend_noirq = pm8921_charger_suspend_noirq,
5025 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08005026 .resume = pm8921_charger_resume,
5027};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005028static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08005029 .probe = pm8921_charger_probe,
5030 .remove = __devexit_p(pm8921_charger_remove),
5031 .driver = {
5032 .name = PM8921_CHARGER_DEV_NAME,
5033 .owner = THIS_MODULE,
5034 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 },
5036};
5037
5038static int __init pm8921_charger_init(void)
5039{
5040 return platform_driver_register(&pm8921_charger_driver);
5041}
5042
5043static void __exit pm8921_charger_exit(void)
5044{
5045 platform_driver_unregister(&pm8921_charger_driver);
5046}
5047
5048late_initcall(pm8921_charger_init);
5049module_exit(pm8921_charger_exit);
5050
5051MODULE_LICENSE("GPL v2");
5052MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
5053MODULE_VERSION("1.0");
5054MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);