blob: cf520cd431cec9fd757cf16afd009928ea690773 [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;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +0530298 int usb_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299};
300
David Keitelacf57c82012-03-07 18:48:50 -0800301/* user space parameter to limit usb current */
302static unsigned int usb_max_current;
303/*
304 * usb_target_ma is used for wall charger
305 * adaptive input current limiting only. Use
306 * pm_iusbmax_get() to get current maximum usb current setting.
307 */
308static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700310static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311
312static struct pm8921_chg_chip *the_chip;
313
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700314static DEFINE_SPINLOCK(lpm_lock);
315#define LPM_ENABLE_BIT BIT(2)
316static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
317{
318 int rc;
319 u8 reg;
320
321 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
322 if (rc) {
323 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
324 CHG_CNTRL, rc);
325 return rc;
326 }
327 reg &= ~LPM_ENABLE_BIT;
328 reg |= (enable ? LPM_ENABLE_BIT : 0);
329
330 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
331 if (rc) {
332 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
333 CHG_CNTRL, rc);
334 return rc;
335 }
336
337 return rc;
338}
339
340static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
341{
342 int rc;
343 unsigned long flags = 0;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800344 u8 temp;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700345
346 /* Disable LPM */
347 if (chip->lockup_lpm_wrkarnd) {
348 spin_lock_irqsave(&lpm_lock, flags);
349
350 /*
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800351 * This delay is to prevent exit out of 32khz mode within
352 * 200uS. It could be that chg was removed just few uS before
353 * this gets called.
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700354 */
355 udelay(200);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800356 /* no clks */
357 temp = 0xD1;
358 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
359 if (rc) {
360 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
361 goto release_lpm_lock;
362 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700363
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800364 /* force 19.2Mhz before reading */
365 temp = 0xD3;
366 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
367 if (rc) {
368 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
369 goto release_lpm_lock;
370 }
371
372 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
373 if (rc) {
374 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
375 goto release_lpm_lock;
376 }
377
378 /* no clks */
379 temp = 0xD1;
380 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
381 if (rc) {
382 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
383 goto release_lpm_lock;
384 }
385
386 /* switch to hw clk selection */
387 temp = 0xD0;
388 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
389 if (rc) {
390 pr_err("Error %d writing %d to CHG_TEST\n", rc, temp);
391 goto release_lpm_lock;
392 }
393
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700394 udelay(200);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700395
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800396release_lpm_lock:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700397 spin_unlock_irqrestore(&lpm_lock, flags);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800398 } else {
399 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
400 if (rc)
401 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
402 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700403 return rc;
404}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700405
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700406static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
407 u8 mask, u8 val)
408{
409 int rc;
410 u8 reg;
411
412 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
413 if (rc) {
414 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
415 return rc;
416 }
417 reg &= ~mask;
418 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700419 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700421 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 return rc;
423 }
424 return 0;
425}
426
David Keitelcf867232012-01-27 18:40:12 -0800427static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
428{
429 return pm8xxx_read_irq_stat(chip->dev->parent,
430 chip->pmic_chg_irq[irq_id]);
431}
432
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700433static int is_chg_on_bat(struct pm8921_chg_chip *chip)
434{
435 return !(pm_chg_get_rt_status(chip, DCIN_VALID_IRQ)
436 || pm_chg_get_rt_status(chip, USBIN_VALID_IRQ));
437}
438
439static void pm8921_chg_bypass_bat_gone_debounce(struct pm8921_chg_chip *chip,
440 int bypass)
441{
442 int rc;
443
444 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, bypass ? 0x89 : 0x88);
445 if (rc) {
446 pr_err("Failed to set bypass bit to %d rc=%d\n", bypass, rc);
447 }
448}
449
David Keitelcf867232012-01-27 18:40:12 -0800450/* Treat OverVoltage/UnderVoltage as source missing */
451static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
452{
453 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
454}
455
456/* Treat OverVoltage/UnderVoltage as source missing */
457static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
458{
459 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
460}
461
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700462static int is_batfet_closed(struct pm8921_chg_chip *chip)
463{
464 return pm_chg_get_rt_status(chip, BATFET_IRQ);
465}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466#define CAPTURE_FSM_STATE_CMD 0xC2
467#define READ_BANK_7 0x70
468#define READ_BANK_4 0x40
469static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
470{
471 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800472 unsigned long flags = 0;
473 int err = 0, ret = 0;
474
475 if (chip->lockup_lpm_wrkarnd) {
476 spin_lock_irqsave(&lpm_lock, flags);
477
478 /*
479 * This delay is to prevent exit out of 32khz mode within
480 * 200uS. It could be that chg was removed just few uS before
481 * this gets called.
482 */
483 udelay(200);
484 /* no clks */
485 temp = 0xD1;
486 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
487 if (err) {
488 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
489 goto err_out;
490 }
491
492 /* force 19.2Mhz before reading */
493 temp = 0xD3;
494 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
495 if (err) {
496 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
497 goto err_out;
498 }
499 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500
501 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800502 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 if (err) {
504 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800505 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 }
507
508 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800509 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510 if (err) {
511 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800512 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 }
514
515 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
516 if (err) {
517 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800518 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700519 }
520 /* get the lower 4 bits */
521 ret = temp & 0xF;
522
523 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800524 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 if (err) {
526 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800527 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 }
529
530 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
531 if (err) {
532 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800533 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 }
535 /* get the upper 1 bit */
536 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800537
538 if (chip->lockup_lpm_wrkarnd) {
539 /* no clks */
540 temp = 0xD1;
541 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
542 if (err) {
543 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
544 goto err_out;
545 }
546
547 /* switch to hw clk selection */
548 temp = 0xD0;
549 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
550 if (err) {
551 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
552 goto err_out;
553 }
554
555 udelay(200);
556 }
557
558err_out:
559 if (chip->lockup_lpm_wrkarnd)
560 spin_unlock_irqrestore(&lpm_lock, flags);
561 if (err)
562 return err;
563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564 return ret;
565}
566
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700567#define READ_BANK_6 0x60
568static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
569{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800570 u8 temp, data;
571 unsigned long flags = 0;
572 int err = 0;
573
574 if (chip->lockup_lpm_wrkarnd) {
575 spin_lock_irqsave(&lpm_lock, flags);
576
577 /*
578 * This delay is to prevent exit out of 32khz mode within
579 * 200uS. It could be that chg was removed just few uS before
580 * this gets called.
581 */
582 udelay(200);
583 /* no clks */
584 temp = 0xD1;
585 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
586 if (err) {
587 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
588 goto err_out;
589 }
590
591 /* force 19.2Mhz before reading */
592 temp = 0xD3;
593 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
594 if (err) {
595 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
596 goto err_out;
597 }
598 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700599
600 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800601 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700602 if (err) {
603 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800604 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700605 }
606
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800607 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700608 if (err) {
609 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800610 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700611 }
612
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800613 if (chip->lockup_lpm_wrkarnd) {
614 /* no clks */
615 temp = 0xD1;
616 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
617 if (err) {
618 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
619 goto err_out;
620 }
621
622 /* switch to hw clk selection */
623 temp = 0xD0;
624 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
625 if (err) {
626 pr_err("Error %d writing %d to CHG_TEST\n", err, temp);
627 goto err_out;
628 }
629
630 udelay(200);
631 }
632
633err_out:
634 if (chip->lockup_lpm_wrkarnd)
635 spin_unlock_irqrestore(&lpm_lock, flags);
636 if (err)
637 return err;
638
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700639 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800640 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700641}
642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643#define CHG_USB_SUSPEND_BIT BIT(2)
644static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
645{
646 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
647 enable ? CHG_USB_SUSPEND_BIT : 0);
648}
649
650#define CHG_EN_BIT BIT(7)
651static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
652{
653 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
654 enable ? CHG_EN_BIT : 0);
655}
656
David Keitel753ec8d2011-11-02 10:56:37 -0700657#define CHG_FAILED_CLEAR BIT(0)
658#define ATC_FAILED_CLEAR BIT(1)
659static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
660{
661 int rc;
662
663 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
664 clear ? ATC_FAILED_CLEAR : 0);
665 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
666 clear ? CHG_FAILED_CLEAR : 0);
667 return rc;
668}
669
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670#define CHG_CHARGE_DIS_BIT BIT(1)
671static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
672{
673 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
674 disable ? CHG_CHARGE_DIS_BIT : 0);
675}
676
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800677static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
678{
679 u8 temp;
680
681 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
682 return temp & CHG_CHARGE_DIS_BIT;
683}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684#define PM8921_CHG_V_MIN_MV 3240
685#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800686#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687#define PM8921_CHG_VDDMAX_MAX 4500
688#define PM8921_CHG_VDDMAX_MIN 3400
689#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800690static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800692 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800693 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800695 if (voltage < PM8921_CHG_VDDMAX_MIN
696 || voltage > PM8921_CHG_VDDMAX_MAX) {
697 pr_err("bad mV=%d asked to set\n", voltage);
698 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699 }
David Keitelcf867232012-01-27 18:40:12 -0800700
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800701 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
702
703 remainder = voltage % 20;
704 if (remainder >= 10) {
705 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
706 }
707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700709 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710}
711
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700712static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
713{
714 u8 temp;
715 int rc;
716
717 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
718 if (rc) {
719 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700720 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700721 return rc;
722 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800723 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
724 + PM8921_CHG_V_MIN_MV;
725 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
726 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700727 return 0;
728}
729
David Keitelcf867232012-01-27 18:40:12 -0800730static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
731{
732 int current_mv, ret, steps, i;
733 bool increase;
734
735 ret = 0;
736
737 if (voltage < PM8921_CHG_VDDMAX_MIN
738 || voltage > PM8921_CHG_VDDMAX_MAX) {
739 pr_err("bad mV=%d asked to set\n", voltage);
740 return -EINVAL;
741 }
742
743 ret = pm_chg_vddmax_get(chip, &current_mv);
744 if (ret) {
745 pr_err("Failed to read vddmax rc=%d\n", ret);
746 return -EINVAL;
747 }
748 if (current_mv == voltage)
749 return 0;
750
751 /* Only change in increments when USB is present */
752 if (is_usb_chg_plugged_in(chip)) {
753 if (current_mv < voltage) {
754 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
755 increase = true;
756 } else {
757 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
758 increase = false;
759 }
760 for (i = 0; i < steps; i++) {
761 if (increase)
762 current_mv += PM8921_CHG_V_STEP_MV;
763 else
764 current_mv -= PM8921_CHG_V_STEP_MV;
765 ret |= __pm_chg_vddmax_set(chip, current_mv);
766 }
767 }
768 ret |= __pm_chg_vddmax_set(chip, voltage);
769 return ret;
770}
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772#define PM8921_CHG_VDDSAFE_MIN 3400
773#define PM8921_CHG_VDDSAFE_MAX 4500
774static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
775{
776 u8 temp;
777
778 if (voltage < PM8921_CHG_VDDSAFE_MIN
779 || voltage > PM8921_CHG_VDDSAFE_MAX) {
780 pr_err("bad mV=%d asked to set\n", voltage);
781 return -EINVAL;
782 }
783 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
784 pr_debug("voltage=%d setting %02x\n", voltage, temp);
785 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
786}
787
788#define PM8921_CHG_VBATDET_MIN 3240
789#define PM8921_CHG_VBATDET_MAX 5780
790static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
791{
792 u8 temp;
793
794 if (voltage < PM8921_CHG_VBATDET_MIN
795 || voltage > PM8921_CHG_VBATDET_MAX) {
796 pr_err("bad mV=%d asked to set\n", voltage);
797 return -EINVAL;
798 }
799 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
800 pr_debug("voltage=%d setting %02x\n", voltage, temp);
801 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
802}
803
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700804#define PM8921_CHG_VINMIN_MIN_MV 3800
805#define PM8921_CHG_VINMIN_STEP_MV 100
806#define PM8921_CHG_VINMIN_USABLE_MAX 6500
807#define PM8921_CHG_VINMIN_USABLE_MIN 4300
808#define PM8921_CHG_VINMIN_MASK 0x1F
809static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
810{
811 u8 temp;
812
813 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
814 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
815 pr_err("bad mV=%d asked to set\n", voltage);
816 return -EINVAL;
817 }
818 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
819 pr_debug("voltage=%d setting %02x\n", voltage, temp);
820 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
821 temp);
822}
823
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800824static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
825{
826 u8 temp;
827 int rc, voltage_mv;
828
829 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
830 temp &= PM8921_CHG_VINMIN_MASK;
831
832 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
833 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
834
835 return voltage_mv;
836}
837
David Keitel0789fc62012-06-07 17:43:27 -0700838#define PM8917_USB_UVD_MIN_MV 3850
839#define PM8917_USB_UVD_MAX_MV 4350
840#define PM8917_USB_UVD_STEP_MV 100
841#define PM8917_USB_UVD_MASK 0x7
842static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
843{
844 u8 temp;
845
846 if (thresh_mv < PM8917_USB_UVD_MIN_MV
847 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
848 pr_err("bad mV=%d asked to set\n", thresh_mv);
849 return -EINVAL;
850 }
851 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
852 return pm_chg_masked_write(chip, OVP_USB_UVD,
853 PM8917_USB_UVD_MASK, temp);
854}
855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700857#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858#define PM8921_CHG_I_MIN_MA 225
859#define PM8921_CHG_I_STEP_MA 50
860#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700861static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
862{
863 u8 temp;
864 int rc;
865
866 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
867 if (rc) {
868 pr_err("rc = %d while reading ibat max\n", rc);
869 *ibat_ma = 0;
870 return rc;
871 }
872 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
873 + PM8921_CHG_I_MIN_MA;
874 return 0;
875}
876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
878{
879 u8 temp;
880
881 if (chg_current < PM8921_CHG_IBATMAX_MIN
882 || chg_current > PM8921_CHG_IBATMAX_MAX) {
883 pr_err("bad mA=%d asked to set\n", chg_current);
884 return -EINVAL;
885 }
886 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
887 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
888}
889
890#define PM8921_CHG_IBATSAFE_MIN 225
891#define PM8921_CHG_IBATSAFE_MAX 3375
892static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
893{
894 u8 temp;
895
896 if (chg_current < PM8921_CHG_IBATSAFE_MIN
897 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
898 pr_err("bad mA=%d asked to set\n", chg_current);
899 return -EINVAL;
900 }
901 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
902 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
903 PM8921_CHG_I_MASK, temp);
904}
905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700907#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908#define PM8921_CHG_ITERM_STEP_MA 10
909#define PM8921_CHG_ITERM_MASK 0xF
910static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
911{
912 u8 temp;
913
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700914 if (chg_current < PM8921_CHG_ITERM_MIN_MA
915 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 pr_err("bad mA=%d asked to set\n", chg_current);
917 return -EINVAL;
918 }
919
920 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
921 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700922 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 temp);
924}
925
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700926static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
927{
928 u8 temp;
929 int rc;
930
931 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
932 if (rc) {
933 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700934 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700935 return rc;
936 }
937 temp &= PM8921_CHG_ITERM_MASK;
938 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
939 + PM8921_CHG_ITERM_MIN_MA;
940 return 0;
941}
942
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800943struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700944 int usb_ma;
945 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800946};
947
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700948/* USB Trim tables */
949static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
950 0x0,
951 0x0,
952 -0x9,
953 0x0,
954 -0xD,
955 0x0,
956 -0x10,
957 -0x11,
958 0x0,
959 0x0,
960 -0x25,
961 0x0,
962 -0x28,
963 0x0,
964 -0x32,
965 0x0
966};
967
968static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
969 0x0,
970 0x0,
971 0xA,
972 0xC,
973 0x10,
974 0x10,
975 0x13,
976 0x14,
977 0x13,
978 0x3,
979 0x1A,
980 0x1D,
981 0x1D,
982 0x21,
983 0x24,
984 0x26
985};
986
987/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800988static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700989 {100, 0x0},
990 {200, 0x1},
991 {500, 0x2},
992 {600, 0x3},
993 {700, 0x4},
994 {800, 0x5},
995 {850, 0x6},
996 {900, 0x8},
997 {950, 0x7},
998 {1000, 0x9},
999 {1100, 0xA},
1000 {1200, 0xB},
1001 {1300, 0xC},
1002 {1400, 0xD},
1003 {1500, 0xE},
1004 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001005};
1006
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001007#define REG_SBI_CONFIG 0x04F
1008#define PAGE3_ENABLE_MASK 0x6
1009#define USB_OVP_TRIM_MASK 0x3F
1010#define USB_OVP_TRIM_PM8917_MASK 0x7F
1011#define USB_OVP_TRIM_MIN 0x00
1012#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
1013#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
1014#define REG_USB_OVP_TRIM_PM8917 0x2B5
1015#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
1016static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
1017{
1018 u8 temp, sbi_config, msb, lsb, mask;
1019 s8 trim;
1020 int rc = 0;
1021 static u8 usb_trim_reg_orig = 0xFF;
1022
1023 /* No trim data for PM8921 */
1024 if (!chip->usb_trim_table)
1025 return 0;
1026
1027 if (usb_trim_reg_orig == 0xFF) {
1028 rc = pm8xxx_readb(chip->dev->parent,
1029 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
1030 if (rc) {
1031 pr_err("error = %d reading sbi config reg\n", rc);
1032 return rc;
1033 }
1034
1035 rc = pm8xxx_readb(chip->dev->parent,
1036 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
1037 if (rc) {
1038 pr_err("error = %d reading sbi config reg\n", rc);
1039 return rc;
1040 }
1041
1042 msb = msb >> 5;
1043 lsb = lsb >> 5;
1044 usb_trim_reg_orig = msb << 3 | lsb;
1045
1046 if (pm8xxx_get_version(chip->dev->parent)
1047 == PM8XXX_VERSION_8917) {
1048 rc = pm8xxx_readb(chip->dev->parent,
1049 REG_USB_OVP_TRIM_PM8917, &msb);
1050 if (rc) {
1051 pr_err("error = %d reading config reg\n", rc);
1052 return rc;
1053 }
1054
1055 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
1056 usb_trim_reg_orig |= msb << 6;
1057 }
1058 }
1059
1060 /* use the original trim value */
1061 trim = usb_trim_reg_orig;
1062
1063 trim += chip->usb_trim_table[index];
1064 if (trim < 0)
1065 trim = 0;
1066
1067 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
1068 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
1069
1070 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
1071 if (rc) {
1072 pr_err("error = %d reading sbi config reg\n", rc);
1073 return rc;
1074 }
1075
1076 temp = sbi_config | PAGE3_ENABLE_MASK;
1077 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
1078 if (rc) {
1079 pr_err("error = %d writing sbi config reg\n", rc);
1080 return rc;
1081 }
1082
1083 mask = USB_OVP_TRIM_MASK;
1084
1085 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
1086 mask = USB_OVP_TRIM_PM8917_MASK;
1087
1088 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
1089 if (rc) {
1090 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
1091 return rc;
1092 }
1093
1094 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
1095 if (rc) {
1096 pr_err("error = %d writing sbi config reg\n", rc);
1097 return rc;
1098 }
1099 return rc;
1100}
1101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -07001103#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001104#define PM8921_CHG_IUSB_MAX 7
1105#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -07001106#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001107static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001109 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -07001110 int rc;
1111
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001112 reg_val = usb_ma_table[index].value >> 1;
1113 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -07001115 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
1116 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001117 return -EINVAL;
1118 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001119 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
1120
1121 /* IUSB_FINE_RES */
1122 if (chip->iusb_fine_res) {
1123 /* Clear IUSB_FINE_RES bit to avoid overshoot */
1124 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1125 PM8917_IUSB_FINE_RES, 0);
1126
1127 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
1128 PM8921_CHG_IUSB_MASK, temp);
1129
1130 if (rc) {
1131 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
1132 return rc;
1133 }
1134
1135 if (fineres) {
1136 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
1137 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001138 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001139 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
1140 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001141 return rc;
1142 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001143 }
1144 } else {
1145 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
1146 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001147 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -07001148 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001149 return rc;
1150 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001151 }
1152
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001153 rc = pm_chg_usb_trim(chip, index);
1154 if (rc)
1155 pr_err("unable to set usb trim rc = %d\n", rc);
1156
David Keitel38bdd4f2012-04-19 15:39:13 -07001157 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158}
1159
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001160static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
1161{
David Keitel38bdd4f2012-04-19 15:39:13 -07001162 u8 temp, fineres;
1163 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001164
David Keitel38bdd4f2012-04-19 15:39:13 -07001165 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001166 *mA = 0;
1167 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
1168 if (rc) {
1169 pr_err("err=%d reading PBL_ACCESS2\n", rc);
1170 return rc;
1171 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001172
1173 if (chip->iusb_fine_res) {
1174 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1175 if (rc) {
1176 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1177 return rc;
1178 }
1179 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001180 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001181 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1182
1183 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1184 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1185 if (usb_ma_table[i].value == temp)
1186 break;
1187 }
1188
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001189 if (i < 0) {
1190 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1191 i = 0;
1192 }
1193
Willie Ruan13c972d2012-11-15 11:56:36 -08001194 if (i < 0) {
1195 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1196 i = 0;
1197 }
1198
David Keitel38bdd4f2012-04-19 15:39:13 -07001199 *mA = usb_ma_table[i].usb_ma;
1200
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001201 return rc;
1202}
1203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204#define PM8921_CHG_WD_MASK 0x1F
1205static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1206{
1207 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001208 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1209}
1210
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001211#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001212#define PM8921_CHG_TCHG_MIN 4
1213#define PM8921_CHG_TCHG_MAX 512
1214#define PM8921_CHG_TCHG_STEP 4
1215static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1216{
1217 u8 temp;
1218
1219 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1220 pr_err("bad max minutes =%d asked to set\n", minutes);
1221 return -EINVAL;
1222 }
1223
1224 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1225 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1226 temp);
1227}
1228
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001229#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001230#define PM8921_CHG_TTRKL_MIN 1
1231#define PM8921_CHG_TTRKL_MAX 64
1232static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1233{
1234 u8 temp;
1235
1236 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1237 pr_err("bad max minutes =%d asked to set\n", minutes);
1238 return -EINVAL;
1239 }
1240
1241 temp = minutes - 1;
1242 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1243 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244}
1245
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001246#define PM8921_CHG_VTRKL_MIN_MV 2050
1247#define PM8921_CHG_VTRKL_MAX_MV 2800
1248#define PM8921_CHG_VTRKL_STEP_MV 50
1249#define PM8921_CHG_VTRKL_SHIFT 4
1250#define PM8921_CHG_VTRKL_MASK 0xF0
1251static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1252{
1253 u8 temp;
1254
1255 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1256 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1257 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1258 return -EINVAL;
1259 }
1260
1261 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1262 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1263 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1264 temp);
1265}
1266
1267#define PM8921_CHG_VWEAK_MIN_MV 2100
1268#define PM8921_CHG_VWEAK_MAX_MV 3600
1269#define PM8921_CHG_VWEAK_STEP_MV 100
1270#define PM8921_CHG_VWEAK_MASK 0x0F
1271static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1272{
1273 u8 temp;
1274
1275 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1276 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1277 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1278 return -EINVAL;
1279 }
1280
1281 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1282 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1283 temp);
1284}
1285
1286#define PM8921_CHG_ITRKL_MIN_MA 50
1287#define PM8921_CHG_ITRKL_MAX_MA 200
1288#define PM8921_CHG_ITRKL_MASK 0x0F
1289#define PM8921_CHG_ITRKL_STEP_MA 10
1290static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1291{
1292 u8 temp;
1293
1294 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1295 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1296 pr_err("bad current = %dmA asked to set\n", milliamps);
1297 return -EINVAL;
1298 }
1299
1300 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1301
1302 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1303 temp);
1304}
1305
1306#define PM8921_CHG_IWEAK_MIN_MA 325
1307#define PM8921_CHG_IWEAK_MAX_MA 525
1308#define PM8921_CHG_IWEAK_SHIFT 7
1309#define PM8921_CHG_IWEAK_MASK 0x80
1310static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1311{
1312 u8 temp;
1313
1314 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1315 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1316 pr_err("bad current = %dmA asked to set\n", milliamps);
1317 return -EINVAL;
1318 }
1319
1320 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1321 temp = 0;
1322 else
1323 temp = 1;
1324
1325 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1326 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1327 temp);
1328}
1329
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001330#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1331#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1332static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1333 enum pm8921_chg_cold_thr cold_thr)
1334{
1335 u8 temp;
1336
1337 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1338 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1339 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1340 PM8921_CHG_BATT_TEMP_THR_COLD,
1341 temp);
1342}
1343
1344#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1345#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1346static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1347 enum pm8921_chg_hot_thr hot_thr)
1348{
1349 u8 temp;
1350
1351 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1352 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1353 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1354 PM8921_CHG_BATT_TEMP_THR_HOT,
1355 temp);
1356}
1357
Jay Chokshid674a512012-03-15 14:06:04 -07001358#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1359#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1360static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1361 enum pm8921_chg_led_src_config led_src_config)
1362{
1363 u8 temp;
1364
1365 if (led_src_config < LED_SRC_GND ||
1366 led_src_config > LED_SRC_BYPASS)
1367 return -EINVAL;
1368
1369 if (led_src_config == LED_SRC_BYPASS)
1370 return 0;
1371
1372 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1373
1374 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1375 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1376}
1377
David Keitel8c5201a2012-02-24 16:08:54 -08001378
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001379static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1380{
1381 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001382 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001383
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001384 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001385 if (rc) {
1386 pr_err("error reading batt id channel = %d, rc = %d\n",
1387 chip->vbat_channel, rc);
1388 return rc;
1389 }
1390 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1391 result.measurement);
1392 return result.physical;
1393}
1394
1395static int is_battery_valid(struct pm8921_chg_chip *chip)
1396{
1397 int64_t rc;
1398
1399 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1400 return 1;
1401
1402 rc = read_battery_id(chip);
1403 if (rc < 0) {
1404 pr_err("error reading batt id channel = %d, rc = %lld\n",
1405 chip->vbat_channel, rc);
1406 /* assume battery id is valid when adc error happens */
1407 return 1;
1408 }
1409
1410 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1411 pr_err("batt_id phy =%lld is not valid\n", rc);
1412 return 0;
1413 }
1414 return 1;
1415}
1416
1417static void check_battery_valid(struct pm8921_chg_chip *chip)
1418{
1419 if (is_battery_valid(chip) == 0) {
1420 pr_err("batt_id not valid, disbling charging\n");
1421 pm_chg_auto_enable(chip, 0);
1422 } else {
1423 pm_chg_auto_enable(chip, !charging_disabled);
1424 }
1425}
1426
1427static void battery_id_valid(struct work_struct *work)
1428{
1429 struct pm8921_chg_chip *chip = container_of(work,
1430 struct pm8921_chg_chip, battery_id_valid_work);
1431
1432 check_battery_valid(chip);
1433}
1434
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1436{
1437 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1438 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1439 enable_irq(chip->pmic_chg_irq[interrupt]);
1440 }
1441}
1442
1443static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1444{
1445 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1446 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1447 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1448 }
1449}
1450
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001451static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1452{
1453 return test_bit(interrupt, chip->enabled_irqs);
1454}
1455
Amir Samuelovd31ef502011-10-26 14:41:36 +02001456static bool is_ext_charging(struct pm8921_chg_chip *chip)
1457{
David Keitel88e1b572012-01-11 11:57:14 -08001458 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001459
David Keitel88e1b572012-01-11 11:57:14 -08001460 if (!chip->ext_psy)
1461 return false;
1462 if (chip->ext_psy->get_property(chip->ext_psy,
1463 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1464 return false;
1465 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1466 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001467
1468 return false;
1469}
1470
1471static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1472{
David Keitel88e1b572012-01-11 11:57:14 -08001473 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001474
David Keitel88e1b572012-01-11 11:57:14 -08001475 if (!chip->ext_psy)
1476 return false;
1477 if (chip->ext_psy->get_property(chip->ext_psy,
1478 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1479 return false;
1480 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001481 return true;
1482
1483 return false;
1484}
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486static int is_battery_charging(int fsm_state)
1487{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001488 if (is_ext_charging(the_chip))
1489 return 1;
1490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 switch (fsm_state) {
1492 case FSM_STATE_ATC_2A:
1493 case FSM_STATE_ATC_2B:
1494 case FSM_STATE_ON_CHG_AND_BAT_6:
1495 case FSM_STATE_FAST_CHG_7:
1496 case FSM_STATE_TRKL_CHG_8:
1497 return 1;
1498 }
1499 return 0;
1500}
1501
1502static void bms_notify(struct work_struct *work)
1503{
1504 struct bms_notify *n = container_of(work, struct bms_notify, work);
1505
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001506 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001508 } else {
1509 pm8921_bms_charging_end(n->is_battery_full);
1510 n->is_battery_full = 0;
1511 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512}
1513
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001514static void bms_notify_check(struct pm8921_chg_chip *chip)
1515{
1516 int fsm_state, new_is_charging;
1517
1518 fsm_state = pm_chg_get_fsm_state(chip);
1519 new_is_charging = is_battery_charging(fsm_state);
1520
1521 if (chip->bms_notify.is_charging ^ new_is_charging) {
1522 chip->bms_notify.is_charging = new_is_charging;
1523 schedule_work(&(chip->bms_notify.work));
1524 }
1525}
1526
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001527static enum power_supply_property pm_power_props_usb[] = {
1528 POWER_SUPPLY_PROP_PRESENT,
1529 POWER_SUPPLY_PROP_ONLINE,
1530 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001531 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001532 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001533};
1534
1535static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001537 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001538};
1539
1540static char *pm_power_supplied_to[] = {
1541 "battery",
1542};
1543
David Keitel6ed71a52012-01-30 12:42:18 -08001544#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001545static int pm_power_get_property_mains(struct power_supply *psy,
1546 enum power_supply_property psp,
1547 union power_supply_propval *val)
1548{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001549 int type;
1550
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001551 /* Check if called before init */
1552 if (!the_chip)
1553 return -EINVAL;
1554
1555 switch (psp) {
1556 case POWER_SUPPLY_PROP_PRESENT:
1557 case POWER_SUPPLY_PROP_ONLINE:
1558 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001559
1560 if (the_chip->has_dc_supply) {
1561 val->intval = 1;
1562 return 0;
1563 }
1564
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001565 if (the_chip->dc_present) {
1566 val->intval = 1;
1567 return 0;
1568 }
1569
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301570 type = the_chip->usb_type;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001571 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1572 type == POWER_SUPPLY_TYPE_USB_ACA ||
1573 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001574 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001575
1576 break;
1577 default:
1578 return -EINVAL;
1579 }
1580 return 0;
1581}
1582
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001583static int disable_aicl(int disable)
1584{
1585 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1586 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1587 pr_err("called with invalid param :%d\n", disable);
1588 return -EINVAL;
1589 }
1590
1591 if (!the_chip) {
1592 pr_err("%s called before init\n", __func__);
1593 return -EINVAL;
1594 }
1595
1596 pr_debug("Disable AICL = %d\n", disable);
1597 the_chip->disable_aicl = disable;
1598 return 0;
1599}
1600
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001601static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1602{
1603 int rc;
1604
1605 if (!chip->host_mode)
1606 return 0;
1607
1608 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001609 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001610 if (rc < 0) {
1611 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1612 return rc;
1613 }
1614
1615 chip->host_mode = 0;
1616
1617 return 0;
1618}
1619
1620static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1621{
1622 int rc;
1623
1624 if (chip->host_mode)
1625 return 0;
1626
1627 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001628 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001629 if (rc < 0) {
1630 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1631 return rc;
1632 }
1633
1634 chip->host_mode = 1;
1635
1636 return 0;
1637}
1638
1639static int pm_power_set_property_usb(struct power_supply *psy,
1640 enum power_supply_property psp,
1641 const union power_supply_propval *val)
1642{
1643 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001644 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001645 return -EINVAL;
1646
1647 switch (psp) {
1648 case POWER_SUPPLY_PROP_SCOPE:
1649 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001650 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001651 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001652 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001653 else
1654 return -EINVAL;
1655 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001656 case POWER_SUPPLY_PROP_TYPE:
1657 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001658 case POWER_SUPPLY_PROP_HEALTH:
1659 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1660 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001661 default:
1662 return -EINVAL;
1663 }
1664 return 0;
1665}
1666
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001667static int usb_property_is_writeable(struct power_supply *psy,
1668 enum power_supply_property psp)
1669{
1670 switch (psp) {
1671 case POWER_SUPPLY_PROP_HEALTH:
1672 return 1;
1673 default:
1674 break;
1675 }
1676
1677 return 0;
1678}
1679
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001680static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 enum power_supply_property psp,
1682 union power_supply_propval *val)
1683{
David Keitel6ed71a52012-01-30 12:42:18 -08001684 int current_max;
1685
1686 /* Check if called before init */
1687 if (!the_chip)
1688 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689
1690 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001691 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001692 if (pm_is_chg_charge_dis(the_chip)) {
1693 val->intval = 0;
1694 } else {
1695 pm_chg_iusbmax_get(the_chip, &current_max);
1696 val->intval = current_max;
1697 }
David Keitel6ed71a52012-01-30 12:42:18 -08001698 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001700 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001701 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001702
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301703 if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001704 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001707
1708 case POWER_SUPPLY_PROP_SCOPE:
1709 if (the_chip->host_mode)
1710 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1711 else
1712 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1713 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001714 case POWER_SUPPLY_PROP_HEALTH:
1715 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1716 val->intval = the_chip->disable_aicl;
1717 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 default:
1719 return -EINVAL;
1720 }
1721 return 0;
1722}
1723
1724static enum power_supply_property msm_batt_power_props[] = {
1725 POWER_SUPPLY_PROP_STATUS,
1726 POWER_SUPPLY_PROP_CHARGE_TYPE,
1727 POWER_SUPPLY_PROP_HEALTH,
1728 POWER_SUPPLY_PROP_PRESENT,
1729 POWER_SUPPLY_PROP_TECHNOLOGY,
1730 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1731 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1732 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1733 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001734 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001735 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001736 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001737 POWER_SUPPLY_PROP_CHARGE_FULL,
1738 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739};
1740
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001741static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742{
1743 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001744 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001746 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 if (rc) {
1748 pr_err("error reading adc channel = %d, rc = %d\n",
1749 chip->vbat_channel, rc);
1750 return rc;
1751 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001752 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 result.measurement);
1754 return (int)result.physical;
1755}
1756
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001757static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1758{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001759 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1760 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1761 unsigned int low_voltage = chip->min_voltage_mv;
1762 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001763
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001764 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001765 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001766 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001767 return 100;
1768 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001769 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001770 / (high_voltage - low_voltage);
1771}
1772
David Keitel4f9397b2012-04-16 11:46:16 -07001773static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1774{
1775 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1776}
1777
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001778static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1779{
1780 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1781 int fsm_state = pm_chg_get_fsm_state(chip);
1782 int i;
1783
1784 if (chip->ext_psy) {
1785 if (chip->ext_charge_done)
1786 return POWER_SUPPLY_STATUS_FULL;
1787 if (chip->ext_charging)
1788 return POWER_SUPPLY_STATUS_CHARGING;
1789 }
1790
1791 for (i = 0; i < ARRAY_SIZE(map); i++)
1792 if (map[i].fsm_state == fsm_state)
1793 batt_state = map[i].batt_state;
1794
1795 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1796 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1797 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1798 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1799 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1800
1801 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1802 }
1803 return batt_state;
1804}
1805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1807{
David Keitel4f9397b2012-04-16 11:46:16 -07001808 int percent_soc;
1809
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001810 if (chip->battery_less_hardware)
1811 return 100;
1812
David Keitel4f9397b2012-04-16 11:46:16 -07001813 if (!get_prop_batt_present(chip))
1814 percent_soc = voltage_based_capacity(chip);
1815 else
1816 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001817
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001818 if (percent_soc == -ENXIO)
1819 percent_soc = voltage_based_capacity(chip);
1820
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001821 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001822 pr_warn_ratelimited("low battery charge = %d%%\n",
1823 percent_soc);
1824
1825 if (percent_soc <= chip->resume_charge_percent
1826 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1827 pr_debug("soc fell below %d. charging enabled.\n",
1828 chip->resume_charge_percent);
1829 if (chip->is_bat_warm)
1830 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1831 chip->is_bat_warm,
1832 chip->resume_charge_percent);
1833 else if (chip->is_bat_cool)
1834 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1835 chip->is_bat_cool,
1836 chip->resume_charge_percent);
1837 else
1838 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1839 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001840
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001841 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001842 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843}
1844
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001845static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1846{
1847 return pm8921_bms_get_current_max();
1848}
1849
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001850static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1851{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001852 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001853
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001854 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001855 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001856 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001857 }
1858
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001859 if (rc) {
1860 pr_err("unable to get batt current rc = %d\n", rc);
1861 return rc;
1862 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001863 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001864 }
1865}
1866
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001867static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1868{
1869 int rc;
1870
1871 rc = pm8921_bms_get_fcc();
1872 if (rc < 0)
1873 pr_err("unable to get batt fcc rc = %d\n", rc);
1874 return rc;
1875}
1876
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001877static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1878{
1879 int rc;
1880 int cc_uah;
1881
1882 rc = pm8921_bms_cc_uah(&cc_uah);
1883
1884 if (rc == 0)
1885 return cc_uah;
1886
1887 pr_err("unable to get batt fcc rc = %d\n", rc);
1888 return rc;
1889}
1890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1892{
1893 int temp;
1894
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001895 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1896 if (temp)
1897 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001899 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1900 if (temp)
1901 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001902
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001903 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904}
1905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1907{
1908 int temp;
1909
Amir Samuelovd31ef502011-10-26 14:41:36 +02001910 if (!get_prop_batt_present(chip))
1911 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1912
1913 if (is_ext_trickle_charging(chip))
1914 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1915
1916 if (is_ext_charging(chip))
1917 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1920 if (temp)
1921 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1922
1923 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1924 if (temp)
1925 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1926
1927 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1928}
1929
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001930#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001931static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1932{
1933 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001934 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001935
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001936 if (chip->battery_less_hardware)
1937 return 300;
1938
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001939 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001940 if (rc) {
1941 pr_err("error reading adc channel = %d, rc = %d\n",
1942 chip->vbat_channel, rc);
1943 return rc;
1944 }
1945 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1946 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001947 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1948 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1949 (int) result.physical);
1950
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001951 return (int)result.physical;
1952}
1953
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954static int pm_batt_power_get_property(struct power_supply *psy,
1955 enum power_supply_property psp,
1956 union power_supply_propval *val)
1957{
1958 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1959 batt_psy);
1960
1961 switch (psp) {
1962 case POWER_SUPPLY_PROP_STATUS:
1963 val->intval = get_prop_batt_status(chip);
1964 break;
1965 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1966 val->intval = get_prop_charge_type(chip);
1967 break;
1968 case POWER_SUPPLY_PROP_HEALTH:
1969 val->intval = get_prop_batt_health(chip);
1970 break;
1971 case POWER_SUPPLY_PROP_PRESENT:
1972 val->intval = get_prop_batt_present(chip);
1973 break;
1974 case POWER_SUPPLY_PROP_TECHNOLOGY:
1975 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1976 break;
1977 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001978 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 break;
1980 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001981 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 break;
1983 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001984 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 break;
1986 case POWER_SUPPLY_PROP_CAPACITY:
1987 val->intval = get_prop_batt_capacity(chip);
1988 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001989 case POWER_SUPPLY_PROP_CURRENT_NOW:
1990 val->intval = get_prop_batt_current(chip);
1991 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001992 case POWER_SUPPLY_PROP_CURRENT_MAX:
1993 val->intval = get_prop_batt_current_max(chip);
1994 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001995 case POWER_SUPPLY_PROP_TEMP:
1996 val->intval = get_prop_batt_temp(chip);
1997 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001998 case POWER_SUPPLY_PROP_CHARGE_FULL:
1999 val->intval = get_prop_batt_fcc(chip);
2000 break;
2001 case POWER_SUPPLY_PROP_CHARGE_NOW:
2002 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07002003 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002004 default:
2005 return -EINVAL;
2006 }
2007
2008 return 0;
2009}
2010
2011static void (*notify_vbus_state_func_ptr)(int);
2012static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013
2014int pm8921_charger_register_vbus_sn(void (*callback)(int))
2015{
2016 pr_debug("%p\n", callback);
2017 notify_vbus_state_func_ptr = callback;
2018 return 0;
2019}
2020EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
2021
2022/* this is passed to the hsusb via platform_data msm_otg_pdata */
2023void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
2024{
2025 pr_debug("%p\n", callback);
2026 notify_vbus_state_func_ptr = NULL;
2027}
2028EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
2029
2030static void notify_usb_of_the_plugin_event(int plugin)
2031{
2032 plugin = !!plugin;
2033 if (notify_vbus_state_func_ptr) {
2034 pr_debug("notifying plugin\n");
2035 (*notify_vbus_state_func_ptr) (plugin);
2036 } else {
2037 pr_debug("unable to notify plugin\n");
2038 }
2039}
2040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041static void __pm8921_charger_vbus_draw(unsigned int mA)
2042{
2043 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07002044 if (!the_chip) {
2045 pr_err("called before init\n");
2046 return;
2047 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002049 if (usb_max_current && mA > usb_max_current) {
2050 pr_debug("restricting usb current to %d instead of %d\n",
2051 usb_max_current, mA);
2052 mA = usb_max_current;
2053 }
2054
2055 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08002057 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08002059 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 }
2061 rc = pm_chg_usb_suspend_enable(the_chip, 1);
2062 if (rc)
2063 pr_err("fail to set suspend bit rc=%d\n", rc);
2064 } else {
2065 rc = pm_chg_usb_suspend_enable(the_chip, 0);
2066 if (rc)
2067 pr_err("fail to reset suspend bit rc=%d\n", rc);
2068 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2069 if (usb_ma_table[i].usb_ma <= mA)
2070 break;
2071 }
David Keitel38bdd4f2012-04-19 15:39:13 -07002072
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002073 if (i < 0) {
2074 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2075 mA);
2076 i = 0;
2077 }
2078
Willie Ruan13c972d2012-11-15 11:56:36 -08002079 if (i < 0) {
2080 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2081 mA);
2082 i = 0;
2083 }
2084
David Keitel38bdd4f2012-04-19 15:39:13 -07002085 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07002086 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07002087 && !the_chip->iusb_fine_res)
2088 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 if (i < 0)
2090 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08002091 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002092 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08002093 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002094 }
2095}
2096
2097/* USB calls these to tell us how much max usb current the system can draw */
2098void pm8921_charger_vbus_draw(unsigned int mA)
2099{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002100 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101
2102 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08002103
David Keitel62c6a4b2012-05-17 12:54:59 -07002104 /*
2105 * Reject VBUS requests if USB connection is the only available
2106 * power source. This makes sure that if booting without
2107 * battery the iusb_max value is not decreased avoiding potential
2108 * brown_outs.
2109 *
2110 * This would also apply when the battery has been
2111 * removed from the running system.
2112 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002113 if (the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07002114 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07002115 if (!the_chip->has_dc_supply) {
2116 pr_err("rejected: no other power source connected\n");
2117 return;
2118 }
David Keitel62c6a4b2012-05-17 12:54:59 -07002119 }
2120
David Keitelacf57c82012-03-07 18:48:50 -08002121 if (usb_max_current && mA > usb_max_current) {
2122 pr_warn("restricting usb current to %d instead of %d\n",
2123 usb_max_current, mA);
2124 mA = usb_max_current;
2125 }
Devin Kim2073afb2012-09-05 13:01:51 -07002126 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
2127 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08002128
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302129 if (usb_target_ma)
2130 usb_target_ma = mA;
2131
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002132
2133 if (mA > USB_WALL_THRESHOLD_MA)
2134 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
2135 else
2136 set_usb_now_ma = mA;
2137
2138 if (the_chip && the_chip->disable_aicl)
2139 set_usb_now_ma = mA;
2140
2141 if (the_chip)
2142 __pm8921_charger_vbus_draw(set_usb_now_ma);
2143 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 /*
2145 * called before pmic initialized,
2146 * save this value and use it at probe
2147 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002148 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002149}
2150EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
2151
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002152int pm8921_is_usb_chg_plugged_in(void)
2153{
2154 if (!the_chip) {
2155 pr_err("called before init\n");
2156 return -EINVAL;
2157 }
2158 return is_usb_chg_plugged_in(the_chip);
2159}
2160EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
2161
2162int pm8921_is_dc_chg_plugged_in(void)
2163{
2164 if (!the_chip) {
2165 pr_err("called before init\n");
2166 return -EINVAL;
2167 }
2168 return is_dc_chg_plugged_in(the_chip);
2169}
2170EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
2171
2172int pm8921_is_battery_present(void)
2173{
2174 if (!the_chip) {
2175 pr_err("called before init\n");
2176 return -EINVAL;
2177 }
2178 return get_prop_batt_present(the_chip);
2179}
2180EXPORT_SYMBOL(pm8921_is_battery_present);
2181
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002182int pm8921_is_batfet_closed(void)
2183{
2184 if (!the_chip) {
2185 pr_err("called before init\n");
2186 return -EINVAL;
2187 }
2188 return is_batfet_closed(the_chip);
2189}
2190EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002191/*
2192 * Disabling the charge current limit causes current
2193 * current limits to have no monitoring. An adequate charger
2194 * capable of supplying high current while sustaining VIN_MIN
2195 * is required if the limiting is disabled.
2196 */
2197int pm8921_disable_input_current_limit(bool disable)
2198{
2199 if (!the_chip) {
2200 pr_err("called before init\n");
2201 return -EINVAL;
2202 }
2203 if (disable) {
2204 pr_warn("Disabling input current limit!\n");
2205
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002206 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002207 }
2208 return 0;
2209}
2210EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2211
David Keitel0789fc62012-06-07 17:43:27 -07002212int pm8917_set_under_voltage_detection_threshold(int mv)
2213{
2214 if (!the_chip) {
2215 pr_err("called before init\n");
2216 return -EINVAL;
2217 }
2218 return pm_chg_uvd_threshold_set(the_chip, mv);
2219}
2220EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2221
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002222int pm8921_set_max_battery_charge_current(int ma)
2223{
2224 if (!the_chip) {
2225 pr_err("called before init\n");
2226 return -EINVAL;
2227 }
2228 return pm_chg_ibatmax_set(the_chip, ma);
2229}
2230EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2231
2232int pm8921_disable_source_current(bool disable)
2233{
2234 if (!the_chip) {
2235 pr_err("called before init\n");
2236 return -EINVAL;
2237 }
2238 if (disable)
2239 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002240
2241 pm_chg_usb_suspend_enable(the_chip, disable);
2242
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002243 return pm_chg_charge_dis(the_chip, disable);
2244}
2245EXPORT_SYMBOL(pm8921_disable_source_current);
2246
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002247int pm8921_regulate_input_voltage(int voltage)
2248{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002249 int rc;
2250
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002251 if (!the_chip) {
2252 pr_err("called before init\n");
2253 return -EINVAL;
2254 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002255 rc = pm_chg_vinmin_set(the_chip, voltage);
2256
2257 if (rc == 0)
2258 the_chip->vin_min = voltage;
2259
2260 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002261}
2262
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002263#define USB_OV_THRESHOLD_MASK 0x60
2264#define USB_OV_THRESHOLD_SHIFT 5
2265int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2266{
2267 u8 temp;
2268
2269 if (!the_chip) {
2270 pr_err("called before init\n");
2271 return -EINVAL;
2272 }
2273
2274 if (ov > PM_USB_OV_7V) {
2275 pr_err("limiting to over voltage threshold to 7volts\n");
2276 ov = PM_USB_OV_7V;
2277 }
2278
2279 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2280
2281 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2282 USB_OV_THRESHOLD_MASK, temp);
2283}
2284EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2285
2286#define USB_DEBOUNCE_TIME_MASK 0x06
2287#define USB_DEBOUNCE_TIME_SHIFT 1
2288int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2289{
2290 u8 temp;
2291
2292 if (!the_chip) {
2293 pr_err("called before init\n");
2294 return -EINVAL;
2295 }
2296
2297 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2298 pr_err("limiting debounce to 80.5ms\n");
2299 ms = PM_USB_DEBOUNCE_80P5MS;
2300 }
2301
2302 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2303
2304 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2305 USB_DEBOUNCE_TIME_MASK, temp);
2306}
2307EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2308
2309#define USB_OVP_DISABLE_MASK 0x80
2310int pm8921_usb_ovp_disable(int disable)
2311{
2312 u8 temp = 0;
2313
2314 if (!the_chip) {
2315 pr_err("called before init\n");
2316 return -EINVAL;
2317 }
2318
2319 if (disable)
2320 temp = USB_OVP_DISABLE_MASK;
2321
2322 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2323 USB_OVP_DISABLE_MASK, temp);
2324}
2325
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002326bool pm8921_is_battery_charging(int *source)
2327{
2328 int fsm_state, is_charging, dc_present, usb_present;
2329
2330 if (!the_chip) {
2331 pr_err("called before init\n");
2332 return -EINVAL;
2333 }
2334 fsm_state = pm_chg_get_fsm_state(the_chip);
2335 is_charging = is_battery_charging(fsm_state);
2336 if (is_charging == 0) {
2337 *source = PM8921_CHG_SRC_NONE;
2338 return is_charging;
2339 }
2340
2341 if (source == NULL)
2342 return is_charging;
2343
2344 /* the battery is charging, the source is requested, find it */
2345 dc_present = is_dc_chg_plugged_in(the_chip);
2346 usb_present = is_usb_chg_plugged_in(the_chip);
2347
2348 if (dc_present && !usb_present)
2349 *source = PM8921_CHG_SRC_DC;
2350
2351 if (usb_present && !dc_present)
2352 *source = PM8921_CHG_SRC_USB;
2353
2354 if (usb_present && dc_present)
2355 /*
2356 * The system always chooses dc for charging since it has
2357 * higher priority.
2358 */
2359 *source = PM8921_CHG_SRC_DC;
2360
2361 return is_charging;
2362}
2363EXPORT_SYMBOL(pm8921_is_battery_charging);
2364
David Keitel86034022012-04-18 12:33:58 -07002365int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2366{
2367 if (!the_chip) {
2368 pr_err("called before init\n");
2369 return -EINVAL;
2370 }
2371
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002372 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002373 return -EINVAL;
2374
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05302375 the_chip->usb_type = type;
David Keitel86034022012-04-18 12:33:58 -07002376 power_supply_changed(&the_chip->usb_psy);
2377 power_supply_changed(&the_chip->dc_psy);
2378 return 0;
2379}
2380EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2381
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002382int pm8921_batt_temperature(void)
2383{
2384 if (!the_chip) {
2385 pr_err("called before init\n");
2386 return -EINVAL;
2387 }
2388 return get_prop_batt_temp(the_chip);
2389}
2390
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002391static int __pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002392{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002393 int err;
2394 u8 temp;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002395
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002396
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002397 temp = 0xD1;
2398 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2399 if (err) {
2400 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002401 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002402 }
2403
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002404 temp = 0xD3;
2405 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2406 if (err) {
2407 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002408 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002409 }
2410
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002411 temp = 0xD1;
2412 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2413 if (err) {
2414 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002415 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002416 }
2417
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002418 temp = 0xD5;
2419 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2420 if (err) {
2421 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002422 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002423 }
2424
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002425 /* Wait a few clock cycles before re-enabling hw clock switching */
2426 udelay(183);
2427
2428 temp = 0xD1;
2429 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2430 if (err) {
2431 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002432 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002433 }
2434
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002435 temp = 0xD0;
2436 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
2437 if (err) {
2438 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002439 return err;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002440 }
2441
2442 /* Wait for few clock cycles before re-enabling LPM */
2443 udelay(32);
2444
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08002445 return 0;
2446}
2447
2448static int pm8921_apply_19p2mhz_kickstart(struct pm8921_chg_chip *chip)
2449{
2450 int err;
2451 unsigned long flags = 0;
2452
2453 spin_lock_irqsave(&lpm_lock, flags);
2454 err = pm8921_chg_set_lpm(chip, 0);
2455 if (err) {
2456 pr_err("Error settig LPM rc=%d\n", err);
2457 goto kick_err;
2458 }
2459
2460 __pm8921_apply_19p2mhz_kickstart(chip);
2461
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002462kick_err:
2463 err = pm8921_chg_set_lpm(chip, 1);
2464 if (err)
2465 pr_err("Error settig LPM rc=%d\n", err);
2466
2467 spin_unlock_irqrestore(&lpm_lock, flags);
2468
2469 return err;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07002470}
2471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2473{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002474 int usb_present, rc = 0;
2475
2476 if (chip->lockup_lpm_wrkarnd) {
2477 rc = pm8921_apply_19p2mhz_kickstart(chip);
2478 if (rc)
2479 pr_err("Failed to apply kickstart rc=%d\n", rc);
2480 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002481
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002482 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483 usb_present = is_usb_chg_plugged_in(chip);
2484 if (chip->usb_present ^ usb_present) {
2485 notify_usb_of_the_plugin_event(usb_present);
2486 chip->usb_present = usb_present;
2487 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002488 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002489 pm8921_bms_calibrate_hkadc();
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002490
2491 /* Enable/disable bypass if charger is on battery */
2492 if (chip->lockup_lpm_wrkarnd)
2493 pm8921_chg_bypass_bat_gone_debounce(chip,
2494 is_chg_on_bat(chip));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002496 if (usb_present) {
2497 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002498 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002499 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2500 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002501 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002502 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002503 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002504 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002505 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506}
2507
Amir Samuelovd31ef502011-10-26 14:41:36 +02002508static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2509{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002510 if (chip->lockup_lpm_wrkarnd)
2511 /* Enable bypass if charger is on battery */
2512 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2513
David Keitel88e1b572012-01-11 11:57:14 -08002514 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002515 pr_debug("external charger not registered.\n");
2516 return;
2517 }
2518
2519 if (!chip->ext_charging) {
2520 pr_debug("already not charging.\n");
2521 return;
2522 }
2523
David Keitel88e1b572012-01-11 11:57:14 -08002524 power_supply_set_charge_type(chip->ext_psy,
2525 POWER_SUPPLY_CHARGE_TYPE_NONE);
2526 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002527 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002528 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002529 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002530 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002531 /* Update battery charging LEDs and user space battery info */
2532 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002533}
2534
2535static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2536{
2537 int dc_present;
2538 int batt_present;
2539 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002540 unsigned long delay =
2541 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2542
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002543 /* Disable bypass if charger connected and not running on bat */
2544 if (chip->lockup_lpm_wrkarnd)
2545 pm8921_chg_bypass_bat_gone_debounce(chip, is_chg_on_bat(chip));
2546
David Keitel88e1b572012-01-11 11:57:14 -08002547 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002548 pr_debug("external charger not registered.\n");
2549 return;
2550 }
2551
2552 if (chip->ext_charging) {
2553 pr_debug("already charging.\n");
2554 return;
2555 }
2556
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002557 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002558 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2559 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002560
2561 if (!dc_present) {
2562 pr_warn("%s. dc not present.\n", __func__);
2563 return;
2564 }
2565 if (!batt_present) {
2566 pr_warn("%s. battery not present.\n", __func__);
2567 return;
2568 }
2569 if (!batt_temp_ok) {
2570 pr_warn("%s. battery temperature not ok.\n", __func__);
2571 return;
2572 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002573
2574 /* Force BATFET=ON */
2575 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002576
David Keitel6ccbf132012-05-30 14:21:24 -07002577 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002578 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002579
David Keitel63f71662012-02-08 20:30:00 -08002580 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002581 power_supply_set_charge_type(chip->ext_psy,
2582 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002583 chip->ext_charging = true;
2584 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002585 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002586 /*
2587 * since we wont get a fastchg irq from external charger
2588 * use eoc worker to detect end of charging
2589 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002590 schedule_delayed_work(&chip->eoc_work, delay);
2591 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002592 if (chip->btc_override)
2593 schedule_delayed_work(&chip->btc_override_work,
2594 round_jiffies_relative(msecs_to_jiffies
2595 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002596 /* Update battery charging LEDs and user space battery info */
2597 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002598}
2599
David Keitel6ccbf132012-05-30 14:21:24 -07002600static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002601{
2602 u8 temp;
2603 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002604
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002605 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002606 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002607 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002608 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002609 }
David Keitel6ccbf132012-05-30 14:21:24 -07002610 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002611 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002612 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002613 return;
2614 }
2615 /* set ovp fet disable bit and the write bit */
2616 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002617 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002618 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002619 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002620 return;
2621 }
2622}
2623
David Keitel6ccbf132012-05-30 14:21:24 -07002624static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002625{
2626 u8 temp;
2627 int rc;
2628
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002629 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002630 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002631 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002632 return;
2633 }
David Keitel6ccbf132012-05-30 14:21:24 -07002634 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002635 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002636 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002637 return;
2638 }
2639 /* unset ovp fet disable bit and set the write bit */
2640 temp &= 0xFE;
2641 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002642 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002643 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002644 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002645 temp, rc);
2646 return;
2647 }
2648}
2649
2650static int param_open_ovp_counter = 10;
2651module_param(param_open_ovp_counter, int, 0644);
2652
David Keitel6ccbf132012-05-30 14:21:24 -07002653#define USB_ACTIVE_BIT BIT(5)
2654#define DC_ACTIVE_BIT BIT(6)
2655static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2656 u8 active_chg_mask)
2657{
2658 if (active_chg_mask & USB_ACTIVE_BIT)
2659 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2660 else if (active_chg_mask & DC_ACTIVE_BIT)
2661 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2662 else
2663 return 0;
2664}
2665
David Keitel8c5201a2012-02-24 16:08:54 -08002666#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002667#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002668static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002669{
David Keitel6ccbf132012-05-30 14:21:24 -07002670 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002671 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002672 u8 active_mask = 0;
2673 u16 ovpreg, ovptestreg;
2674
2675 if (is_usb_chg_plugged_in(chip) &&
2676 (chip->active_path & USB_ACTIVE_BIT)) {
2677 ovpreg = USB_OVP_CONTROL;
2678 ovptestreg = USB_OVP_TEST;
2679 active_mask = USB_ACTIVE_BIT;
2680 } else if (is_dc_chg_plugged_in(chip) &&
2681 (chip->active_path & DC_ACTIVE_BIT)) {
2682 ovpreg = DC_OVP_CONTROL;
2683 ovptestreg = DC_OVP_TEST;
2684 active_mask = DC_ACTIVE_BIT;
2685 } else {
2686 return;
2687 }
David Keitel8c5201a2012-02-24 16:08:54 -08002688
2689 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002690 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002691 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002692 active_chg_plugged_in
2693 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002694 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002695 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2696 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002697
2698 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002699 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002700 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002701 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002702
2703 msleep(20);
2704
David Keitel6ccbf132012-05-30 14:21:24 -07002705 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002706 } else {
David Keitel712782e2012-03-29 14:11:47 -07002707 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002708 }
2709 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002710 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2711 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2712 else
2713 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2714
David Keitel6ccbf132012-05-30 14:21:24 -07002715 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2716 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002717 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002718}
David Keitelacf57c82012-03-07 18:48:50 -08002719
2720static int find_usb_ma_value(int value)
2721{
2722 int i;
2723
2724 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2725 if (value >= usb_ma_table[i].usb_ma)
2726 break;
2727 }
2728
2729 return i;
2730}
2731
2732static void decrease_usb_ma_value(int *value)
2733{
2734 int i;
2735
2736 if (value) {
2737 i = find_usb_ma_value(*value);
2738 if (i > 0)
2739 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002740 while (!the_chip->iusb_fine_res && i > 0
2741 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2742 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002743
2744 if (i < 0) {
2745 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2746 *value);
2747 i = 0;
2748 }
2749
David Keitelacf57c82012-03-07 18:48:50 -08002750 *value = usb_ma_table[i].usb_ma;
2751 }
2752}
2753
2754static void increase_usb_ma_value(int *value)
2755{
2756 int i;
2757
2758 if (value) {
2759 i = find_usb_ma_value(*value);
2760
2761 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2762 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002763 /* Get next correct entry if IUSB_FINE_RES is not available */
2764 while (!the_chip->iusb_fine_res
2765 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2766 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2767 i++;
2768
David Keitelacf57c82012-03-07 18:48:50 -08002769 *value = usb_ma_table[i].usb_ma;
2770 }
2771}
2772
2773static void vin_collapse_check_worker(struct work_struct *work)
2774{
2775 struct delayed_work *dwork = to_delayed_work(work);
2776 struct pm8921_chg_chip *chip = container_of(dwork,
2777 struct pm8921_chg_chip, vin_collapse_check_work);
2778
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002779 /*
2780 * AICL only for wall-chargers. If the charger appears to be plugged
2781 * back in now, the corresponding unplug must have been because of we
2782 * were trying to draw more current than the charger can support. In
2783 * such a case reset usb current to 500mA and decrease the target.
2784 * The AICL algorithm will step up the current from 500mA to target
2785 */
2786 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002787 && usb_target_ma > USB_WALL_THRESHOLD_MA
2788 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002789 /* decrease usb_target_ma */
2790 decrease_usb_ma_value(&usb_target_ma);
2791 /* reset here, increase in unplug_check_worker */
2792 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2793 pr_debug("usb_now=%d, usb_target = %d\n",
2794 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002795 if (!delayed_work_pending(&chip->unplug_check_work))
2796 schedule_delayed_work(&chip->unplug_check_work,
2797 msecs_to_jiffies
2798 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002799 } else {
2800 handle_usb_insertion_removal(chip);
2801 }
2802}
2803
2804#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2806{
David Keitelacf57c82012-03-07 18:48:50 -08002807 if (usb_target_ma)
2808 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2809 round_jiffies_relative(msecs_to_jiffies
2810 (VIN_MIN_COLLAPSE_CHECK_MS)));
2811 else
2812 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813 return IRQ_HANDLED;
2814}
2815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2817{
2818 struct pm8921_chg_chip *chip = data;
2819 int status;
2820
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002821 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2822 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002823 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002824 pr_debug("battery present=%d", status);
2825 power_supply_changed(&chip->batt_psy);
2826 return IRQ_HANDLED;
2827}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002828
2829/*
2830 * this interrupt used to restart charging a battery.
2831 *
2832 * Note: When DC-inserted the VBAT can't go low.
2833 * VPH_PWR is provided by the ext-charger.
2834 * After End-Of-Charging from DC, charging can be resumed only
2835 * if DC is removed and then inserted after the battery was in use.
2836 * Therefore the handle_start_ext_chg() is not called.
2837 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2839{
2840 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002841 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002843 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002844
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002845 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002846 /* enable auto charging */
2847 pm_chg_auto_enable(chip, !charging_disabled);
2848 pr_info("batt fell below resume voltage %s\n",
2849 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002850 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002852
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853 power_supply_changed(&chip->batt_psy);
2854 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002855 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002856
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002857 return IRQ_HANDLED;
2858}
2859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2861{
2862 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2863 return IRQ_HANDLED;
2864}
2865
2866static irqreturn_t vcp_irq_handler(int irq, void *data)
2867{
David Keitel8c5201a2012-02-24 16:08:54 -08002868 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 return IRQ_HANDLED;
2870}
2871
2872static irqreturn_t atcdone_irq_handler(int irq, void *data)
2873{
2874 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2875 return IRQ_HANDLED;
2876}
2877
2878static irqreturn_t atcfail_irq_handler(int irq, void *data)
2879{
2880 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2881 return IRQ_HANDLED;
2882}
2883
2884static irqreturn_t chgdone_irq_handler(int irq, void *data)
2885{
2886 struct pm8921_chg_chip *chip = data;
2887
2888 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002889
2890 handle_stop_ext_chg(chip);
2891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 power_supply_changed(&chip->batt_psy);
2893 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002894 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002895
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002896 bms_notify_check(chip);
2897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002898 return IRQ_HANDLED;
2899}
2900
2901static irqreturn_t chgfail_irq_handler(int irq, void *data)
2902{
2903 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002904 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002905
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002906 if (!chip->stop_chg_upon_expiry) {
2907 ret = pm_chg_failed_clear(chip, 1);
2908 if (ret)
2909 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2910 }
David Keitel753ec8d2011-11-02 10:56:37 -07002911
2912 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2913 get_prop_batt_present(chip),
2914 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2915 pm_chg_get_fsm_state(data));
2916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917 power_supply_changed(&chip->batt_psy);
2918 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002919 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 return IRQ_HANDLED;
2921}
2922
2923static irqreturn_t chgstate_irq_handler(int irq, void *data)
2924{
2925 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926
2927 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2928 power_supply_changed(&chip->batt_psy);
2929 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002930 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002932 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 return IRQ_HANDLED;
2935}
2936
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002937enum {
2938 PON_TIME_25NS = 0x04,
2939 PON_TIME_50NS = 0x08,
2940 PON_TIME_100NS = 0x0C,
2941};
David Keitel8c5201a2012-02-24 16:08:54 -08002942
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002943static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002944{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002945 u8 temp;
2946 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002947
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002948 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2949 if (rc) {
2950 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2951 return;
2952 }
2953 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2954 if (rc) {
2955 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2956 return;
2957 }
2958 /* clear the min pon time select bit */
2959 temp &= 0xF3;
2960 /* set the pon time */
2961 temp |= (u8)pon_time_ns;
2962 /* write enable bank 4 */
2963 temp |= 0x80;
2964 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2965 if (rc) {
2966 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2967 return;
2968 }
2969}
David Keitel8c5201a2012-02-24 16:08:54 -08002970
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002971static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2972{
2973 pr_debug("Start\n");
2974 set_min_pon_time(chip, PON_TIME_100NS);
2975 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2976 msleep(250);
2977 pm_chg_vinmin_set(chip, chip->vin_min);
2978 set_min_pon_time(chip, PON_TIME_25NS);
2979 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002980}
2981
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002982#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002983#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2984#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002985static void unplug_check_worker(struct work_struct *work)
2986{
2987 struct delayed_work *dwork = to_delayed_work(work);
2988 struct pm8921_chg_chip *chip = container_of(dwork,
2989 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002990 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002991 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002992 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002993 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002994
2995 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2996 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002997 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2998 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002999 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003000
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003001 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003002 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07003003 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
3004 active_path, active_chg_plugged_in);
3005 if (active_path & USB_ACTIVE_BIT) {
3006 pr_debug("USB charger active\n");
3007
3008 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07003009
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003010 if (usb_ma <= 100) {
3011 pr_debug(
3012 "Unenumerated or suspended usb_ma = %d skip\n",
3013 usb_ma);
3014 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07003015 }
3016 } else if (active_path & DC_ACTIVE_BIT) {
3017 pr_debug("DC charger active\n");
3018 } else {
3019 /* No charger active */
3020 if (!(is_usb_chg_plugged_in(chip)
3021 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003022 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07003023 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
3024 pm_chg_get_regulation_loop(chip),
3025 pm_chg_get_fsm_state(chip),
3026 get_prop_batt_current(chip)
3027 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003028 if (chip->lockup_lpm_wrkarnd) {
3029 rc = pm8921_apply_19p2mhz_kickstart(chip);
3030 if (rc)
3031 pr_err("Failed kickstart rc=%d\n", rc);
3032
3033 /*
3034 * Make sure kickstart happens at least 200 ms
3035 * after charger has been removed.
3036 */
3037 if (chip->final_kickstart) {
3038 chip->final_kickstart = false;
3039 goto check_again_later;
3040 }
3041 }
3042 return;
3043 } else {
3044 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07003045 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003046 }
David Keitel8c5201a2012-02-24 16:08:54 -08003047
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003048 chip->final_kickstart = true;
3049
3050 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003051 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
3052 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07003053 reg_loop = pm_chg_get_regulation_loop(chip);
3054 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
3055 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003056 (usb_ma > USB_WALL_THRESHOLD_MA)
3057 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07003058 decrease_usb_ma_value(&usb_ma);
3059 usb_target_ma = usb_ma;
3060 /* end AICL here */
3061 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003062 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07003063 usb_ma, usb_target_ma);
3064 }
David Keitelacf57c82012-03-07 18:48:50 -08003065 }
3066
3067 reg_loop = pm_chg_get_regulation_loop(chip);
3068 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
3069
David Keitel6ccbf132012-05-30 14:21:24 -07003070 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08003071 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003072 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003073 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
3074 ibat, pm_chg_get_fsm_state(chip), reg_loop);
3075 attempt_reverse_boost_fix(chip);
3076 /* after reverse boost fix check if the active
3077 * charger was detected as removed */
3078 active_chg_plugged_in
3079 = is_active_chg_plugged_in(chip,
3080 active_path);
3081 pr_debug("revboost post: active_chg_plugged_in = %d\n",
3082 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003083 }
3084 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003085
3086 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07003087 pr_debug("active_path = 0x%x, active_chg = %d\n",
3088 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08003089 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3090
David Keitel6ccbf132012-05-30 14:21:24 -07003091 if (chg_gone == 1 && active_chg_plugged_in == 1) {
3092 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
3093 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07003094 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08003095 }
3096
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003097 /* AICL only for usb wall charger */
3098 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
3099 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003100 && !charging_disabled
3101 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08003102 /* only increase iusb_max if vin loop not active */
3103 if (usb_ma < usb_target_ma) {
3104 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05303105 if (usb_ma > usb_target_ma)
3106 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08003107 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003108 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08003109 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003110 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07003111 } else {
3112 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08003113 }
3114 }
Devin Kim2073afb2012-09-05 13:01:51 -07003115check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003116 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08003117 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003118 if (ramp)
3119 schedule_delayed_work(&chip->unplug_check_work,
3120 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
3121 else
3122 schedule_delayed_work(&chip->unplug_check_work,
3123 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003124}
3125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126static irqreturn_t loop_change_irq_handler(int irq, void *data)
3127{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003128 struct pm8921_chg_chip *chip = data;
3129
3130 pr_debug("fsm_state=%d reg_loop=0x%x\n",
3131 pm_chg_get_fsm_state(data),
3132 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07003133 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134 return IRQ_HANDLED;
3135}
3136
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003137struct ibatmax_max_adj_entry {
3138 int ibat_max_ma;
3139 int max_adj_ma;
3140};
3141
3142static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
3143 {975, 300},
3144 {1475, 150},
3145 {1975, 200},
3146 {2475, 250},
3147};
3148
3149static int find_ibat_max_adj_ma(int ibat_target_ma)
3150{
3151 int i = 0;
3152
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08003153 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
3154 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003155 break;
3156 }
3157
3158 return ibatmax_adj_table[i].max_adj_ma;
3159}
3160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161static irqreturn_t fastchg_irq_handler(int irq, void *data)
3162{
3163 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003164 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003166 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3167 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
3168 wake_lock(&chip->eoc_wake_lock);
3169 schedule_delayed_work(&chip->eoc_work,
3170 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003171 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003172 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003173 if (high_transition
3174 && chip->btc_override
3175 && !delayed_work_pending(&chip->btc_override_work)) {
3176 schedule_delayed_work(&chip->btc_override_work,
3177 round_jiffies_relative(msecs_to_jiffies
3178 (chip->btc_delay_ms)));
3179 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003180 power_supply_changed(&chip->batt_psy);
3181 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182 return IRQ_HANDLED;
3183}
3184
3185static irqreturn_t trklchg_irq_handler(int irq, void *data)
3186{
3187 struct pm8921_chg_chip *chip = data;
3188
3189 power_supply_changed(&chip->batt_psy);
3190 return IRQ_HANDLED;
3191}
3192
3193static irqreturn_t batt_removed_irq_handler(int irq, void *data)
3194{
3195 struct pm8921_chg_chip *chip = data;
3196 int status;
3197
3198 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
3199 pr_debug("battery present=%d state=%d", !status,
3200 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003201 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 power_supply_changed(&chip->batt_psy);
3203 return IRQ_HANDLED;
3204}
3205
3206static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
3207{
3208 struct pm8921_chg_chip *chip = data;
3209
Amir Samuelovd31ef502011-10-26 14:41:36 +02003210 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003211 power_supply_changed(&chip->batt_psy);
3212 return IRQ_HANDLED;
3213}
3214
3215static irqreturn_t chghot_irq_handler(int irq, void *data)
3216{
3217 struct pm8921_chg_chip *chip = data;
3218
3219 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
3220 power_supply_changed(&chip->batt_psy);
3221 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08003222 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003223 return IRQ_HANDLED;
3224}
3225
3226static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
3227{
3228 struct pm8921_chg_chip *chip = data;
3229
3230 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02003231 handle_stop_ext_chg(chip);
3232
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003233 power_supply_changed(&chip->batt_psy);
3234 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003235 return IRQ_HANDLED;
3236}
3237
3238static irqreturn_t chg_gone_irq_handler(int irq, void *data)
3239{
3240 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07003241 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08003242
3243 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
3244 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
3245
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003246 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
3247 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07003248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 power_supply_changed(&chip->batt_psy);
3250 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003251 return IRQ_HANDLED;
3252}
David Keitel52fda532011-11-10 10:43:44 -08003253/*
3254 *
3255 * bat_temp_ok_irq_handler - is edge triggered, hence it will
3256 * fire for two cases:
3257 *
3258 * If the interrupt line switches to high temperature is okay
3259 * and thus charging begins.
3260 * If bat_temp_ok is low this means the temperature is now
3261 * too hot or cold, so charging is stopped.
3262 *
3263 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003264static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
3265{
David Keitel52fda532011-11-10 10:43:44 -08003266 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003267 struct pm8921_chg_chip *chip = data;
3268
David Keitel52fda532011-11-10 10:43:44 -08003269 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3270
3271 pr_debug("batt_temp_ok = %d fsm_state%d\n",
3272 bat_temp_ok, pm_chg_get_fsm_state(data));
3273
3274 if (bat_temp_ok)
3275 handle_start_ext_chg(chip);
3276 else
3277 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02003278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003279 power_supply_changed(&chip->batt_psy);
3280 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003281 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003282 return IRQ_HANDLED;
3283}
3284
3285static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
3286{
3287 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3288 return IRQ_HANDLED;
3289}
3290
3291static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3292{
3293 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3294 return IRQ_HANDLED;
3295}
3296
3297static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3298{
3299 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3300 return IRQ_HANDLED;
3301}
3302
3303static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3304{
3305 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3306 return IRQ_HANDLED;
3307}
3308
3309static irqreturn_t batfet_irq_handler(int irq, void *data)
3310{
3311 struct pm8921_chg_chip *chip = data;
3312
3313 pr_debug("vreg ov\n");
3314 power_supply_changed(&chip->batt_psy);
3315 return IRQ_HANDLED;
3316}
3317
3318static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3319{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003320 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003321 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003322
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003323 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003324 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003325
3326 if (chip->dc_present ^ dc_present)
3327 pm8921_bms_calibrate_hkadc();
3328
David Keitel88e1b572012-01-11 11:57:14 -08003329 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003330 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003331 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003332 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3333
3334 chip->dc_present = dc_present;
3335
3336 if (chip->ext_psy) {
3337 if (dc_present)
3338 handle_start_ext_chg(chip);
3339 else
3340 handle_stop_ext_chg(chip);
3341 } else {
3342 if (chip->lockup_lpm_wrkarnd)
3343 /* if no external supply call bypass debounce here */
3344 pm8921_chg_bypass_bat_gone_debounce(chip,
3345 is_chg_on_bat(chip));
3346
3347 if (dc_present)
3348 schedule_delayed_work(&chip->unplug_check_work,
3349 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3350 power_supply_changed(&chip->dc_psy);
3351 }
3352
3353 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003354 return IRQ_HANDLED;
3355}
3356
3357static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3358{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003359 struct pm8921_chg_chip *chip = data;
3360
Amir Samuelovd31ef502011-10-26 14:41:36 +02003361 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003362 return IRQ_HANDLED;
3363}
3364
3365static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3366{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003367 struct pm8921_chg_chip *chip = data;
3368
Amir Samuelovd31ef502011-10-26 14:41:36 +02003369 handle_stop_ext_chg(chip);
3370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003371 return IRQ_HANDLED;
3372}
3373
David Keitel88e1b572012-01-11 11:57:14 -08003374static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3375{
3376 struct power_supply *psy = &the_chip->batt_psy;
3377 struct power_supply *epsy = dev_get_drvdata(dev);
3378 int i, dcin_irq;
3379
3380 /* Only search for external supply if none is registered */
3381 if (!the_chip->ext_psy) {
3382 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3383 for (i = 0; i < epsy->num_supplicants; i++) {
3384 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3385 if (!strncmp(epsy->name, "dc", 2)) {
3386 the_chip->ext_psy = epsy;
3387 dcin_valid_irq_handler(dcin_irq,
3388 the_chip);
3389 }
3390 }
3391 }
3392 }
3393 return 0;
3394}
3395
3396static void pm_batt_external_power_changed(struct power_supply *psy)
3397{
3398 /* Only look for an external supply if it hasn't been registered */
3399 if (!the_chip->ext_psy)
3400 class_for_each_device(power_supply_class, NULL, psy,
3401 __pm_batt_external_power_changed_work);
3402}
3403
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003404/**
3405 * update_heartbeat - internal function to update userspace
3406 * per update_time minutes
3407 *
3408 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003409#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003410static void update_heartbeat(struct work_struct *work)
3411{
3412 struct delayed_work *dwork = to_delayed_work(work);
3413 struct pm8921_chg_chip *chip = container_of(dwork,
3414 struct pm8921_chg_chip, update_heartbeat_work);
3415
3416 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003417 if (chip->recent_reported_soc <= 20)
3418 schedule_delayed_work(&chip->update_heartbeat_work,
3419 round_jiffies_relative(msecs_to_jiffies
3420 (LOW_SOC_HEARTBEAT_MS)));
3421 else
3422 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003423 round_jiffies_relative(msecs_to_jiffies
3424 (chip->update_time)));
3425}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003426#define VDD_LOOP_ACTIVE_BIT BIT(3)
3427#define VDD_MAX_INCREASE_MV 400
3428static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3429module_param(vdd_max_increase_mv, int, 0644);
3430
3431static int ichg_threshold_ua = -400000;
3432module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003433
3434#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003435static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3436 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003437{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003438 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003439 int vbat_batt_terminal_mv;
3440 int reg_loop;
3441 int delta_mv = 0;
3442
3443 if (chip->rconn_mohm == 0) {
3444 pr_debug("Exiting as rconn_mohm is 0\n");
3445 return;
3446 }
3447 /* adjust vdd_max only in normal temperature zone */
3448 if (chip->is_bat_cool || chip->is_bat_warm) {
3449 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3450 chip->is_bat_cool, chip->is_bat_warm);
3451 return;
3452 }
3453
3454 reg_loop = pm_chg_get_regulation_loop(chip);
3455 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3456 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3457 reg_loop);
3458 return;
3459 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003460 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3461 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3462
3463 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3464
3465 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3466 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3467 delta_mv,
3468 programmed_vdd_max,
3469 adj_vdd_max_mv);
3470
3471 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3472 pr_debug("adj vdd_max lower than default max voltage\n");
3473 return;
3474 }
3475
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003476 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3477 * PM8921_CHG_VDDMAX_RES_MV;
3478
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003479 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3480 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003481 pr_debug("adjusting vdd_max_mv to %d to make "
3482 "vbat_batt_termial_uv = %d to %d\n",
3483 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3484 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3485}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003486
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003487static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3488{
3489 if (chip->is_bat_cool)
3490 pm_chg_vbatdet_set(the_chip,
3491 the_chip->cool_bat_voltage
3492 - the_chip->resume_voltage_delta);
3493 else if (chip->is_bat_warm)
3494 pm_chg_vbatdet_set(the_chip,
3495 the_chip->warm_bat_voltage
3496 - the_chip->resume_voltage_delta);
3497 else
3498 pm_chg_vbatdet_set(the_chip,
3499 the_chip->max_voltage_mv
3500 - the_chip->resume_voltage_delta);
3501}
3502
3503static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3504{
3505 unsigned int chg_current = chip->max_bat_chg_current;
3506
3507 if (chip->is_bat_cool)
3508 chg_current = min(chg_current, chip->cool_bat_chg_current);
3509
3510 if (chip->is_bat_warm)
3511 chg_current = min(chg_current, chip->warm_bat_chg_current);
3512
3513 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3514 chg_current = min(chg_current,
3515 chip->thermal_mitigation[thermal_mitigation]);
3516
3517 pm_chg_ibatmax_set(the_chip, chg_current);
3518}
3519
3520#define TEMP_HYSTERISIS_DECIDEGC 20
3521static void battery_cool(bool enter)
3522{
3523 pr_debug("enter = %d\n", enter);
3524 if (enter == the_chip->is_bat_cool)
3525 return;
3526 the_chip->is_bat_cool = enter;
3527 if (enter)
3528 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3529 else
3530 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3531 set_appropriate_battery_current(the_chip);
3532 set_appropriate_vbatdet(the_chip);
3533}
3534
3535static void battery_warm(bool enter)
3536{
3537 pr_debug("enter = %d\n", enter);
3538 if (enter == the_chip->is_bat_warm)
3539 return;
3540 the_chip->is_bat_warm = enter;
3541 if (enter)
3542 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3543 else
3544 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3545
3546 set_appropriate_battery_current(the_chip);
3547 set_appropriate_vbatdet(the_chip);
3548}
3549
3550static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3551{
3552 int temp = 0;
3553
3554 temp = get_prop_batt_temp(chip);
3555 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3556 temp, chip->warm_temp_dc,
3557 chip->cool_temp_dc);
3558
3559 if (chip->warm_temp_dc != INT_MIN) {
3560 if (chip->is_bat_warm
3561 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3562 battery_warm(false);
3563 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3564 battery_warm(true);
3565 }
3566
3567 if (chip->cool_temp_dc != INT_MIN) {
3568 if (chip->is_bat_cool
3569 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3570 battery_cool(false);
3571 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3572 battery_cool(true);
3573 }
3574}
3575
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003576enum {
3577 CHG_IN_PROGRESS,
3578 CHG_NOT_IN_PROGRESS,
3579 CHG_FINISHED,
3580};
3581
3582#define VBAT_TOLERANCE_MV 70
3583#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003584static int is_charging_finished(struct pm8921_chg_chip *chip,
3585 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003586{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003587 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003588 int regulation_loop, fast_chg, vcp;
3589 int rc;
3590 static int last_vbat_programmed = -EINVAL;
3591
3592 if (!is_ext_charging(chip)) {
3593 /* return if the battery is not being fastcharged */
3594 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3595 pr_debug("fast_chg = %d\n", fast_chg);
3596 if (fast_chg == 0)
3597 return CHG_NOT_IN_PROGRESS;
3598
3599 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3600 pr_debug("vcp = %d\n", vcp);
3601 if (vcp == 1)
3602 return CHG_IN_PROGRESS;
3603
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003604 /* reset count if battery is hot/cold */
3605 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3606 pr_debug("batt_temp_ok = %d\n", rc);
3607 if (rc == 0)
3608 return CHG_IN_PROGRESS;
3609
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003610 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3611 if (rc) {
3612 pr_err("couldnt read vddmax rc = %d\n", rc);
3613 return CHG_IN_PROGRESS;
3614 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003615 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3616 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003617
3618 if (last_vbat_programmed == -EINVAL)
3619 last_vbat_programmed = vbat_programmed;
3620 if (last_vbat_programmed != vbat_programmed) {
3621 /* vddmax changed, reset and check again */
3622 pr_debug("vddmax = %d last_vdd_max=%d\n",
3623 vbat_programmed, last_vbat_programmed);
3624 last_vbat_programmed = vbat_programmed;
3625 return CHG_IN_PROGRESS;
3626 }
3627
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003628 if (chip->is_bat_cool)
3629 vbat_intended = chip->cool_bat_voltage;
3630 else if (chip->is_bat_warm)
3631 vbat_intended = chip->warm_bat_voltage;
3632 else
3633 vbat_intended = chip->max_voltage_mv;
3634
3635 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3636 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3637 vbat_batt_terminal_uv,
3638 vbat_intended);
3639 return CHG_IN_PROGRESS;
3640 }
3641
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003642 regulation_loop = pm_chg_get_regulation_loop(chip);
3643 if (regulation_loop < 0) {
3644 pr_err("couldnt read the regulation loop err=%d\n",
3645 regulation_loop);
3646 return CHG_IN_PROGRESS;
3647 }
3648 pr_debug("regulation_loop=%d\n", regulation_loop);
3649
3650 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3651 return CHG_IN_PROGRESS;
3652 } /* !is_ext_charging */
3653
3654 /* reset count if battery chg current is more than iterm */
3655 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3656 if (rc) {
3657 pr_err("couldnt read iterm rc = %d\n", rc);
3658 return CHG_IN_PROGRESS;
3659 }
3660
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003661 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3662 iterm_programmed, ichg_meas_ma);
3663 /*
3664 * ichg_meas_ma < 0 means battery is drawing current
3665 * ichg_meas_ma > 0 means battery is providing current
3666 */
3667 if (ichg_meas_ma > 0)
3668 return CHG_IN_PROGRESS;
3669
3670 if (ichg_meas_ma * -1 > iterm_programmed)
3671 return CHG_IN_PROGRESS;
3672
3673 return CHG_FINISHED;
3674}
3675
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003676#define COMP_OVERRIDE_HOT_BANK 6
3677#define COMP_OVERRIDE_COLD_BANK 7
3678#define COMP_OVERRIDE_BIT BIT(1)
3679static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3680{
3681 u8 val;
3682 int rc = 0;
3683
3684 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3685
3686 if (flag)
3687 val |= 0x01;
3688
3689 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3690 if (rc < 0)
3691 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3692
3693 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3694 return rc;
3695}
3696
3697static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3698{
3699 u8 val;
3700 int rc = 0;
3701
3702 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3703
3704 if (flag)
3705 val |= 0x01;
3706
3707 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3708 if (rc < 0)
3709 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3710
3711 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3712 return rc;
3713}
3714
3715static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3716{
3717 int rc = 0;
3718 u8 reg;
3719 u8 val;
3720
3721 val = COMP_OVERRIDE_HOT_BANK << 2;
3722 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3723 if (rc < 0) {
3724 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3725 goto cold_init;
3726 }
3727 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3728 if (rc < 0) {
3729 pr_err("Could not read bank %d of override rc = %d\n",
3730 COMP_OVERRIDE_HOT_BANK, rc);
3731 goto cold_init;
3732 }
3733 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3734 /* for now override it as not hot */
3735 rc = pm_chg_override_hot(chip, 0);
3736 if (rc < 0)
3737 pr_err("Could not override hot rc = %d\n", rc);
3738 }
3739
3740cold_init:
3741 val = COMP_OVERRIDE_COLD_BANK << 2;
3742 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3743 if (rc < 0) {
3744 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3745 return;
3746 }
3747 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3748 if (rc < 0) {
3749 pr_err("Could not read bank %d of override rc = %d\n",
3750 COMP_OVERRIDE_COLD_BANK, rc);
3751 return;
3752 }
3753 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3754 /* for now override it as not cold */
3755 rc = pm_chg_override_cold(chip, 0);
3756 if (rc < 0)
3757 pr_err("Could not override cold rc = %d\n", rc);
3758 }
3759}
3760
3761static void btc_override_worker(struct work_struct *work)
3762{
3763 int decidegc;
3764 int temp;
3765 int rc = 0;
3766 struct delayed_work *dwork = to_delayed_work(work);
3767 struct pm8921_chg_chip *chip = container_of(dwork,
3768 struct pm8921_chg_chip, btc_override_work);
3769
3770 if (!chip->btc_override) {
3771 pr_err("called when not enabled\n");
3772 return;
3773 }
3774
3775 decidegc = get_prop_batt_temp(chip);
3776
3777 pr_debug("temp=%d\n", decidegc);
3778
3779 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3780 if (temp) {
3781 if (decidegc < chip->btc_override_hot_decidegc)
3782 /* stop forcing batt hot */
3783 rc = pm_chg_override_hot(chip, 0);
3784 if (rc)
3785 pr_err("Couldnt write 0 to hot comp\n");
3786 } else {
3787 if (decidegc >= chip->btc_override_hot_decidegc)
3788 /* start forcing batt hot */
3789 rc = pm_chg_override_hot(chip, 1);
3790 if (rc && chip->btc_panic_if_cant_stop_chg)
3791 panic("Couldnt override comps to stop chg\n");
3792 }
3793
3794 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3795 if (temp) {
3796 if (decidegc > chip->btc_override_cold_decidegc)
3797 /* stop forcing batt cold */
3798 rc = pm_chg_override_cold(chip, 0);
3799 if (rc)
3800 pr_err("Couldnt write 0 to cold comp\n");
3801 } else {
3802 if (decidegc <= chip->btc_override_cold_decidegc)
3803 /* start forcing batt cold */
3804 rc = pm_chg_override_cold(chip, 1);
3805 if (rc && chip->btc_panic_if_cant_stop_chg)
3806 panic("Couldnt override comps to stop chg\n");
3807 }
3808
3809 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3810 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3811 schedule_delayed_work(&chip->btc_override_work,
3812 round_jiffies_relative(msecs_to_jiffies
3813 (chip->btc_delay_ms)));
3814 return;
3815 }
3816
3817 rc = pm_chg_override_hot(chip, 0);
3818 if (rc)
3819 pr_err("Couldnt write 0 to hot comp\n");
3820 rc = pm_chg_override_cold(chip, 0);
3821 if (rc)
3822 pr_err("Couldnt write 0 to cold comp\n");
3823}
3824
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003825/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003826 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003827 * has happened
3828 *
3829 * If all conditions favouring, if the charge current is
3830 * less than the term current for three consecutive times
3831 * an EOC has happened.
3832 * The wakelock is released if there is no need to reshedule
3833 * - this happens when the battery is removed or EOC has
3834 * happened
3835 */
3836#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003837static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003838{
3839 struct delayed_work *dwork = to_delayed_work(work);
3840 struct pm8921_chg_chip *chip = container_of(dwork,
3841 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003842 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003843 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003844 int vbat_meas_uv, vbat_meas_mv;
3845 int ichg_meas_ua, ichg_meas_ma;
3846 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003847
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003848 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3849 &ichg_meas_ua, &vbat_meas_uv);
3850 vbat_meas_mv = vbat_meas_uv / 1000;
3851 /* rconn_mohm is in milliOhms */
3852 ichg_meas_ma = ichg_meas_ua / 1000;
3853 vbat_batt_terminal_uv = vbat_meas_uv
3854 + ichg_meas_ma
3855 * the_chip->rconn_mohm;
3856
3857 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003858
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003859 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003860 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003861 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003862 }
3863
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003864 if (end == CHG_FINISHED) {
3865 count++;
3866 } else {
3867 count = 0;
3868 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003869
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003870 if (count == CONSECUTIVE_COUNT) {
3871 count = 0;
3872 pr_info("End of Charging\n");
3873
3874 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003875
Amir Samuelovd31ef502011-10-26 14:41:36 +02003876 if (is_ext_charging(chip))
3877 chip->ext_charge_done = true;
3878
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003879 if (chip->is_bat_warm || chip->is_bat_cool)
3880 chip->bms_notify.is_battery_full = 0;
3881 else
3882 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003883 /* declare end of charging by invoking chgdone interrupt */
3884 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003885 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003886 check_temp_thresholds(chip);
3887 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003888 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003889 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003890 round_jiffies_relative(msecs_to_jiffies
3891 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003892 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003893 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003894
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003895eoc_worker_stop:
3896 wake_unlock(&chip->eoc_wake_lock);
3897 /* set the vbatdet back, in case it was changed to trigger charging */
3898 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003899}
3900
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003901/**
3902 * set_disable_status_param -
3903 *
3904 * Internal function to disable battery charging and also disable drawing
3905 * any current from the source. The device is forced to run on a battery
3906 * after this.
3907 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003908static int set_disable_status_param(const char *val, struct kernel_param *kp)
3909{
3910 int ret;
3911 struct pm8921_chg_chip *chip = the_chip;
3912
3913 ret = param_set_int(val, kp);
3914 if (ret) {
3915 pr_err("error setting value %d\n", ret);
3916 return ret;
3917 }
3918 pr_info("factory set disable param to %d\n", charging_disabled);
3919 if (chip) {
3920 pm_chg_auto_enable(chip, !charging_disabled);
3921 pm_chg_charge_dis(chip, charging_disabled);
3922 }
3923 return 0;
3924}
3925module_param_call(disabled, set_disable_status_param, param_get_uint,
3926 &charging_disabled, 0644);
3927
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003928static int rconn_mohm;
3929static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3930{
3931 int ret;
3932 struct pm8921_chg_chip *chip = the_chip;
3933
3934 ret = param_set_int(val, kp);
3935 if (ret) {
3936 pr_err("error setting value %d\n", ret);
3937 return ret;
3938 }
3939 if (chip)
3940 chip->rconn_mohm = rconn_mohm;
3941 return 0;
3942}
3943module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3944 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003945/**
3946 * set_thermal_mitigation_level -
3947 *
3948 * Internal function to control battery charging current to reduce
3949 * temperature
3950 */
3951static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3952{
3953 int ret;
3954 struct pm8921_chg_chip *chip = the_chip;
3955
3956 ret = param_set_int(val, kp);
3957 if (ret) {
3958 pr_err("error setting value %d\n", ret);
3959 return ret;
3960 }
3961
3962 if (!chip) {
3963 pr_err("called before init\n");
3964 return -EINVAL;
3965 }
3966
3967 if (!chip->thermal_mitigation) {
3968 pr_err("no thermal mitigation\n");
3969 return -EINVAL;
3970 }
3971
3972 if (thermal_mitigation < 0
3973 || thermal_mitigation >= chip->thermal_levels) {
3974 pr_err("out of bound level selected\n");
3975 return -EINVAL;
3976 }
3977
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003978 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003979 return ret;
3980}
3981module_param_call(thermal_mitigation, set_therm_mitigation_level,
3982 param_get_uint,
3983 &thermal_mitigation, 0644);
3984
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003985static int set_usb_max_current(const char *val, struct kernel_param *kp)
3986{
3987 int ret, mA;
3988 struct pm8921_chg_chip *chip = the_chip;
3989
3990 ret = param_set_int(val, kp);
3991 if (ret) {
3992 pr_err("error setting value %d\n", ret);
3993 return ret;
3994 }
3995 if (chip) {
3996 pr_warn("setting current max to %d\n", usb_max_current);
3997 pm_chg_iusbmax_get(chip, &mA);
3998 if (mA > usb_max_current)
3999 pm8921_charger_vbus_draw(usb_max_current);
4000 return 0;
4001 }
4002 return -EINVAL;
4003}
David Keitelacf57c82012-03-07 18:48:50 -08004004module_param_call(usb_max_current, set_usb_max_current,
4005 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007static void free_irqs(struct pm8921_chg_chip *chip)
4008{
4009 int i;
4010
4011 for (i = 0; i < PM_CHG_MAX_INTS; i++)
4012 if (chip->pmic_chg_irq[i]) {
4013 free_irq(chip->pmic_chg_irq[i], chip);
4014 chip->pmic_chg_irq[i] = 0;
4015 }
4016}
4017
David Keitel88e1b572012-01-11 11:57:14 -08004018/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004019static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
4020{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07004022 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023
4024 chip->dc_present = !!is_dc_chg_plugged_in(chip);
4025 chip->usb_present = !!is_usb_chg_plugged_in(chip);
4026
4027 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004028 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004029 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004030 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08004031 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004032 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033
4034 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
4035 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
4036 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004037 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004038 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
4039 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07004040 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004041 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
4042 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004043 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004045 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
4046 if (usb_chg_current)
4047 /*
4048 * Reissue a vbus draw call only if a battery
4049 * or DC is present. We don't want to brown out the
4050 * device if usb is its only source
4051 */
4052 __pm8921_charger_vbus_draw(usb_chg_current);
4053 usb_chg_current = 0;
4054
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07004055 /*
4056 * The bootloader could have started charging, a fastchg interrupt
4057 * might not happen. Check the real time status and if it is fast
4058 * charging invoke the handler so that the eoc worker could be
4059 * started
4060 */
4061 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
4062 if (is_fast_chg)
4063 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064
4065 fsm_state = pm_chg_get_fsm_state(chip);
4066 if (is_battery_charging(fsm_state)) {
4067 chip->bms_notify.is_charging = 1;
4068 pm8921_bms_charging_began();
4069 }
4070
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004071 check_battery_valid(chip);
4072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
4074 chip->usb_present,
4075 chip->dc_present,
4076 get_prop_batt_present(chip),
4077 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004078
4079 /* Determine which USB trim column to use */
4080 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
4081 chip->usb_trim_table = usb_trim_8917_table;
4082 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
4083 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004084}
4085
4086struct pm_chg_irq_init_data {
4087 unsigned int irq_id;
4088 char *name;
4089 unsigned long flags;
4090 irqreturn_t (*handler)(int, void *);
4091};
4092
4093#define CHG_IRQ(_id, _flags, _handler) \
4094{ \
4095 .irq_id = _id, \
4096 .name = #_id, \
4097 .flags = _flags, \
4098 .handler = _handler, \
4099}
4100struct pm_chg_irq_init_data chg_irq_data[] = {
4101 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4102 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4104 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07004105 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4106 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
4108 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
4109 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
4110 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
4111 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
4112 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
4113 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
4114 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07004115 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4116 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
4118 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
4119 batt_removed_irq_handler),
4120 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
4121 batttemp_hot_irq_handler),
4122 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
4123 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
4124 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08004125 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4126 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07004127 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4128 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
4130 coarse_det_low_irq_handler),
4131 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
4132 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
4133 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
4134 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4135 batfet_irq_handler),
4136 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4137 dcin_valid_irq_handler),
4138 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
4139 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07004140 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141};
4142
4143static int __devinit request_irqs(struct pm8921_chg_chip *chip,
4144 struct platform_device *pdev)
4145{
4146 struct resource *res;
4147 int ret, i;
4148
4149 ret = 0;
4150 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
4151
4152 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4153 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
4154 chg_irq_data[i].name);
4155 if (res == NULL) {
4156 pr_err("couldn't find %s\n", chg_irq_data[i].name);
4157 goto err_out;
4158 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004159 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004160 ret = request_irq(res->start, chg_irq_data[i].handler,
4161 chg_irq_data[i].flags,
4162 chg_irq_data[i].name, chip);
4163 if (ret < 0) {
4164 pr_err("couldn't request %d (%s) %d\n", res->start,
4165 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004166 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004167 goto err_out;
4168 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004169 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
4170 }
4171 return 0;
4172
4173err_out:
4174 free_irqs(chip);
4175 return -EINVAL;
4176}
4177
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004178#define VREF_BATT_THERM_FORCE_ON BIT(7)
4179static void detect_battery_removal(struct pm8921_chg_chip *chip)
4180{
4181 u8 temp;
4182
4183 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
4184 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
4185
4186 if (!(temp & VREF_BATT_THERM_FORCE_ON))
4187 /*
4188 * batt therm force on bit is battery backed and is default 0
4189 * The charger sets this bit at init time. If this bit is found
4190 * 0 that means the battery was removed. Tell the bms about it
4191 */
4192 pm8921_bms_invalidate_shutdown_soc();
4193}
4194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004195#define ENUM_TIMER_STOP_BIT BIT(1)
4196#define BOOT_DONE_BIT BIT(6)
4197#define CHG_BATFET_ON_BIT BIT(3)
4198#define CHG_VCP_EN BIT(0)
4199#define CHG_BAT_TEMP_DIS_BIT BIT(2)
4200#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004201#define PM_SUB_REV 0x001
4202#define MIN_CHARGE_CURRENT_MA 350
4203#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
4205{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004206 u8 subrev;
4207 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004208
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004209 spin_lock_init(&lpm_lock);
Abhijeet Dharmapurikarf5abc1c2013-01-30 21:51:37 -08004210
4211 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4212 rc = __pm8921_apply_19p2mhz_kickstart(chip);
4213 if (rc) {
4214 pr_err("Failed to apply kickstart rc=%d\n", rc);
4215 return rc;
4216 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004217 }
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004218
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004219 detect_battery_removal(chip);
4220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004221 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004222 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 if (rc) {
4224 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4225 return rc;
4226 }
4227
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004228 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4229
4230 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4231 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4232
4233 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004235 if (rc) {
4236 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004237 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 return rc;
4239 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004240 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004241 chip->max_voltage_mv
4242 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004243 if (rc) {
4244 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004245 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004246 return rc;
4247 }
4248
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004249 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004250 if (rc) {
4251 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004252 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253 return rc;
4254 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004255
4256 if (chip->safe_current_ma == 0)
4257 chip->safe_current_ma = SAFE_CURRENT_MA;
4258
4259 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260 if (rc) {
4261 pr_err("Failed to set max voltage to %d rc=%d\n",
4262 SAFE_CURRENT_MA, rc);
4263 return rc;
4264 }
4265
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004266 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267 if (rc) {
4268 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4269 return rc;
4270 }
4271
4272 rc = pm_chg_iterm_set(chip, chip->term_current);
4273 if (rc) {
4274 pr_err("Failed to set term current to %d rc=%d\n",
4275 chip->term_current, rc);
4276 return rc;
4277 }
4278
4279 /* Disable the ENUM TIMER */
4280 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4281 ENUM_TIMER_STOP_BIT);
4282 if (rc) {
4283 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4284 return rc;
4285 }
4286
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004287 fcc_uah = pm8921_bms_get_fcc();
4288 if (fcc_uah > 0) {
4289 safety_time = div_s64((s64)fcc_uah * 60,
4290 1000 * MIN_CHARGE_CURRENT_MA);
4291 /* add 20 minutes of buffer time */
4292 safety_time += 20;
4293
4294 /* make sure we do not exceed the maximum programmable time */
4295 if (safety_time > PM8921_CHG_TCHG_MAX)
4296 safety_time = PM8921_CHG_TCHG_MAX;
4297 }
4298
4299 rc = pm_chg_tchg_max_set(chip, safety_time);
4300 if (rc) {
4301 pr_err("Failed to set max time to %d minutes rc=%d\n",
4302 safety_time, rc);
4303 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004304 }
4305
4306 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004307 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004308 if (rc) {
4309 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004310 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004311 return rc;
4312 }
4313 }
4314
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004315 if (chip->vin_min != 0) {
4316 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4317 if (rc) {
4318 pr_err("Failed to set vin min to %d mV rc=%d\n",
4319 chip->vin_min, rc);
4320 return rc;
4321 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004322 } else {
4323 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004324 }
4325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326 rc = pm_chg_disable_wd(chip);
4327 if (rc) {
4328 pr_err("Failed to disable wd rc=%d\n", rc);
4329 return rc;
4330 }
4331
4332 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4333 CHG_BAT_TEMP_DIS_BIT, 0);
4334 if (rc) {
4335 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4336 return rc;
4337 }
4338 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004339 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4340 rc = pm_chg_write(chip,
4341 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4342 else
4343 rc = pm_chg_write(chip,
4344 CHG_BUCK_CLOCK_CTRL, 0x15);
4345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004346 if (rc) {
4347 pr_err("Failed to switch buck clk rc=%d\n", rc);
4348 return rc;
4349 }
4350
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004351 if (chip->trkl_voltage != 0) {
4352 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4353 if (rc) {
4354 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4355 chip->trkl_voltage, rc);
4356 return rc;
4357 }
4358 }
4359
4360 if (chip->weak_voltage != 0) {
4361 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4362 if (rc) {
4363 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4364 chip->weak_voltage, rc);
4365 return rc;
4366 }
4367 }
4368
4369 if (chip->trkl_current != 0) {
4370 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4371 if (rc) {
4372 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4373 chip->trkl_voltage, rc);
4374 return rc;
4375 }
4376 }
4377
4378 if (chip->weak_current != 0) {
4379 rc = pm_chg_iweak_set(chip, chip->weak_current);
4380 if (rc) {
4381 pr_err("Failed to set weak current to %dmA rc=%d\n",
4382 chip->weak_current, rc);
4383 return rc;
4384 }
4385 }
4386
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004387 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4388 if (rc) {
4389 pr_err("Failed to set cold config %d rc=%d\n",
4390 chip->cold_thr, rc);
4391 }
4392
4393 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4394 if (rc) {
4395 pr_err("Failed to set hot config %d rc=%d\n",
4396 chip->hot_thr, rc);
4397 }
4398
Jay Chokshid674a512012-03-15 14:06:04 -07004399 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4400 if (rc) {
4401 pr_err("Failed to set charger LED src config %d rc=%d\n",
4402 chip->led_src_config, rc);
4403 }
4404
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004405 /* Workarounds for die 3.0 */
4406 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4407 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4408 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4409 if (rc) {
4410 pr_err("read failed: addr=%03X, rc=%d\n",
4411 PM_SUB_REV, rc);
4412 return rc;
4413 }
4414 /* Check if die 3.0.1 is present */
4415 if (subrev & 0x1)
4416 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4417 else
4418 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004419 }
4420
David Keitel0789fc62012-06-07 17:43:27 -07004421 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004422 /* Set PM8917 USB_OVP debounce time to 15 ms */
4423 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4424 OVP_DEBOUNCE_TIME, 0x6);
4425 if (rc) {
4426 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4427 return rc;
4428 }
4429
4430 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004431 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004432 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004433 rc = pm_chg_uvd_threshold_set(chip,
4434 chip->uvd_voltage_mv);
4435 if (rc) {
4436 pr_err("Failed to set UVD threshold %drc=%d\n",
4437 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004438 return rc;
4439 }
David Keitel0789fc62012-06-07 17:43:27 -07004440 }
4441 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004442
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004443 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004444
David Keitela3c0d822011-11-03 14:18:52 -07004445 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004446 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004447
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004448 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4449 VREF_BATT_THERM_FORCE_ON);
4450 if (rc)
4451 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004453 rc = pm_chg_charge_dis(chip, charging_disabled);
4454 if (rc) {
4455 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4456 return rc;
4457 }
4458
4459 rc = pm_chg_auto_enable(chip, !charging_disabled);
4460 if (rc) {
4461 pr_err("Failed to enable charging rc=%d\n", rc);
4462 return rc;
4463 }
4464
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004465 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4466 /* Clear kickstart */
4467 rc = pm8xxx_writeb(chip->dev->parent, CHG_TEST, 0xD0);
4468 if (rc) {
4469 pr_err("Failed to clear kickstart rc=%d\n", rc);
4470 return rc;
4471 }
4472
4473 /* From here the lpm_workaround will be active */
4474 chip->lockup_lpm_wrkarnd = true;
4475
4476 /* Enable LPM */
4477 pm8921_chg_set_lpm(chip, 1);
4478 }
4479
4480 if (chip->lockup_lpm_wrkarnd) {
4481 chip->vreg_xoadc = regulator_get(chip->dev, "vreg_xoadc");
4482 if (IS_ERR(chip->vreg_xoadc))
4483 return -ENODEV;
4484
4485 rc = regulator_set_optimum_mode(chip->vreg_xoadc, 10000);
4486 if (rc < 0) {
4487 pr_err("Failed to set configure HPM rc=%d\n", rc);
4488 return rc;
4489 }
4490
4491 rc = regulator_set_voltage(chip->vreg_xoadc, 1800000, 1800000);
4492 if (rc) {
4493 pr_err("Failed to set L14 voltage rc=%d\n", rc);
4494 return rc;
4495 }
4496
4497 rc = regulator_enable(chip->vreg_xoadc);
4498 if (rc) {
4499 pr_err("Failed to enable L14 rc=%d\n", rc);
4500 return rc;
4501 }
4502 }
4503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004504 return 0;
4505}
4506
4507static int get_rt_status(void *data, u64 * val)
4508{
4509 int i = (int)data;
4510 int ret;
4511
4512 /* global irq number is passed in via data */
4513 ret = pm_chg_get_rt_status(the_chip, i);
4514 *val = ret;
4515 return 0;
4516}
4517DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4518
4519static int get_fsm_status(void *data, u64 * val)
4520{
4521 u8 temp;
4522
4523 temp = pm_chg_get_fsm_state(the_chip);
4524 *val = temp;
4525 return 0;
4526}
4527DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4528
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004529static int get_reg_loop(void *data, u64 * val)
4530{
4531 u8 temp;
4532
4533 if (!the_chip) {
4534 pr_err("%s called before init\n", __func__);
4535 return -EINVAL;
4536 }
4537 temp = pm_chg_get_regulation_loop(the_chip);
4538 *val = temp;
4539 return 0;
4540}
4541DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004543static int get_reg(void *data, u64 * val)
4544{
4545 int addr = (int)data;
4546 int ret;
4547 u8 temp;
4548
4549 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4550 if (ret) {
4551 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4552 addr, temp, ret);
4553 return -EAGAIN;
4554 }
4555 *val = temp;
4556 return 0;
4557}
4558
4559static int set_reg(void *data, u64 val)
4560{
4561 int addr = (int)data;
4562 int ret;
4563 u8 temp;
4564
4565 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004566 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004567 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004568 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004569 addr, temp, ret);
4570 return -EAGAIN;
4571 }
4572 return 0;
4573}
4574DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4575
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004576static int reg_loop;
4577#define MAX_REG_LOOP_CHAR 10
4578static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4579{
4580 u8 temp;
4581
4582 if (!the_chip) {
4583 pr_err("called before init\n");
4584 return -EINVAL;
4585 }
4586 temp = pm_chg_get_regulation_loop(the_chip);
4587 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4588}
4589module_param_call(reg_loop, NULL, get_reg_loop_param,
4590 &reg_loop, 0644);
4591
4592static int max_chg_ma;
4593#define MAX_MA_CHAR 10
4594static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4595{
4596 if (!the_chip) {
4597 pr_err("called before init\n");
4598 return -EINVAL;
4599 }
4600 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4601}
4602module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4603 &max_chg_ma, 0644);
4604static int ibatmax_ma;
4605static int set_ibat_max(const char *val, struct kernel_param *kp)
4606{
4607 int rc;
4608
4609 if (!the_chip) {
4610 pr_err("called before init\n");
4611 return -EINVAL;
4612 }
4613
4614 rc = param_set_int(val, kp);
4615 if (rc) {
4616 pr_err("error setting value %d\n", rc);
4617 return rc;
4618 }
4619
4620 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4621 <= the_chip->ibatmax_max_adj_ma) {
4622 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4623 if (rc) {
4624 pr_err("Failed to set ibatmax rc = %d\n", rc);
4625 return rc;
4626 }
4627 }
4628
4629 return 0;
4630}
4631static int get_ibat_max(char *buf, struct kernel_param *kp)
4632{
4633 int ibat_ma;
4634 int rc;
4635
4636 if (!the_chip) {
4637 pr_err("called before init\n");
4638 return -EINVAL;
4639 }
4640
4641 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4642 if (rc) {
4643 pr_err("ibatmax_get error = %d\n", rc);
4644 return rc;
4645 }
4646
4647 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4648}
4649module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4650 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004651enum {
4652 BAT_WARM_ZONE,
4653 BAT_COOL_ZONE,
4654};
4655static int get_warm_cool(void *data, u64 * val)
4656{
4657 if (!the_chip) {
4658 pr_err("%s called before init\n", __func__);
4659 return -EINVAL;
4660 }
4661 if ((int)data == BAT_WARM_ZONE)
4662 *val = the_chip->is_bat_warm;
4663 if ((int)data == BAT_COOL_ZONE)
4664 *val = the_chip->is_bat_cool;
4665 return 0;
4666}
4667DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004669static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4670{
4671 int i;
4672
4673 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4674
4675 if (IS_ERR(chip->dent)) {
4676 pr_err("pmic charger couldnt create debugfs dir\n");
4677 return;
4678 }
4679
4680 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4681 (void *)CHG_CNTRL, &reg_fops);
4682 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4683 (void *)CHG_CNTRL_2, &reg_fops);
4684 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4685 (void *)CHG_CNTRL_3, &reg_fops);
4686 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4687 (void *)PBL_ACCESS1, &reg_fops);
4688 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4689 (void *)PBL_ACCESS2, &reg_fops);
4690 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4691 (void *)SYS_CONFIG_1, &reg_fops);
4692 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4693 (void *)SYS_CONFIG_2, &reg_fops);
4694 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4695 (void *)CHG_VDD_MAX, &reg_fops);
4696 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4697 (void *)CHG_VDD_SAFE, &reg_fops);
4698 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4699 (void *)CHG_VBAT_DET, &reg_fops);
4700 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4701 (void *)CHG_IBAT_MAX, &reg_fops);
4702 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4703 (void *)CHG_IBAT_SAFE, &reg_fops);
4704 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4705 (void *)CHG_VIN_MIN, &reg_fops);
4706 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4707 (void *)CHG_VTRICKLE, &reg_fops);
4708 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4709 (void *)CHG_ITRICKLE, &reg_fops);
4710 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4711 (void *)CHG_ITERM, &reg_fops);
4712 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4713 (void *)CHG_TCHG_MAX, &reg_fops);
4714 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4715 (void *)CHG_TWDOG, &reg_fops);
4716 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4717 (void *)CHG_TEMP_THRESH, &reg_fops);
4718 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4719 (void *)CHG_COMP_OVR, &reg_fops);
4720 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4721 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4722 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4723 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4724 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4725 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4726 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4727 (void *)CHG_TEST, &reg_fops);
4728
4729 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4730 &fsm_fops);
4731
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004732 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4733 &reg_loop_fops);
4734
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004735 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4736 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4737 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4738 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4741 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4742 debugfs_create_file(chg_irq_data[i].name, 0444,
4743 chip->dent,
4744 (void *)chg_irq_data[i].irq_id,
4745 &rt_fops);
4746 }
4747}
4748
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004749static int pm8921_charger_suspend_noirq(struct device *dev)
4750{
4751 int rc;
4752 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4753
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004754 if (chip->lockup_lpm_wrkarnd) {
4755 rc = regulator_disable(chip->vreg_xoadc);
4756 if (rc)
4757 pr_err("Failed to disable L14 rc=%d\n", rc);
4758
4759 rc = pm8921_apply_19p2mhz_kickstart(chip);
4760 if (rc)
4761 pr_err("Failed to apply kickstart rc=%d\n", rc);
4762 }
4763
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004764 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4765 if (rc)
4766 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004767 return 0;
4768}
4769
4770static int pm8921_charger_resume_noirq(struct device *dev)
4771{
4772 int rc;
4773 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4774
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004775 if (chip->lockup_lpm_wrkarnd) {
4776 rc = regulator_enable(chip->vreg_xoadc);
4777 if (rc)
4778 pr_err("Failed to enable L14 rc=%d\n", rc);
4779
4780 rc = pm8921_apply_19p2mhz_kickstart(chip);
4781 if (rc)
4782 pr_err("Failed to apply kickstart rc=%d\n", rc);
4783 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004784
4785 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4786 VREF_BATT_THERM_FORCE_ON);
4787 if (rc)
4788 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4789 return 0;
4790}
4791
David Keitelf2226022011-12-13 15:55:50 -08004792static int pm8921_charger_resume(struct device *dev)
4793{
David Keitelf2226022011-12-13 15:55:50 -08004794 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4795
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004796 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4797 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4798 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4799 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004800
4801 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4802 is_usb_chg_plugged_in(the_chip)))
4803 schedule_delayed_work(&chip->btc_override_work, 0);
4804
David Keitelf2226022011-12-13 15:55:50 -08004805 return 0;
4806}
4807
4808static int pm8921_charger_suspend(struct device *dev)
4809{
David Keitelf2226022011-12-13 15:55:50 -08004810 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4811
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004812 if (chip->btc_override)
4813 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004814
4815 if (is_usb_chg_plugged_in(chip)) {
4816 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4817 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4818 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004819
David Keitelf2226022011-12-13 15:55:50 -08004820 return 0;
4821}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004822static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4823{
4824 int rc = 0;
4825 struct pm8921_chg_chip *chip;
4826 const struct pm8921_charger_platform_data *pdata
4827 = pdev->dev.platform_data;
4828
4829 if (!pdata) {
4830 pr_err("missing platform data\n");
4831 return -EINVAL;
4832 }
4833
4834 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4835 GFP_KERNEL);
4836 if (!chip) {
4837 pr_err("Cannot allocate pm_chg_chip\n");
4838 return -ENOMEM;
4839 }
4840
4841 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004842 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004844 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004845 chip->alarm_low_mv = pdata->alarm_low_mv;
4846 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004847 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004848 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004849 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004850 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004851 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004852 chip->term_current = pdata->term_current;
4853 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004854 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004855 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4856 chip->batt_id_min = pdata->batt_id_min;
4857 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004858 if (pdata->cool_temp != INT_MIN)
4859 chip->cool_temp_dc = pdata->cool_temp * 10;
4860 else
4861 chip->cool_temp_dc = INT_MIN;
4862
4863 if (pdata->warm_temp != INT_MIN)
4864 chip->warm_temp_dc = pdata->warm_temp * 10;
4865 else
4866 chip->warm_temp_dc = INT_MIN;
4867
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004868 chip->temp_check_period = pdata->temp_check_period;
4869 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004870 /* Assign to corresponding module parameter */
4871 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004872 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4873 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4874 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4875 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004876 chip->trkl_voltage = pdata->trkl_voltage;
4877 chip->weak_voltage = pdata->weak_voltage;
4878 chip->trkl_current = pdata->trkl_current;
4879 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004880 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004881 chip->thermal_mitigation = pdata->thermal_mitigation;
4882 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004883
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004884 chip->cold_thr = pdata->cold_thr;
4885 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004886 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004887 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004888 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004889 chip->battery_less_hardware = pdata->battery_less_hardware;
4890 chip->btc_override = pdata->btc_override;
4891 if (chip->btc_override) {
4892 chip->btc_delay_ms = pdata->btc_delay_ms;
4893 chip->btc_override_cold_decidegc
4894 = pdata->btc_override_cold_degc * 10;
4895 chip->btc_override_hot_decidegc
4896 = pdata->btc_override_hot_degc * 10;
4897 chip->btc_panic_if_cant_stop_chg
4898 = pdata->btc_panic_if_cant_stop_chg;
4899 }
4900
4901 if (chip->battery_less_hardware)
4902 charging_disabled = 1;
4903
4904 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4905 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907 rc = pm8921_chg_hw_init(chip);
4908 if (rc) {
4909 pr_err("couldn't init hardware rc=%d\n", rc);
4910 goto free_chip;
4911 }
4912
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004913 if (chip->btc_override)
4914 pm8921_chg_btc_override_init(chip);
4915
4916 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304917 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004918
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004919 chip->usb_psy.name = "usb";
4920 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4921 chip->usb_psy.supplied_to = pm_power_supplied_to;
4922 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4923 chip->usb_psy.properties = pm_power_props_usb;
4924 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4925 chip->usb_psy.get_property = pm_power_get_property_usb;
4926 chip->usb_psy.set_property = pm_power_set_property_usb;
4927 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004928
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004929 chip->dc_psy.name = "pm8921-dc";
4930 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4931 chip->dc_psy.supplied_to = pm_power_supplied_to;
4932 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4933 chip->dc_psy.properties = pm_power_props_mains;
4934 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4935 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004936
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004937 chip->batt_psy.name = "battery";
4938 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4939 chip->batt_psy.properties = msm_batt_power_props;
4940 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4941 chip->batt_psy.get_property = pm_batt_power_get_property;
4942 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004943 rc = power_supply_register(chip->dev, &chip->usb_psy);
4944 if (rc < 0) {
4945 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004946 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004947 }
4948
David Keitel6ed71a52012-01-30 12:42:18 -08004949 rc = power_supply_register(chip->dev, &chip->dc_psy);
4950 if (rc < 0) {
4951 pr_err("power_supply_register usb failed rc = %d\n", rc);
4952 goto unregister_usb;
4953 }
4954
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 rc = power_supply_register(chip->dev, &chip->batt_psy);
4956 if (rc < 0) {
4957 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004958 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004959 }
4960
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004961 platform_set_drvdata(pdev, chip);
4962 the_chip = chip;
4963
4964 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004965 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004966 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4967 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004968 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004969
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004970 INIT_WORK(&chip->bms_notify.work, bms_notify);
4971 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4972
4973 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4974 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004976 rc = request_irqs(chip, pdev);
4977 if (rc) {
4978 pr_err("couldn't register interrupts rc=%d\n", rc);
4979 goto unregister_batt;
4980 }
4981
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004982 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004983 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004984 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004985 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004987 create_debugfs_entries(chip);
4988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989 /* determine what state the charger is in */
4990 determine_initial_state(chip);
4991
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004992 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004993 schedule_delayed_work(&chip->update_heartbeat_work,
4994 round_jiffies_relative(msecs_to_jiffies
4995 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004996 return 0;
4997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004998unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004999 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005000 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08005001unregister_dc:
5002 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003unregister_usb:
5004 power_supply_unregister(&chip->usb_psy);
5005free_chip:
5006 kfree(chip);
5007 return rc;
5008}
5009
5010static int __devexit pm8921_charger_remove(struct platform_device *pdev)
5011{
5012 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
5013
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07005014 regulator_put(chip->vreg_xoadc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005015 free_irqs(chip);
5016 platform_set_drvdata(pdev, NULL);
5017 the_chip = NULL;
5018 kfree(chip);
5019 return 0;
5020}
David Keitelf2226022011-12-13 15:55:50 -08005021static const struct dev_pm_ops pm8921_pm_ops = {
5022 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08005023 .suspend_noirq = pm8921_charger_suspend_noirq,
5024 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08005025 .resume = pm8921_charger_resume,
5026};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08005028 .probe = pm8921_charger_probe,
5029 .remove = __devexit_p(pm8921_charger_remove),
5030 .driver = {
5031 .name = PM8921_CHARGER_DEV_NAME,
5032 .owner = THIS_MODULE,
5033 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034 },
5035};
5036
5037static int __init pm8921_charger_init(void)
5038{
5039 return platform_driver_register(&pm8921_charger_driver);
5040}
5041
5042static void __exit pm8921_charger_exit(void)
5043{
5044 platform_driver_unregister(&pm8921_charger_driver);
5045}
5046
5047late_initcall(pm8921_charger_init);
5048module_exit(pm8921_charger_exit);
5049
5050MODULE_LICENSE("GPL v2");
5051MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
5052MODULE_VERSION("1.0");
5053MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);