blob: 1ca95f6fe836e7b45e3e382e7fb2df464f09ec63 [file] [log] [blame]
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/pm8921-charger.h>
20#include <linux/mfd/pm8xxx/pm8921-bms.h>
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -070021#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -080022#include <linux/mfd/pm8xxx/ccadc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023#include <linux/mfd/pm8xxx/core.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070024#include <linux/regulator/consumer.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/interrupt.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/delay.h>
27#include <linux/bitops.h>
28#include <linux/workqueue.h>
29#include <linux/debugfs.h>
30#include <linux/slab.h>
Ajay Dudani11aeb7b2012-06-28 19:14:30 -070031#include <linux/mfd/pm8xxx/batt-alarm.h>
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070032#include <linux/ratelimit.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033
34#include <mach/msm_xo.h>
35#include <mach/msm_hsusb.h>
36
37#define CHG_BUCK_CLOCK_CTRL 0x14
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070038#define CHG_BUCK_CLOCK_CTRL_8038 0xD
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#define PBL_ACCESS1 0x04
41#define PBL_ACCESS2 0x05
42#define SYS_CONFIG_1 0x06
43#define SYS_CONFIG_2 0x07
44#define CHG_CNTRL 0x204
45#define CHG_IBAT_MAX 0x205
46#define CHG_TEST 0x206
47#define CHG_BUCK_CTRL_TEST1 0x207
48#define CHG_BUCK_CTRL_TEST2 0x208
49#define CHG_BUCK_CTRL_TEST3 0x209
50#define COMPARATOR_OVERRIDE 0x20A
51#define PSI_TXRX_SAMPLE_DATA_0 0x20B
52#define PSI_TXRX_SAMPLE_DATA_1 0x20C
53#define PSI_TXRX_SAMPLE_DATA_2 0x20D
54#define PSI_TXRX_SAMPLE_DATA_3 0x20E
55#define PSI_CONFIG_STATUS 0x20F
56#define CHG_IBAT_SAFE 0x210
57#define CHG_ITRICKLE 0x211
58#define CHG_CNTRL_2 0x212
59#define CHG_VBAT_DET 0x213
60#define CHG_VTRICKLE 0x214
61#define CHG_ITERM 0x215
62#define CHG_CNTRL_3 0x216
63#define CHG_VIN_MIN 0x217
64#define CHG_TWDOG 0x218
65#define CHG_TTRKL_MAX 0x219
66#define CHG_TEMP_THRESH 0x21A
67#define CHG_TCHG_MAX 0x21B
68#define USB_OVP_CONTROL 0x21C
69#define DC_OVP_CONTROL 0x21D
70#define USB_OVP_TEST 0x21E
71#define DC_OVP_TEST 0x21F
72#define CHG_VDD_MAX 0x220
73#define CHG_VDD_SAFE 0x221
74#define CHG_VBAT_BOOT_THRESH 0x222
75#define USB_OVP_TRIM 0x355
76#define BUCK_CONTROL_TRIM1 0x356
77#define BUCK_CONTROL_TRIM2 0x357
78#define BUCK_CONTROL_TRIM3 0x358
79#define BUCK_CONTROL_TRIM4 0x359
80#define CHG_DEFAULTS_TRIM 0x35A
81#define CHG_ITRIM 0x35B
82#define CHG_TTRIM 0x35C
83#define CHG_COMP_OVR 0x20A
David Keitel38bdd4f2012-04-19 15:39:13 -070084#define IUSB_FINE_RES 0x2B6
David Keitel0789fc62012-06-07 17:43:27 -070085#define OVP_USB_UVD 0x2B7
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070087/* check EOC every 10 seconds */
88#define EOC_CHECK_PERIOD_MS 10000
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -080089/* check for USB unplug every 200 msecs */
90#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -070091#define UNPLUG_CHECK_RAMP_MS 25
92#define USB_TRIM_ENTRIES 16
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -070093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070094enum chg_fsm_state {
95 FSM_STATE_OFF_0 = 0,
96 FSM_STATE_BATFETDET_START_12 = 12,
97 FSM_STATE_BATFETDET_END_16 = 16,
98 FSM_STATE_ON_CHG_HIGHI_1 = 1,
99 FSM_STATE_ATC_2A = 2,
100 FSM_STATE_ATC_2B = 18,
101 FSM_STATE_ON_BAT_3 = 3,
102 FSM_STATE_ATC_FAIL_4 = 4 ,
103 FSM_STATE_DELAY_5 = 5,
104 FSM_STATE_ON_CHG_AND_BAT_6 = 6,
105 FSM_STATE_FAST_CHG_7 = 7,
106 FSM_STATE_TRKL_CHG_8 = 8,
107 FSM_STATE_CHG_FAIL_9 = 9,
108 FSM_STATE_EOC_10 = 10,
109 FSM_STATE_ON_CHG_VREGOK_11 = 11,
110 FSM_STATE_ATC_PAUSE_13 = 13,
111 FSM_STATE_FAST_CHG_PAUSE_14 = 14,
112 FSM_STATE_TRKL_CHG_PAUSE_15 = 15,
113 FSM_STATE_START_BOOT = 20,
114 FSM_STATE_FLCB_VREGOK = 21,
115 FSM_STATE_FLCB = 22,
116};
117
Abhijeet Dharmapurikar236aa5a2011-11-03 12:17:19 -0700118struct fsm_state_to_batt_status {
119 enum chg_fsm_state fsm_state;
120 int batt_state;
121};
122
123static struct fsm_state_to_batt_status map[] = {
124 {FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
125 {FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
126 {FSM_STATE_BATFETDET_END_16, POWER_SUPPLY_STATUS_UNKNOWN},
127 /*
128 * for CHG_HIGHI_1 report NOT_CHARGING if battery missing,
129 * too hot/cold, charger too hot
130 */
131 {FSM_STATE_ON_CHG_HIGHI_1, POWER_SUPPLY_STATUS_FULL},
132 {FSM_STATE_ATC_2A, POWER_SUPPLY_STATUS_CHARGING},
133 {FSM_STATE_ATC_2B, POWER_SUPPLY_STATUS_CHARGING},
134 {FSM_STATE_ON_BAT_3, POWER_SUPPLY_STATUS_DISCHARGING},
135 {FSM_STATE_ATC_FAIL_4, POWER_SUPPLY_STATUS_DISCHARGING},
136 {FSM_STATE_DELAY_5, POWER_SUPPLY_STATUS_UNKNOWN },
137 {FSM_STATE_ON_CHG_AND_BAT_6, POWER_SUPPLY_STATUS_CHARGING},
138 {FSM_STATE_FAST_CHG_7, POWER_SUPPLY_STATUS_CHARGING},
139 {FSM_STATE_TRKL_CHG_8, POWER_SUPPLY_STATUS_CHARGING},
140 {FSM_STATE_CHG_FAIL_9, POWER_SUPPLY_STATUS_DISCHARGING},
141 {FSM_STATE_EOC_10, POWER_SUPPLY_STATUS_FULL},
142 {FSM_STATE_ON_CHG_VREGOK_11, POWER_SUPPLY_STATUS_NOT_CHARGING},
143 {FSM_STATE_ATC_PAUSE_13, POWER_SUPPLY_STATUS_NOT_CHARGING},
144 {FSM_STATE_FAST_CHG_PAUSE_14, POWER_SUPPLY_STATUS_NOT_CHARGING},
145 {FSM_STATE_TRKL_CHG_PAUSE_15, POWER_SUPPLY_STATUS_NOT_CHARGING},
146 {FSM_STATE_START_BOOT, POWER_SUPPLY_STATUS_NOT_CHARGING},
147 {FSM_STATE_FLCB_VREGOK, POWER_SUPPLY_STATUS_NOT_CHARGING},
148 {FSM_STATE_FLCB, POWER_SUPPLY_STATUS_NOT_CHARGING},
149};
150
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700151enum chg_regulation_loop {
152 VDD_LOOP = BIT(3),
153 BAT_CURRENT_LOOP = BIT(2),
154 INPUT_CURRENT_LOOP = BIT(1),
155 INPUT_VOLTAGE_LOOP = BIT(0),
156 CHG_ALL_LOOPS = VDD_LOOP | BAT_CURRENT_LOOP
157 | INPUT_CURRENT_LOOP | INPUT_VOLTAGE_LOOP,
158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160enum pmic_chg_interrupts {
161 USBIN_VALID_IRQ = 0,
162 USBIN_OV_IRQ,
163 BATT_INSERTED_IRQ,
164 VBATDET_LOW_IRQ,
165 USBIN_UV_IRQ,
166 VBAT_OV_IRQ,
167 CHGWDOG_IRQ,
168 VCP_IRQ,
169 ATCDONE_IRQ,
170 ATCFAIL_IRQ,
171 CHGDONE_IRQ,
172 CHGFAIL_IRQ,
173 CHGSTATE_IRQ,
174 LOOP_CHANGE_IRQ,
175 FASTCHG_IRQ,
176 TRKLCHG_IRQ,
177 BATT_REMOVED_IRQ,
178 BATTTEMP_HOT_IRQ,
179 CHGHOT_IRQ,
180 BATTTEMP_COLD_IRQ,
181 CHG_GONE_IRQ,
182 BAT_TEMP_OK_IRQ,
183 COARSE_DET_LOW_IRQ,
184 VDD_LOOP_IRQ,
185 VREG_OV_IRQ,
186 VBATDET_IRQ,
187 BATFET_IRQ,
188 PSI_IRQ,
189 DCIN_VALID_IRQ,
190 DCIN_OV_IRQ,
191 DCIN_UV_IRQ,
192 PM_CHG_MAX_INTS,
193};
194
195struct bms_notify {
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -0700196 int is_battery_full;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 int is_charging;
198 struct work_struct work;
199};
200
201/**
202 * struct pm8921_chg_chip -device information
203 * @dev: device pointer to access the parent
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204 * @usb_present: present status of usb
205 * @dc_present: present status of dc
206 * @usb_charger_current: usb current to charge the battery with used when
207 * the usb path is enabled or charging is resumed
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 * @update_time: how frequently the userland needs to be updated
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800209 * @max_voltage_mv: the max volts the batt should be charged up to
210 * @min_voltage_mv: the min battery voltage before turning the FETon
David Keitel0789fc62012-06-07 17:43:27 -0700211 * @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700212 * @alarm_low_mv: the battery alarm voltage low
213 * @alarm_high_mv: the battery alarm voltage high
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800214 * @cool_temp_dc: the cool temp threshold in deciCelcius
215 * @warm_temp_dc: the warm temp threshold in deciCelcius
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700216 * @resume_voltage_delta: the voltage delta from vdd max at which the
217 * battery should resume charging
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218 * @term_current: The charging based term current
219 *
220 */
221struct pm8921_chg_chip {
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700222 struct device *dev;
223 unsigned int usb_present;
224 unsigned int dc_present;
225 unsigned int usb_charger_current;
226 unsigned int max_bat_chg_current;
227 unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700228 unsigned int ttrkl_time;
229 unsigned int update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800230 unsigned int max_voltage_mv;
231 unsigned int min_voltage_mv;
David Keitel0789fc62012-06-07 17:43:27 -0700232 unsigned int uvd_voltage_mv;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700233 unsigned int safe_current_ma;
234 unsigned int alarm_low_mv;
235 unsigned int alarm_high_mv;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -0800236 int cool_temp_dc;
237 int warm_temp_dc;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700238 unsigned int temp_check_period;
239 unsigned int cool_bat_chg_current;
240 unsigned int warm_bat_chg_current;
241 unsigned int cool_bat_voltage;
242 unsigned int warm_bat_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -0700243 unsigned int is_bat_cool;
244 unsigned int is_bat_warm;
245 unsigned int resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700246 int resume_charge_percent;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700247 unsigned int term_current;
248 unsigned int vbat_channel;
249 unsigned int batt_temp_channel;
250 unsigned int batt_id_channel;
251 struct power_supply usb_psy;
David Keitel6ed71a52012-01-30 12:42:18 -0800252 struct power_supply dc_psy;
David Keitel88e1b572012-01-11 11:57:14 -0800253 struct power_supply *ext_psy;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700254 struct power_supply batt_psy;
255 struct dentry *dent;
256 struct bms_notify bms_notify;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700257 int *usb_trim_table;
Amir Samuelovd31ef502011-10-26 14:41:36 +0200258 bool ext_charging;
259 bool ext_charge_done;
David Keitel38bdd4f2012-04-19 15:39:13 -0700260 bool iusb_fine_res;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700262 struct work_struct battery_id_valid_work;
263 int64_t batt_id_min;
264 int64_t batt_id_max;
265 int trkl_voltage;
266 int weak_voltage;
267 int trkl_current;
268 int weak_current;
269 int vin_min;
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -0800270 unsigned int *thermal_mitigation;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700271 int thermal_levels;
272 struct delayed_work update_heartbeat_work;
273 struct delayed_work eoc_work;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800274 struct delayed_work unplug_check_work;
David Keitelacf57c82012-03-07 18:48:50 -0800275 struct delayed_work vin_collapse_check_work;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700276 struct delayed_work btc_override_work;
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -0700277 struct wake_lock eoc_wake_lock;
278 enum pm8921_chg_cold_thr cold_thr;
279 enum pm8921_chg_hot_thr hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -0800280 int rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -0700281 enum pm8921_chg_led_src_config led_src_config;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -0700282 bool host_mode;
David Keitelff4f9ce2012-08-24 15:11:23 -0700283 bool has_dc_supply;
David Keitel6ccbf132012-05-30 14:21:24 -0700284 u8 active_path;
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -0700285 int recent_reported_soc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700286 int battery_less_hardware;
287 int ibatmax_max_adj_ma;
288 int btc_override;
289 int btc_override_cold_decidegc;
290 int btc_override_hot_decidegc;
291 int btc_delay_ms;
292 bool btc_panic_if_cant_stop_chg;
293 int stop_chg_upon_expiry;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -0800294 bool disable_aicl;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +0530295 int usb_type;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +0530296 bool disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297};
298
David Keitelacf57c82012-03-07 18:48:50 -0800299/* user space parameter to limit usb current */
300static unsigned int usb_max_current;
301/*
302 * usb_target_ma is used for wall charger
303 * adaptive input current limiting only. Use
304 * pm_iusbmax_get() to get current maximum usb current setting.
305 */
306static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700308static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
310static struct pm8921_chg_chip *the_chip;
311
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700312#define LPM_ENABLE_BIT BIT(2)
313static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
314{
315 int rc;
316 u8 reg;
317
318 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
319 if (rc) {
320 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
321 CHG_CNTRL, rc);
322 return rc;
323 }
324 reg &= ~LPM_ENABLE_BIT;
325 reg |= (enable ? LPM_ENABLE_BIT : 0);
326
327 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
328 if (rc) {
329 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
330 CHG_CNTRL, rc);
331 return rc;
332 }
333
334 return rc;
335}
336
337static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
338{
339 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700340
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -0800341 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
342 if (rc)
343 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700344
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700345 return rc;
346}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700347
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
349 u8 mask, u8 val)
350{
351 int rc;
352 u8 reg;
353
354 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
355 if (rc) {
356 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
357 return rc;
358 }
359 reg &= ~mask;
360 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700361 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700363 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 return rc;
365 }
366 return 0;
367}
368
David Keitelcf867232012-01-27 18:40:12 -0800369static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
370{
371 return pm8xxx_read_irq_stat(chip->dev->parent,
372 chip->pmic_chg_irq[irq_id]);
373}
374
375/* Treat OverVoltage/UnderVoltage as source missing */
376static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
377{
378 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
379}
380
381/* Treat OverVoltage/UnderVoltage as source missing */
382static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
383{
384 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
385}
386
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700387static int is_batfet_closed(struct pm8921_chg_chip *chip)
388{
389 return pm_chg_get_rt_status(chip, BATFET_IRQ);
390}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391#define CAPTURE_FSM_STATE_CMD 0xC2
392#define READ_BANK_7 0x70
393#define READ_BANK_4 0x40
394static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
395{
396 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800397 int err = 0, ret = 0;
398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800400 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 if (err) {
402 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800403 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700404 }
405
406 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800407 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 if (err) {
409 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800410 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 }
412
413 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
414 if (err) {
415 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800416 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 }
418 /* get the lower 4 bits */
419 ret = temp & 0xF;
420
421 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800422 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 if (err) {
424 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800425 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 }
427
428 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
429 if (err) {
430 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800431 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432 }
433 /* get the upper 1 bit */
434 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800435
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800436err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800437 if (err)
438 return err;
439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 return ret;
441}
442
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700443#define READ_BANK_6 0x60
444static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
445{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800446 u8 temp, data;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800447 int err = 0;
448
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700449 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800450 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700451 if (err) {
452 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800453 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700454 }
455
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800456 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700457 if (err) {
458 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800459 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700460 }
461
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800462err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800463 if (err)
464 return err;
465
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700466 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800467 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700468}
469
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470#define CHG_USB_SUSPEND_BIT BIT(2)
471static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
472{
473 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
474 enable ? CHG_USB_SUSPEND_BIT : 0);
475}
476
477#define CHG_EN_BIT BIT(7)
478static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
479{
480 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
481 enable ? CHG_EN_BIT : 0);
482}
483
David Keitel753ec8d2011-11-02 10:56:37 -0700484#define CHG_FAILED_CLEAR BIT(0)
485#define ATC_FAILED_CLEAR BIT(1)
486static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
487{
488 int rc;
489
490 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
491 clear ? ATC_FAILED_CLEAR : 0);
492 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
493 clear ? CHG_FAILED_CLEAR : 0);
494 return rc;
495}
496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497#define CHG_CHARGE_DIS_BIT BIT(1)
498static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
499{
500 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
501 disable ? CHG_CHARGE_DIS_BIT : 0);
502}
503
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800504static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
505{
506 u8 temp;
507
508 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
509 return temp & CHG_CHARGE_DIS_BIT;
510}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511#define PM8921_CHG_V_MIN_MV 3240
512#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800513#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514#define PM8921_CHG_VDDMAX_MAX 4500
515#define PM8921_CHG_VDDMAX_MIN 3400
516#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800517static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800519 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800520 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800522 if (voltage < PM8921_CHG_VDDMAX_MIN
523 || voltage > PM8921_CHG_VDDMAX_MAX) {
524 pr_err("bad mV=%d asked to set\n", voltage);
525 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 }
David Keitelcf867232012-01-27 18:40:12 -0800527
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800528 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
529
530 remainder = voltage % 20;
531 if (remainder >= 10) {
532 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
533 }
534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700536 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537}
538
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700539static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
540{
541 u8 temp;
542 int rc;
543
544 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
545 if (rc) {
546 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700547 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700548 return rc;
549 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800550 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
551 + PM8921_CHG_V_MIN_MV;
552 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
553 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700554 return 0;
555}
556
David Keitelcf867232012-01-27 18:40:12 -0800557static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
558{
559 int current_mv, ret, steps, i;
560 bool increase;
561
562 ret = 0;
563
564 if (voltage < PM8921_CHG_VDDMAX_MIN
565 || voltage > PM8921_CHG_VDDMAX_MAX) {
566 pr_err("bad mV=%d asked to set\n", voltage);
567 return -EINVAL;
568 }
569
570 ret = pm_chg_vddmax_get(chip, &current_mv);
571 if (ret) {
572 pr_err("Failed to read vddmax rc=%d\n", ret);
573 return -EINVAL;
574 }
575 if (current_mv == voltage)
576 return 0;
577
578 /* Only change in increments when USB is present */
579 if (is_usb_chg_plugged_in(chip)) {
580 if (current_mv < voltage) {
581 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
582 increase = true;
583 } else {
584 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
585 increase = false;
586 }
587 for (i = 0; i < steps; i++) {
588 if (increase)
589 current_mv += PM8921_CHG_V_STEP_MV;
590 else
591 current_mv -= PM8921_CHG_V_STEP_MV;
592 ret |= __pm_chg_vddmax_set(chip, current_mv);
593 }
594 }
595 ret |= __pm_chg_vddmax_set(chip, voltage);
596 return ret;
597}
598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599#define PM8921_CHG_VDDSAFE_MIN 3400
600#define PM8921_CHG_VDDSAFE_MAX 4500
601static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
602{
603 u8 temp;
604
605 if (voltage < PM8921_CHG_VDDSAFE_MIN
606 || voltage > PM8921_CHG_VDDSAFE_MAX) {
607 pr_err("bad mV=%d asked to set\n", voltage);
608 return -EINVAL;
609 }
610 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
611 pr_debug("voltage=%d setting %02x\n", voltage, temp);
612 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
613}
614
615#define PM8921_CHG_VBATDET_MIN 3240
616#define PM8921_CHG_VBATDET_MAX 5780
617static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
618{
619 u8 temp;
620
621 if (voltage < PM8921_CHG_VBATDET_MIN
622 || voltage > PM8921_CHG_VBATDET_MAX) {
623 pr_err("bad mV=%d asked to set\n", voltage);
624 return -EINVAL;
625 }
626 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
627 pr_debug("voltage=%d setting %02x\n", voltage, temp);
628 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
629}
630
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700631#define PM8921_CHG_VINMIN_MIN_MV 3800
632#define PM8921_CHG_VINMIN_STEP_MV 100
633#define PM8921_CHG_VINMIN_USABLE_MAX 6500
634#define PM8921_CHG_VINMIN_USABLE_MIN 4300
635#define PM8921_CHG_VINMIN_MASK 0x1F
636static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
637{
638 u8 temp;
639
640 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
641 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
642 pr_err("bad mV=%d asked to set\n", voltage);
643 return -EINVAL;
644 }
645 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
646 pr_debug("voltage=%d setting %02x\n", voltage, temp);
647 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
648 temp);
649}
650
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800651static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
652{
653 u8 temp;
654 int rc, voltage_mv;
655
656 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
657 temp &= PM8921_CHG_VINMIN_MASK;
658
659 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
660 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
661
662 return voltage_mv;
663}
664
David Keitel0789fc62012-06-07 17:43:27 -0700665#define PM8917_USB_UVD_MIN_MV 3850
666#define PM8917_USB_UVD_MAX_MV 4350
667#define PM8917_USB_UVD_STEP_MV 100
668#define PM8917_USB_UVD_MASK 0x7
669static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
670{
671 u8 temp;
672
673 if (thresh_mv < PM8917_USB_UVD_MIN_MV
674 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
675 pr_err("bad mV=%d asked to set\n", thresh_mv);
676 return -EINVAL;
677 }
678 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
679 return pm_chg_masked_write(chip, OVP_USB_UVD,
680 PM8917_USB_UVD_MASK, temp);
681}
682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700684#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685#define PM8921_CHG_I_MIN_MA 225
686#define PM8921_CHG_I_STEP_MA 50
687#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700688static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
689{
690 u8 temp;
691 int rc;
692
693 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
694 if (rc) {
695 pr_err("rc = %d while reading ibat max\n", rc);
696 *ibat_ma = 0;
697 return rc;
698 }
699 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
700 + PM8921_CHG_I_MIN_MA;
701 return 0;
702}
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
705{
706 u8 temp;
707
708 if (chg_current < PM8921_CHG_IBATMAX_MIN
709 || chg_current > PM8921_CHG_IBATMAX_MAX) {
710 pr_err("bad mA=%d asked to set\n", chg_current);
711 return -EINVAL;
712 }
713 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
714 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
715}
716
717#define PM8921_CHG_IBATSAFE_MIN 225
718#define PM8921_CHG_IBATSAFE_MAX 3375
719static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
720{
721 u8 temp;
722
723 if (chg_current < PM8921_CHG_IBATSAFE_MIN
724 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
725 pr_err("bad mA=%d asked to set\n", chg_current);
726 return -EINVAL;
727 }
728 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
729 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
730 PM8921_CHG_I_MASK, temp);
731}
732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700733#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700734#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735#define PM8921_CHG_ITERM_STEP_MA 10
736#define PM8921_CHG_ITERM_MASK 0xF
737static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
738{
739 u8 temp;
740
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700741 if (chg_current < PM8921_CHG_ITERM_MIN_MA
742 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743 pr_err("bad mA=%d asked to set\n", chg_current);
744 return -EINVAL;
745 }
746
747 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
748 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700749 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750 temp);
751}
752
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700753static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
754{
755 u8 temp;
756 int rc;
757
758 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
759 if (rc) {
760 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700761 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700762 return rc;
763 }
764 temp &= PM8921_CHG_ITERM_MASK;
765 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
766 + PM8921_CHG_ITERM_MIN_MA;
767 return 0;
768}
769
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800770struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700771 int usb_ma;
772 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800773};
774
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700775/* USB Trim tables */
776static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
777 0x0,
778 0x0,
779 -0x9,
780 0x0,
781 -0xD,
782 0x0,
783 -0x10,
784 -0x11,
785 0x0,
786 0x0,
787 -0x25,
788 0x0,
789 -0x28,
790 0x0,
791 -0x32,
792 0x0
793};
794
795static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
796 0x0,
797 0x0,
798 0xA,
799 0xC,
800 0x10,
801 0x10,
802 0x13,
803 0x14,
804 0x13,
805 0x3,
806 0x1A,
807 0x1D,
808 0x1D,
809 0x21,
810 0x24,
811 0x26
812};
813
814/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800815static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700816 {100, 0x0},
817 {200, 0x1},
818 {500, 0x2},
819 {600, 0x3},
820 {700, 0x4},
821 {800, 0x5},
822 {850, 0x6},
823 {900, 0x8},
824 {950, 0x7},
825 {1000, 0x9},
826 {1100, 0xA},
827 {1200, 0xB},
828 {1300, 0xC},
829 {1400, 0xD},
830 {1500, 0xE},
831 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800832};
833
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700834#define REG_SBI_CONFIG 0x04F
835#define PAGE3_ENABLE_MASK 0x6
836#define USB_OVP_TRIM_MASK 0x3F
837#define USB_OVP_TRIM_PM8917_MASK 0x7F
838#define USB_OVP_TRIM_MIN 0x00
839#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
840#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
841#define REG_USB_OVP_TRIM_PM8917 0x2B5
842#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
843static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
844{
845 u8 temp, sbi_config, msb, lsb, mask;
846 s8 trim;
847 int rc = 0;
848 static u8 usb_trim_reg_orig = 0xFF;
849
850 /* No trim data for PM8921 */
851 if (!chip->usb_trim_table)
852 return 0;
853
854 if (usb_trim_reg_orig == 0xFF) {
855 rc = pm8xxx_readb(chip->dev->parent,
856 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
857 if (rc) {
858 pr_err("error = %d reading sbi config reg\n", rc);
859 return rc;
860 }
861
862 rc = pm8xxx_readb(chip->dev->parent,
863 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
864 if (rc) {
865 pr_err("error = %d reading sbi config reg\n", rc);
866 return rc;
867 }
868
869 msb = msb >> 5;
870 lsb = lsb >> 5;
871 usb_trim_reg_orig = msb << 3 | lsb;
872
873 if (pm8xxx_get_version(chip->dev->parent)
874 == PM8XXX_VERSION_8917) {
875 rc = pm8xxx_readb(chip->dev->parent,
876 REG_USB_OVP_TRIM_PM8917, &msb);
877 if (rc) {
878 pr_err("error = %d reading config reg\n", rc);
879 return rc;
880 }
881
882 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
883 usb_trim_reg_orig |= msb << 6;
884 }
885 }
886
887 /* use the original trim value */
888 trim = usb_trim_reg_orig;
889
890 trim += chip->usb_trim_table[index];
891 if (trim < 0)
892 trim = 0;
893
894 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
895 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
896
897 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
898 if (rc) {
899 pr_err("error = %d reading sbi config reg\n", rc);
900 return rc;
901 }
902
903 temp = sbi_config | PAGE3_ENABLE_MASK;
904 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
905 if (rc) {
906 pr_err("error = %d writing sbi config reg\n", rc);
907 return rc;
908 }
909
910 mask = USB_OVP_TRIM_MASK;
911
912 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
913 mask = USB_OVP_TRIM_PM8917_MASK;
914
915 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
916 if (rc) {
917 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
918 return rc;
919 }
920
921 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
922 if (rc) {
923 pr_err("error = %d writing sbi config reg\n", rc);
924 return rc;
925 }
926 return rc;
927}
928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700930#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931#define PM8921_CHG_IUSB_MAX 7
932#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700933#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700934static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700936 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700937 int rc;
938
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700939 reg_val = usb_ma_table[index].value >> 1;
940 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700942 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
943 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 return -EINVAL;
945 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700946 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
947
948 /* IUSB_FINE_RES */
949 if (chip->iusb_fine_res) {
950 /* Clear IUSB_FINE_RES bit to avoid overshoot */
951 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
952 PM8917_IUSB_FINE_RES, 0);
953
954 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
955 PM8921_CHG_IUSB_MASK, temp);
956
957 if (rc) {
958 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
959 return rc;
960 }
961
962 if (fineres) {
963 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
964 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700965 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700966 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
967 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700968 return rc;
969 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700970 }
971 } else {
972 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
973 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700974 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700975 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700976 return rc;
977 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700978 }
979
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700980 rc = pm_chg_usb_trim(chip, index);
981 if (rc)
982 pr_err("unable to set usb trim rc = %d\n", rc);
983
David Keitel38bdd4f2012-04-19 15:39:13 -0700984 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985}
986
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800987static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
988{
David Keitel38bdd4f2012-04-19 15:39:13 -0700989 u8 temp, fineres;
990 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800991
David Keitel38bdd4f2012-04-19 15:39:13 -0700992 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800993 *mA = 0;
994 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
995 if (rc) {
996 pr_err("err=%d reading PBL_ACCESS2\n", rc);
997 return rc;
998 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700999
1000 if (chip->iusb_fine_res) {
1001 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1002 if (rc) {
1003 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1004 return rc;
1005 }
1006 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001007 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001008 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1009
1010 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1011 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1012 if (usb_ma_table[i].value == temp)
1013 break;
1014 }
1015
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001016 if (i < 0) {
1017 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1018 i = 0;
1019 }
1020
Willie Ruan13c972d2012-11-15 11:56:36 -08001021 if (i < 0) {
1022 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1023 i = 0;
1024 }
1025
David Keitel38bdd4f2012-04-19 15:39:13 -07001026 *mA = usb_ma_table[i].usb_ma;
1027
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001028 return rc;
1029}
1030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031#define PM8921_CHG_WD_MASK 0x1F
1032static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1033{
1034 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001035 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1036}
1037
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001038#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001039#define PM8921_CHG_TCHG_MIN 4
1040#define PM8921_CHG_TCHG_MAX 512
1041#define PM8921_CHG_TCHG_STEP 4
1042static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1043{
1044 u8 temp;
1045
1046 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1047 pr_err("bad max minutes =%d asked to set\n", minutes);
1048 return -EINVAL;
1049 }
1050
1051 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1052 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1053 temp);
1054}
1055
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001056#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001057#define PM8921_CHG_TTRKL_MIN 1
1058#define PM8921_CHG_TTRKL_MAX 64
1059static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1060{
1061 u8 temp;
1062
1063 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1064 pr_err("bad max minutes =%d asked to set\n", minutes);
1065 return -EINVAL;
1066 }
1067
1068 temp = minutes - 1;
1069 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1070 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001071}
1072
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001073#define PM8921_CHG_VTRKL_MIN_MV 2050
1074#define PM8921_CHG_VTRKL_MAX_MV 2800
1075#define PM8921_CHG_VTRKL_STEP_MV 50
1076#define PM8921_CHG_VTRKL_SHIFT 4
1077#define PM8921_CHG_VTRKL_MASK 0xF0
1078static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1079{
1080 u8 temp;
1081
1082 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1083 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1084 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1085 return -EINVAL;
1086 }
1087
1088 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1089 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1090 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1091 temp);
1092}
1093
1094#define PM8921_CHG_VWEAK_MIN_MV 2100
1095#define PM8921_CHG_VWEAK_MAX_MV 3600
1096#define PM8921_CHG_VWEAK_STEP_MV 100
1097#define PM8921_CHG_VWEAK_MASK 0x0F
1098static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1099{
1100 u8 temp;
1101
1102 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1103 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1104 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1105 return -EINVAL;
1106 }
1107
1108 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1109 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1110 temp);
1111}
1112
1113#define PM8921_CHG_ITRKL_MIN_MA 50
1114#define PM8921_CHG_ITRKL_MAX_MA 200
1115#define PM8921_CHG_ITRKL_MASK 0x0F
1116#define PM8921_CHG_ITRKL_STEP_MA 10
1117static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1118{
1119 u8 temp;
1120
1121 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1122 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1123 pr_err("bad current = %dmA asked to set\n", milliamps);
1124 return -EINVAL;
1125 }
1126
1127 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1128
1129 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1130 temp);
1131}
1132
1133#define PM8921_CHG_IWEAK_MIN_MA 325
1134#define PM8921_CHG_IWEAK_MAX_MA 525
1135#define PM8921_CHG_IWEAK_SHIFT 7
1136#define PM8921_CHG_IWEAK_MASK 0x80
1137static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1138{
1139 u8 temp;
1140
1141 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1142 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1143 pr_err("bad current = %dmA asked to set\n", milliamps);
1144 return -EINVAL;
1145 }
1146
1147 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1148 temp = 0;
1149 else
1150 temp = 1;
1151
1152 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1153 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1154 temp);
1155}
1156
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001157#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1158#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1159static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1160 enum pm8921_chg_cold_thr cold_thr)
1161{
1162 u8 temp;
1163
1164 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1165 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1166 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1167 PM8921_CHG_BATT_TEMP_THR_COLD,
1168 temp);
1169}
1170
1171#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1172#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1173static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1174 enum pm8921_chg_hot_thr hot_thr)
1175{
1176 u8 temp;
1177
1178 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1179 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1180 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1181 PM8921_CHG_BATT_TEMP_THR_HOT,
1182 temp);
1183}
1184
Jay Chokshid674a512012-03-15 14:06:04 -07001185#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1186#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1187static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1188 enum pm8921_chg_led_src_config led_src_config)
1189{
1190 u8 temp;
1191
1192 if (led_src_config < LED_SRC_GND ||
1193 led_src_config > LED_SRC_BYPASS)
1194 return -EINVAL;
1195
1196 if (led_src_config == LED_SRC_BYPASS)
1197 return 0;
1198
1199 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1200
1201 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1202 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1203}
1204
David Keitel8c5201a2012-02-24 16:08:54 -08001205
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001206static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1207{
1208 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001209 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001210
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001211 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001212 if (rc) {
1213 pr_err("error reading batt id channel = %d, rc = %d\n",
1214 chip->vbat_channel, rc);
1215 return rc;
1216 }
1217 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1218 result.measurement);
1219 return result.physical;
1220}
1221
1222static int is_battery_valid(struct pm8921_chg_chip *chip)
1223{
1224 int64_t rc;
1225
1226 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1227 return 1;
1228
1229 rc = read_battery_id(chip);
1230 if (rc < 0) {
1231 pr_err("error reading batt id channel = %d, rc = %lld\n",
1232 chip->vbat_channel, rc);
1233 /* assume battery id is valid when adc error happens */
1234 return 1;
1235 }
1236
1237 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1238 pr_err("batt_id phy =%lld is not valid\n", rc);
1239 return 0;
1240 }
1241 return 1;
1242}
1243
1244static void check_battery_valid(struct pm8921_chg_chip *chip)
1245{
1246 if (is_battery_valid(chip) == 0) {
1247 pr_err("batt_id not valid, disbling charging\n");
1248 pm_chg_auto_enable(chip, 0);
1249 } else {
1250 pm_chg_auto_enable(chip, !charging_disabled);
1251 }
1252}
1253
1254static void battery_id_valid(struct work_struct *work)
1255{
1256 struct pm8921_chg_chip *chip = container_of(work,
1257 struct pm8921_chg_chip, battery_id_valid_work);
1258
1259 check_battery_valid(chip);
1260}
1261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1263{
1264 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1265 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1266 enable_irq(chip->pmic_chg_irq[interrupt]);
1267 }
1268}
1269
1270static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1271{
1272 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1273 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1274 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1275 }
1276}
1277
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001278static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1279{
1280 return test_bit(interrupt, chip->enabled_irqs);
1281}
1282
Amir Samuelovd31ef502011-10-26 14:41:36 +02001283static bool is_ext_charging(struct pm8921_chg_chip *chip)
1284{
David Keitel88e1b572012-01-11 11:57:14 -08001285 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001286
David Keitel88e1b572012-01-11 11:57:14 -08001287 if (!chip->ext_psy)
1288 return false;
1289 if (chip->ext_psy->get_property(chip->ext_psy,
1290 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1291 return false;
1292 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1293 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001294
1295 return false;
1296}
1297
1298static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1299{
David Keitel88e1b572012-01-11 11:57:14 -08001300 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001301
David Keitel88e1b572012-01-11 11:57:14 -08001302 if (!chip->ext_psy)
1303 return false;
1304 if (chip->ext_psy->get_property(chip->ext_psy,
1305 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1306 return false;
1307 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001308 return true;
1309
1310 return false;
1311}
1312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313static int is_battery_charging(int fsm_state)
1314{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001315 if (is_ext_charging(the_chip))
1316 return 1;
1317
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318 switch (fsm_state) {
1319 case FSM_STATE_ATC_2A:
1320 case FSM_STATE_ATC_2B:
1321 case FSM_STATE_ON_CHG_AND_BAT_6:
1322 case FSM_STATE_FAST_CHG_7:
1323 case FSM_STATE_TRKL_CHG_8:
1324 return 1;
1325 }
1326 return 0;
1327}
1328
1329static void bms_notify(struct work_struct *work)
1330{
1331 struct bms_notify *n = container_of(work, struct bms_notify, work);
1332
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001333 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001335 } else {
1336 pm8921_bms_charging_end(n->is_battery_full);
1337 n->is_battery_full = 0;
1338 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339}
1340
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001341static void bms_notify_check(struct pm8921_chg_chip *chip)
1342{
1343 int fsm_state, new_is_charging;
1344
1345 fsm_state = pm_chg_get_fsm_state(chip);
1346 new_is_charging = is_battery_charging(fsm_state);
1347
1348 if (chip->bms_notify.is_charging ^ new_is_charging) {
1349 chip->bms_notify.is_charging = new_is_charging;
1350 schedule_work(&(chip->bms_notify.work));
1351 }
1352}
1353
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001354static enum power_supply_property pm_power_props_usb[] = {
1355 POWER_SUPPLY_PROP_PRESENT,
1356 POWER_SUPPLY_PROP_ONLINE,
1357 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001358 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001359 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001360};
1361
1362static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001364 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365};
1366
1367static char *pm_power_supplied_to[] = {
1368 "battery",
1369};
1370
David Keitel6ed71a52012-01-30 12:42:18 -08001371#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001372static int pm_power_get_property_mains(struct power_supply *psy,
1373 enum power_supply_property psp,
1374 union power_supply_propval *val)
1375{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001376 int type;
1377
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001378 /* Check if called before init */
1379 if (!the_chip)
1380 return -EINVAL;
1381
1382 switch (psp) {
1383 case POWER_SUPPLY_PROP_PRESENT:
1384 case POWER_SUPPLY_PROP_ONLINE:
1385 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001386
1387 if (the_chip->has_dc_supply) {
1388 val->intval = 1;
1389 return 0;
1390 }
1391
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001392 if (the_chip->dc_present) {
1393 val->intval = 1;
1394 return 0;
1395 }
1396
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301397 type = the_chip->usb_type;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001398 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1399 type == POWER_SUPPLY_TYPE_USB_ACA ||
1400 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001401 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001402
1403 break;
1404 default:
1405 return -EINVAL;
1406 }
1407 return 0;
1408}
1409
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001410static int disable_aicl(int disable)
1411{
1412 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1413 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1414 pr_err("called with invalid param :%d\n", disable);
1415 return -EINVAL;
1416 }
1417
1418 if (!the_chip) {
1419 pr_err("%s called before init\n", __func__);
1420 return -EINVAL;
1421 }
1422
1423 pr_debug("Disable AICL = %d\n", disable);
1424 the_chip->disable_aicl = disable;
1425 return 0;
1426}
1427
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001428static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1429{
1430 int rc;
1431
1432 if (!chip->host_mode)
1433 return 0;
1434
1435 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001436 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001437 if (rc < 0) {
1438 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1439 return rc;
1440 }
1441
1442 chip->host_mode = 0;
1443
1444 return 0;
1445}
1446
1447static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1448{
1449 int rc;
1450
1451 if (chip->host_mode)
1452 return 0;
1453
1454 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001455 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001456 if (rc < 0) {
1457 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1458 return rc;
1459 }
1460
1461 chip->host_mode = 1;
1462
1463 return 0;
1464}
1465
1466static int pm_power_set_property_usb(struct power_supply *psy,
1467 enum power_supply_property psp,
1468 const union power_supply_propval *val)
1469{
1470 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001471 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001472 return -EINVAL;
1473
1474 switch (psp) {
1475 case POWER_SUPPLY_PROP_SCOPE:
1476 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001477 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001478 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001479 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001480 else
1481 return -EINVAL;
1482 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001483 case POWER_SUPPLY_PROP_TYPE:
1484 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001485 case POWER_SUPPLY_PROP_HEALTH:
1486 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1487 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001488 default:
1489 return -EINVAL;
1490 }
1491 return 0;
1492}
1493
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001494static int usb_property_is_writeable(struct power_supply *psy,
1495 enum power_supply_property psp)
1496{
1497 switch (psp) {
1498 case POWER_SUPPLY_PROP_HEALTH:
1499 return 1;
1500 default:
1501 break;
1502 }
1503
1504 return 0;
1505}
1506
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001507static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 enum power_supply_property psp,
1509 union power_supply_propval *val)
1510{
David Keitel6ed71a52012-01-30 12:42:18 -08001511 int current_max;
1512
1513 /* Check if called before init */
1514 if (!the_chip)
1515 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516
1517 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001518 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001519 if (pm_is_chg_charge_dis(the_chip)) {
1520 val->intval = 0;
1521 } else {
1522 pm_chg_iusbmax_get(the_chip, &current_max);
1523 val->intval = current_max;
1524 }
David Keitel6ed71a52012-01-30 12:42:18 -08001525 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001527 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001528 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001529
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301530 if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001531 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001534
1535 case POWER_SUPPLY_PROP_SCOPE:
1536 if (the_chip->host_mode)
1537 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1538 else
1539 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1540 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001541 case POWER_SUPPLY_PROP_HEALTH:
1542 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1543 val->intval = the_chip->disable_aicl;
1544 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545 default:
1546 return -EINVAL;
1547 }
1548 return 0;
1549}
1550
1551static enum power_supply_property msm_batt_power_props[] = {
1552 POWER_SUPPLY_PROP_STATUS,
1553 POWER_SUPPLY_PROP_CHARGE_TYPE,
1554 POWER_SUPPLY_PROP_HEALTH,
1555 POWER_SUPPLY_PROP_PRESENT,
1556 POWER_SUPPLY_PROP_TECHNOLOGY,
1557 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1558 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1559 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1560 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001561 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001562 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001563 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001564 POWER_SUPPLY_PROP_CHARGE_FULL,
1565 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566};
1567
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001568static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569{
1570 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001571 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001573 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 if (rc) {
1575 pr_err("error reading adc channel = %d, rc = %d\n",
1576 chip->vbat_channel, rc);
1577 return rc;
1578 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001579 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 result.measurement);
1581 return (int)result.physical;
1582}
1583
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001584static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1585{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001586 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1587 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1588 unsigned int low_voltage = chip->min_voltage_mv;
1589 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001590
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001591 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001592 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001593 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001594 return 100;
1595 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001596 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001597 / (high_voltage - low_voltage);
1598}
1599
David Keitel4f9397b2012-04-16 11:46:16 -07001600static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1601{
1602 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1603}
1604
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001605static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1606{
1607 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1608 int fsm_state = pm_chg_get_fsm_state(chip);
1609 int i;
1610
1611 if (chip->ext_psy) {
1612 if (chip->ext_charge_done)
1613 return POWER_SUPPLY_STATUS_FULL;
1614 if (chip->ext_charging)
1615 return POWER_SUPPLY_STATUS_CHARGING;
1616 }
1617
1618 for (i = 0; i < ARRAY_SIZE(map); i++)
1619 if (map[i].fsm_state == fsm_state)
1620 batt_state = map[i].batt_state;
1621
1622 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1623 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1624 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1625 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1626 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1627
1628 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1629 }
1630 return batt_state;
1631}
1632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1634{
David Keitel4f9397b2012-04-16 11:46:16 -07001635 int percent_soc;
1636
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001637 if (chip->battery_less_hardware)
1638 return 100;
1639
David Keitel4f9397b2012-04-16 11:46:16 -07001640 if (!get_prop_batt_present(chip))
1641 percent_soc = voltage_based_capacity(chip);
1642 else
1643 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001644
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001645 if (percent_soc == -ENXIO)
1646 percent_soc = voltage_based_capacity(chip);
1647
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001648 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001649 pr_warn_ratelimited("low battery charge = %d%%\n",
1650 percent_soc);
1651
1652 if (percent_soc <= chip->resume_charge_percent
1653 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1654 pr_debug("soc fell below %d. charging enabled.\n",
1655 chip->resume_charge_percent);
1656 if (chip->is_bat_warm)
1657 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1658 chip->is_bat_warm,
1659 chip->resume_charge_percent);
1660 else if (chip->is_bat_cool)
1661 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1662 chip->is_bat_cool,
1663 chip->resume_charge_percent);
1664 else
1665 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1666 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001667
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001668 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001669 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670}
1671
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001672static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1673{
1674 return pm8921_bms_get_current_max();
1675}
1676
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001677static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1678{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001679 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001680
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001681 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001682 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001683 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001684 }
1685
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001686 if (rc) {
1687 pr_err("unable to get batt current rc = %d\n", rc);
1688 return rc;
1689 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001690 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001691 }
1692}
1693
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001694static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1695{
1696 int rc;
1697
1698 rc = pm8921_bms_get_fcc();
1699 if (rc < 0)
1700 pr_err("unable to get batt fcc rc = %d\n", rc);
1701 return rc;
1702}
1703
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001704static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1705{
1706 int rc;
1707 int cc_uah;
1708
1709 rc = pm8921_bms_cc_uah(&cc_uah);
1710
1711 if (rc == 0)
1712 return cc_uah;
1713
1714 pr_err("unable to get batt fcc rc = %d\n", rc);
1715 return rc;
1716}
1717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1719{
1720 int temp;
1721
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001722 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1723 if (temp)
1724 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001725
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001726 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1727 if (temp)
1728 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001730 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731}
1732
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1734{
1735 int temp;
1736
Amir Samuelovd31ef502011-10-26 14:41:36 +02001737 if (!get_prop_batt_present(chip))
1738 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1739
1740 if (is_ext_trickle_charging(chip))
1741 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1742
1743 if (is_ext_charging(chip))
1744 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1745
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1747 if (temp)
1748 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1749
1750 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1751 if (temp)
1752 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1753
1754 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1755}
1756
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001757#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001758static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1759{
1760 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001761 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001762
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001763 if (chip->battery_less_hardware)
1764 return 300;
1765
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001766 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001767 if (rc) {
1768 pr_err("error reading adc channel = %d, rc = %d\n",
1769 chip->vbat_channel, rc);
1770 return rc;
1771 }
1772 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1773 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001774 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1775 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1776 (int) result.physical);
1777
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001778 return (int)result.physical;
1779}
1780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781static int pm_batt_power_get_property(struct power_supply *psy,
1782 enum power_supply_property psp,
1783 union power_supply_propval *val)
1784{
1785 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1786 batt_psy);
1787
1788 switch (psp) {
1789 case POWER_SUPPLY_PROP_STATUS:
1790 val->intval = get_prop_batt_status(chip);
1791 break;
1792 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1793 val->intval = get_prop_charge_type(chip);
1794 break;
1795 case POWER_SUPPLY_PROP_HEALTH:
1796 val->intval = get_prop_batt_health(chip);
1797 break;
1798 case POWER_SUPPLY_PROP_PRESENT:
1799 val->intval = get_prop_batt_present(chip);
1800 break;
1801 case POWER_SUPPLY_PROP_TECHNOLOGY:
1802 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1803 break;
1804 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001805 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 break;
1807 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001808 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 break;
1810 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001811 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001812 break;
1813 case POWER_SUPPLY_PROP_CAPACITY:
1814 val->intval = get_prop_batt_capacity(chip);
1815 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001816 case POWER_SUPPLY_PROP_CURRENT_NOW:
1817 val->intval = get_prop_batt_current(chip);
1818 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001819 case POWER_SUPPLY_PROP_CURRENT_MAX:
1820 val->intval = get_prop_batt_current_max(chip);
1821 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001822 case POWER_SUPPLY_PROP_TEMP:
1823 val->intval = get_prop_batt_temp(chip);
1824 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001825 case POWER_SUPPLY_PROP_CHARGE_FULL:
1826 val->intval = get_prop_batt_fcc(chip);
1827 break;
1828 case POWER_SUPPLY_PROP_CHARGE_NOW:
1829 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001830 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 default:
1832 return -EINVAL;
1833 }
1834
1835 return 0;
1836}
1837
1838static void (*notify_vbus_state_func_ptr)(int);
1839static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840
1841int pm8921_charger_register_vbus_sn(void (*callback)(int))
1842{
1843 pr_debug("%p\n", callback);
1844 notify_vbus_state_func_ptr = callback;
1845 return 0;
1846}
1847EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1848
1849/* this is passed to the hsusb via platform_data msm_otg_pdata */
1850void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1851{
1852 pr_debug("%p\n", callback);
1853 notify_vbus_state_func_ptr = NULL;
1854}
1855EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1856
1857static void notify_usb_of_the_plugin_event(int plugin)
1858{
1859 plugin = !!plugin;
1860 if (notify_vbus_state_func_ptr) {
1861 pr_debug("notifying plugin\n");
1862 (*notify_vbus_state_func_ptr) (plugin);
1863 } else {
1864 pr_debug("unable to notify plugin\n");
1865 }
1866}
1867
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868static void __pm8921_charger_vbus_draw(unsigned int mA)
1869{
1870 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001871 if (!the_chip) {
1872 pr_err("called before init\n");
1873 return;
1874 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001876 if (usb_max_current && mA > usb_max_current) {
1877 pr_debug("restricting usb current to %d instead of %d\n",
1878 usb_max_current, mA);
1879 mA = usb_max_current;
1880 }
1881
1882 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001884 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001886 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001887 }
1888 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1889 if (rc)
1890 pr_err("fail to set suspend bit rc=%d\n", rc);
1891 } else {
1892 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1893 if (rc)
1894 pr_err("fail to reset suspend bit rc=%d\n", rc);
1895 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1896 if (usb_ma_table[i].usb_ma <= mA)
1897 break;
1898 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001899
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001900 if (i < 0) {
1901 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1902 mA);
1903 i = 0;
1904 }
1905
Willie Ruan13c972d2012-11-15 11:56:36 -08001906 if (i < 0) {
1907 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1908 mA);
1909 i = 0;
1910 }
1911
David Keitel38bdd4f2012-04-19 15:39:13 -07001912 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001913 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001914 && !the_chip->iusb_fine_res)
1915 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 if (i < 0)
1917 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001918 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001919 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001920 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921 }
1922}
1923
1924/* USB calls these to tell us how much max usb current the system can draw */
1925void pm8921_charger_vbus_draw(unsigned int mA)
1926{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001927 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928
1929 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001930
David Keitel62c6a4b2012-05-17 12:54:59 -07001931 /*
1932 * Reject VBUS requests if USB connection is the only available
1933 * power source. This makes sure that if booting without
1934 * battery the iusb_max value is not decreased avoiding potential
1935 * brown_outs.
1936 *
1937 * This would also apply when the battery has been
1938 * removed from the running system.
1939 */
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001940 if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07001941 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001942 if (!the_chip->has_dc_supply) {
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001943 pr_err("rejected: no other power source mA = %d\n", mA);
David Keitelff4f9ce2012-08-24 15:11:23 -07001944 return;
1945 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001946 }
1947
David Keitelacf57c82012-03-07 18:48:50 -08001948 if (usb_max_current && mA > usb_max_current) {
1949 pr_warn("restricting usb current to %d instead of %d\n",
1950 usb_max_current, mA);
1951 mA = usb_max_current;
1952 }
Devin Kim2073afb2012-09-05 13:01:51 -07001953 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1954 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001955
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301956 if (usb_target_ma)
1957 usb_target_ma = mA;
1958
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001959
1960 if (mA > USB_WALL_THRESHOLD_MA)
1961 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
1962 else
1963 set_usb_now_ma = mA;
1964
1965 if (the_chip && the_chip->disable_aicl)
1966 set_usb_now_ma = mA;
1967
1968 if (the_chip)
1969 __pm8921_charger_vbus_draw(set_usb_now_ma);
1970 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 /*
1972 * called before pmic initialized,
1973 * save this value and use it at probe
1974 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001975 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976}
1977EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1978
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001979int pm8921_is_usb_chg_plugged_in(void)
1980{
1981 if (!the_chip) {
1982 pr_err("called before init\n");
1983 return -EINVAL;
1984 }
1985 return is_usb_chg_plugged_in(the_chip);
1986}
1987EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1988
1989int pm8921_is_dc_chg_plugged_in(void)
1990{
1991 if (!the_chip) {
1992 pr_err("called before init\n");
1993 return -EINVAL;
1994 }
1995 return is_dc_chg_plugged_in(the_chip);
1996}
1997EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1998
1999int pm8921_is_battery_present(void)
2000{
2001 if (!the_chip) {
2002 pr_err("called before init\n");
2003 return -EINVAL;
2004 }
2005 return get_prop_batt_present(the_chip);
2006}
2007EXPORT_SYMBOL(pm8921_is_battery_present);
2008
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002009int pm8921_is_batfet_closed(void)
2010{
2011 if (!the_chip) {
2012 pr_err("called before init\n");
2013 return -EINVAL;
2014 }
2015 return is_batfet_closed(the_chip);
2016}
2017EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002018/*
2019 * Disabling the charge current limit causes current
2020 * current limits to have no monitoring. An adequate charger
2021 * capable of supplying high current while sustaining VIN_MIN
2022 * is required if the limiting is disabled.
2023 */
2024int pm8921_disable_input_current_limit(bool disable)
2025{
2026 if (!the_chip) {
2027 pr_err("called before init\n");
2028 return -EINVAL;
2029 }
2030 if (disable) {
2031 pr_warn("Disabling input current limit!\n");
2032
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002033 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002034 }
2035 return 0;
2036}
2037EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2038
David Keitel0789fc62012-06-07 17:43:27 -07002039int pm8917_set_under_voltage_detection_threshold(int mv)
2040{
2041 if (!the_chip) {
2042 pr_err("called before init\n");
2043 return -EINVAL;
2044 }
2045 return pm_chg_uvd_threshold_set(the_chip, mv);
2046}
2047EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2048
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002049int pm8921_set_max_battery_charge_current(int ma)
2050{
2051 if (!the_chip) {
2052 pr_err("called before init\n");
2053 return -EINVAL;
2054 }
2055 return pm_chg_ibatmax_set(the_chip, ma);
2056}
2057EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2058
2059int pm8921_disable_source_current(bool disable)
2060{
2061 if (!the_chip) {
2062 pr_err("called before init\n");
2063 return -EINVAL;
2064 }
2065 if (disable)
2066 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002067
2068 pm_chg_usb_suspend_enable(the_chip, disable);
2069
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002070 return pm_chg_charge_dis(the_chip, disable);
2071}
2072EXPORT_SYMBOL(pm8921_disable_source_current);
2073
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002074int pm8921_regulate_input_voltage(int voltage)
2075{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002076 int rc;
2077
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002078 if (!the_chip) {
2079 pr_err("called before init\n");
2080 return -EINVAL;
2081 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002082 rc = pm_chg_vinmin_set(the_chip, voltage);
2083
2084 if (rc == 0)
2085 the_chip->vin_min = voltage;
2086
2087 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002088}
2089
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002090#define USB_OV_THRESHOLD_MASK 0x60
2091#define USB_OV_THRESHOLD_SHIFT 5
2092int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2093{
2094 u8 temp;
2095
2096 if (!the_chip) {
2097 pr_err("called before init\n");
2098 return -EINVAL;
2099 }
2100
2101 if (ov > PM_USB_OV_7V) {
2102 pr_err("limiting to over voltage threshold to 7volts\n");
2103 ov = PM_USB_OV_7V;
2104 }
2105
2106 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2107
2108 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2109 USB_OV_THRESHOLD_MASK, temp);
2110}
2111EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2112
2113#define USB_DEBOUNCE_TIME_MASK 0x06
2114#define USB_DEBOUNCE_TIME_SHIFT 1
2115int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2116{
2117 u8 temp;
2118
2119 if (!the_chip) {
2120 pr_err("called before init\n");
2121 return -EINVAL;
2122 }
2123
2124 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2125 pr_err("limiting debounce to 80.5ms\n");
2126 ms = PM_USB_DEBOUNCE_80P5MS;
2127 }
2128
2129 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2130
2131 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2132 USB_DEBOUNCE_TIME_MASK, temp);
2133}
2134EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2135
2136#define USB_OVP_DISABLE_MASK 0x80
2137int pm8921_usb_ovp_disable(int disable)
2138{
2139 u8 temp = 0;
2140
2141 if (!the_chip) {
2142 pr_err("called before init\n");
2143 return -EINVAL;
2144 }
2145
2146 if (disable)
2147 temp = USB_OVP_DISABLE_MASK;
2148
2149 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2150 USB_OVP_DISABLE_MASK, temp);
2151}
2152
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002153bool pm8921_is_battery_charging(int *source)
2154{
2155 int fsm_state, is_charging, dc_present, usb_present;
2156
2157 if (!the_chip) {
2158 pr_err("called before init\n");
2159 return -EINVAL;
2160 }
2161 fsm_state = pm_chg_get_fsm_state(the_chip);
2162 is_charging = is_battery_charging(fsm_state);
2163 if (is_charging == 0) {
2164 *source = PM8921_CHG_SRC_NONE;
2165 return is_charging;
2166 }
2167
2168 if (source == NULL)
2169 return is_charging;
2170
2171 /* the battery is charging, the source is requested, find it */
2172 dc_present = is_dc_chg_plugged_in(the_chip);
2173 usb_present = is_usb_chg_plugged_in(the_chip);
2174
2175 if (dc_present && !usb_present)
2176 *source = PM8921_CHG_SRC_DC;
2177
2178 if (usb_present && !dc_present)
2179 *source = PM8921_CHG_SRC_USB;
2180
2181 if (usb_present && dc_present)
2182 /*
2183 * The system always chooses dc for charging since it has
2184 * higher priority.
2185 */
2186 *source = PM8921_CHG_SRC_DC;
2187
2188 return is_charging;
2189}
2190EXPORT_SYMBOL(pm8921_is_battery_charging);
2191
David Keitel86034022012-04-18 12:33:58 -07002192int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2193{
2194 if (!the_chip) {
2195 pr_err("called before init\n");
2196 return -EINVAL;
2197 }
2198
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002199 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002200 return -EINVAL;
2201
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05302202 the_chip->usb_type = type;
David Keitel86034022012-04-18 12:33:58 -07002203 power_supply_changed(&the_chip->usb_psy);
2204 power_supply_changed(&the_chip->dc_psy);
2205 return 0;
2206}
2207EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2208
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002209int pm8921_batt_temperature(void)
2210{
2211 if (!the_chip) {
2212 pr_err("called before init\n");
2213 return -EINVAL;
2214 }
2215 return get_prop_batt_temp(the_chip);
2216}
2217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2219{
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08002220 int usb_present;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002222 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223 usb_present = is_usb_chg_plugged_in(chip);
2224 if (chip->usb_present ^ usb_present) {
2225 notify_usb_of_the_plugin_event(usb_present);
2226 chip->usb_present = usb_present;
2227 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002228 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002229 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002231 if (usb_present) {
2232 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002233 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002234 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2235 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002236 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002237 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002238 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002239 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002240 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241}
2242
Amir Samuelovd31ef502011-10-26 14:41:36 +02002243static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2244{
David Keitel88e1b572012-01-11 11:57:14 -08002245 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002246 pr_debug("external charger not registered.\n");
2247 return;
2248 }
2249
2250 if (!chip->ext_charging) {
2251 pr_debug("already not charging.\n");
2252 return;
2253 }
2254
David Keitel88e1b572012-01-11 11:57:14 -08002255 power_supply_set_charge_type(chip->ext_psy,
2256 POWER_SUPPLY_CHARGE_TYPE_NONE);
2257 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002258 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002259 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002260 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002261 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002262 /* Update battery charging LEDs and user space battery info */
2263 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002264}
2265
2266static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2267{
2268 int dc_present;
2269 int batt_present;
2270 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002271 unsigned long delay =
2272 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2273
David Keitel88e1b572012-01-11 11:57:14 -08002274 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002275 pr_debug("external charger not registered.\n");
2276 return;
2277 }
2278
2279 if (chip->ext_charging) {
2280 pr_debug("already charging.\n");
2281 return;
2282 }
2283
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002284 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002285 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2286 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002287
2288 if (!dc_present) {
2289 pr_warn("%s. dc not present.\n", __func__);
2290 return;
2291 }
2292 if (!batt_present) {
2293 pr_warn("%s. battery not present.\n", __func__);
2294 return;
2295 }
2296 if (!batt_temp_ok) {
2297 pr_warn("%s. battery temperature not ok.\n", __func__);
2298 return;
2299 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002300
2301 /* Force BATFET=ON */
2302 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002303
David Keitel6ccbf132012-05-30 14:21:24 -07002304 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002305 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002306
David Keitel63f71662012-02-08 20:30:00 -08002307 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002308 power_supply_set_charge_type(chip->ext_psy,
2309 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002310 chip->ext_charging = true;
2311 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002312 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002313 /*
2314 * since we wont get a fastchg irq from external charger
2315 * use eoc worker to detect end of charging
2316 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002317 schedule_delayed_work(&chip->eoc_work, delay);
2318 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002319 if (chip->btc_override)
2320 schedule_delayed_work(&chip->btc_override_work,
2321 round_jiffies_relative(msecs_to_jiffies
2322 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002323 /* Update battery charging LEDs and user space battery info */
2324 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002325}
2326
David Keitel6ccbf132012-05-30 14:21:24 -07002327static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002328{
2329 u8 temp;
2330 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002331
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002332 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002333 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002334 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002335 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002336 }
David Keitel6ccbf132012-05-30 14:21:24 -07002337 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002338 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002339 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002340 return;
2341 }
2342 /* set ovp fet disable bit and the write bit */
2343 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002344 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002345 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002346 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002347 return;
2348 }
2349}
2350
David Keitel6ccbf132012-05-30 14:21:24 -07002351static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002352{
2353 u8 temp;
2354 int rc;
2355
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002356 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002357 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002358 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002359 return;
2360 }
David Keitel6ccbf132012-05-30 14:21:24 -07002361 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002362 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002363 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002364 return;
2365 }
2366 /* unset ovp fet disable bit and set the write bit */
2367 temp &= 0xFE;
2368 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002369 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002370 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002371 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002372 temp, rc);
2373 return;
2374 }
2375}
2376
2377static int param_open_ovp_counter = 10;
2378module_param(param_open_ovp_counter, int, 0644);
2379
David Keitel6ccbf132012-05-30 14:21:24 -07002380#define USB_ACTIVE_BIT BIT(5)
2381#define DC_ACTIVE_BIT BIT(6)
2382static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2383 u8 active_chg_mask)
2384{
2385 if (active_chg_mask & USB_ACTIVE_BIT)
2386 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2387 else if (active_chg_mask & DC_ACTIVE_BIT)
2388 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2389 else
2390 return 0;
2391}
2392
David Keitel8c5201a2012-02-24 16:08:54 -08002393#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002394#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002395static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002396{
David Keitel6ccbf132012-05-30 14:21:24 -07002397 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002398 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002399 u8 active_mask = 0;
2400 u16 ovpreg, ovptestreg;
2401
2402 if (is_usb_chg_plugged_in(chip) &&
2403 (chip->active_path & USB_ACTIVE_BIT)) {
2404 ovpreg = USB_OVP_CONTROL;
2405 ovptestreg = USB_OVP_TEST;
2406 active_mask = USB_ACTIVE_BIT;
2407 } else if (is_dc_chg_plugged_in(chip) &&
2408 (chip->active_path & DC_ACTIVE_BIT)) {
2409 ovpreg = DC_OVP_CONTROL;
2410 ovptestreg = DC_OVP_TEST;
2411 active_mask = DC_ACTIVE_BIT;
2412 } else {
2413 return;
2414 }
David Keitel8c5201a2012-02-24 16:08:54 -08002415
2416 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002417 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002418 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002419 active_chg_plugged_in
2420 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002421 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002422 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2423 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002424
2425 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002426 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002427 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002428 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002429
2430 msleep(20);
2431
David Keitel6ccbf132012-05-30 14:21:24 -07002432 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002433 } else {
David Keitel712782e2012-03-29 14:11:47 -07002434 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002435 }
2436 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002437 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2438 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2439 else
2440 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2441
David Keitel6ccbf132012-05-30 14:21:24 -07002442 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2443 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002444 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002445}
David Keitelacf57c82012-03-07 18:48:50 -08002446
2447static int find_usb_ma_value(int value)
2448{
2449 int i;
2450
2451 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2452 if (value >= usb_ma_table[i].usb_ma)
2453 break;
2454 }
2455
2456 return i;
2457}
2458
2459static void decrease_usb_ma_value(int *value)
2460{
2461 int i;
2462
2463 if (value) {
2464 i = find_usb_ma_value(*value);
2465 if (i > 0)
2466 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002467 while (!the_chip->iusb_fine_res && i > 0
2468 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2469 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002470
2471 if (i < 0) {
2472 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2473 *value);
2474 i = 0;
2475 }
2476
David Keitelacf57c82012-03-07 18:48:50 -08002477 *value = usb_ma_table[i].usb_ma;
2478 }
2479}
2480
2481static void increase_usb_ma_value(int *value)
2482{
2483 int i;
2484
2485 if (value) {
2486 i = find_usb_ma_value(*value);
2487
2488 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2489 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002490 /* Get next correct entry if IUSB_FINE_RES is not available */
2491 while (!the_chip->iusb_fine_res
2492 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2493 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2494 i++;
2495
David Keitelacf57c82012-03-07 18:48:50 -08002496 *value = usb_ma_table[i].usb_ma;
2497 }
2498}
2499
2500static void vin_collapse_check_worker(struct work_struct *work)
2501{
2502 struct delayed_work *dwork = to_delayed_work(work);
2503 struct pm8921_chg_chip *chip = container_of(dwork,
2504 struct pm8921_chg_chip, vin_collapse_check_work);
2505
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002506 /*
2507 * AICL only for wall-chargers. If the charger appears to be plugged
2508 * back in now, the corresponding unplug must have been because of we
2509 * were trying to draw more current than the charger can support. In
2510 * such a case reset usb current to 500mA and decrease the target.
2511 * The AICL algorithm will step up the current from 500mA to target
2512 */
2513 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002514 && usb_target_ma > USB_WALL_THRESHOLD_MA
2515 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002516 /* decrease usb_target_ma */
2517 decrease_usb_ma_value(&usb_target_ma);
2518 /* reset here, increase in unplug_check_worker */
2519 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2520 pr_debug("usb_now=%d, usb_target = %d\n",
2521 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002522 if (!delayed_work_pending(&chip->unplug_check_work))
2523 schedule_delayed_work(&chip->unplug_check_work,
2524 msecs_to_jiffies
2525 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002526 } else {
2527 handle_usb_insertion_removal(chip);
2528 }
2529}
2530
2531#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2533{
David Keitelacf57c82012-03-07 18:48:50 -08002534 if (usb_target_ma)
2535 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2536 round_jiffies_relative(msecs_to_jiffies
2537 (VIN_MIN_COLLAPSE_CHECK_MS)));
2538 else
2539 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540 return IRQ_HANDLED;
2541}
2542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2544{
2545 struct pm8921_chg_chip *chip = data;
2546 int status;
2547
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002548 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2549 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002550 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551 pr_debug("battery present=%d", status);
2552 power_supply_changed(&chip->batt_psy);
2553 return IRQ_HANDLED;
2554}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002555
2556/*
2557 * this interrupt used to restart charging a battery.
2558 *
2559 * Note: When DC-inserted the VBAT can't go low.
2560 * VPH_PWR is provided by the ext-charger.
2561 * After End-Of-Charging from DC, charging can be resumed only
2562 * if DC is removed and then inserted after the battery was in use.
2563 * Therefore the handle_start_ext_chg() is not called.
2564 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002565static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2566{
2567 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002568 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002570 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002571
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002572 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002573 /* enable auto charging */
2574 pm_chg_auto_enable(chip, !charging_disabled);
2575 pr_info("batt fell below resume voltage %s\n",
2576 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002577 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002579
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580 power_supply_changed(&chip->batt_psy);
2581 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002582 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 return IRQ_HANDLED;
2585}
2586
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2588{
2589 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2590 return IRQ_HANDLED;
2591}
2592
2593static irqreturn_t vcp_irq_handler(int irq, void *data)
2594{
David Keitel8c5201a2012-02-24 16:08:54 -08002595 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 return IRQ_HANDLED;
2597}
2598
2599static irqreturn_t atcdone_irq_handler(int irq, void *data)
2600{
2601 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2602 return IRQ_HANDLED;
2603}
2604
2605static irqreturn_t atcfail_irq_handler(int irq, void *data)
2606{
2607 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2608 return IRQ_HANDLED;
2609}
2610
2611static irqreturn_t chgdone_irq_handler(int irq, void *data)
2612{
2613 struct pm8921_chg_chip *chip = data;
2614
2615 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002616
2617 handle_stop_ext_chg(chip);
2618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002619 power_supply_changed(&chip->batt_psy);
2620 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002621 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002622
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002623 bms_notify_check(chip);
2624
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002625 return IRQ_HANDLED;
2626}
2627
2628static irqreturn_t chgfail_irq_handler(int irq, void *data)
2629{
2630 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002631 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002633 if (!chip->stop_chg_upon_expiry) {
2634 ret = pm_chg_failed_clear(chip, 1);
2635 if (ret)
2636 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2637 }
David Keitel753ec8d2011-11-02 10:56:37 -07002638
2639 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2640 get_prop_batt_present(chip),
2641 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2642 pm_chg_get_fsm_state(data));
2643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 power_supply_changed(&chip->batt_psy);
2645 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002646 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002647 return IRQ_HANDLED;
2648}
2649
2650static irqreturn_t chgstate_irq_handler(int irq, void *data)
2651{
2652 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002653
2654 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2655 power_supply_changed(&chip->batt_psy);
2656 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002657 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002658
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002659 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 return IRQ_HANDLED;
2662}
2663
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002664enum {
2665 PON_TIME_25NS = 0x04,
2666 PON_TIME_50NS = 0x08,
2667 PON_TIME_100NS = 0x0C,
2668};
David Keitel8c5201a2012-02-24 16:08:54 -08002669
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002670static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002671{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002672 u8 temp;
2673 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002674
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002675 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2676 if (rc) {
2677 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2678 return;
2679 }
2680 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2681 if (rc) {
2682 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2683 return;
2684 }
2685 /* clear the min pon time select bit */
2686 temp &= 0xF3;
2687 /* set the pon time */
2688 temp |= (u8)pon_time_ns;
2689 /* write enable bank 4 */
2690 temp |= 0x80;
2691 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2692 if (rc) {
2693 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2694 return;
2695 }
2696}
David Keitel8c5201a2012-02-24 16:08:54 -08002697
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002698static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2699{
2700 pr_debug("Start\n");
2701 set_min_pon_time(chip, PON_TIME_100NS);
2702 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2703 msleep(250);
2704 pm_chg_vinmin_set(chip, chip->vin_min);
2705 set_min_pon_time(chip, PON_TIME_25NS);
2706 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002707}
2708
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002709#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002710#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2711#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002712static void unplug_check_worker(struct work_struct *work)
2713{
2714 struct delayed_work *dwork = to_delayed_work(work);
2715 struct pm8921_chg_chip *chip = container_of(dwork,
2716 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002717 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002718 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002719 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002720 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002721
2722 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2723 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002724 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2725 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002726 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002727
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002728 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002729 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002730 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2731 active_path, active_chg_plugged_in);
2732 if (active_path & USB_ACTIVE_BIT) {
2733 pr_debug("USB charger active\n");
2734
2735 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002736
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002737 if (usb_ma <= 100) {
2738 pr_debug(
2739 "Unenumerated or suspended usb_ma = %d skip\n",
2740 usb_ma);
2741 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002742 }
2743 } else if (active_path & DC_ACTIVE_BIT) {
2744 pr_debug("DC charger active\n");
2745 } else {
2746 /* No charger active */
2747 if (!(is_usb_chg_plugged_in(chip)
2748 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002749 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002750 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2751 pm_chg_get_regulation_loop(chip),
2752 pm_chg_get_fsm_state(chip),
2753 get_prop_batt_current(chip)
2754 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002755 return;
2756 } else {
2757 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002758 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002759 }
David Keitel8c5201a2012-02-24 16:08:54 -08002760
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002761 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002762 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
2763 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07002764 reg_loop = pm_chg_get_regulation_loop(chip);
2765 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2766 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002767 (usb_ma > USB_WALL_THRESHOLD_MA)
2768 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002769 decrease_usb_ma_value(&usb_ma);
2770 usb_target_ma = usb_ma;
2771 /* end AICL here */
2772 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002773 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002774 usb_ma, usb_target_ma);
2775 }
David Keitelacf57c82012-03-07 18:48:50 -08002776 }
2777
2778 reg_loop = pm_chg_get_regulation_loop(chip);
2779 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2780
David Keitel6ccbf132012-05-30 14:21:24 -07002781 ibat = get_prop_batt_current(chip);
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302782 if ((reg_loop & VIN_ACTIVE_BIT) && !chip->disable_chg_rmvl_wrkarnd) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002783 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002784 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2785 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2786 attempt_reverse_boost_fix(chip);
2787 /* after reverse boost fix check if the active
2788 * charger was detected as removed */
2789 active_chg_plugged_in
2790 = is_active_chg_plugged_in(chip,
2791 active_path);
2792 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2793 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002794 }
2795 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002796
2797 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002798 pr_debug("active_path = 0x%x, active_chg = %d\n",
2799 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002800 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2801
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05302802 if (chg_gone == 1 && active_chg_plugged_in == 1 &&
2803 !chip->disable_chg_rmvl_wrkarnd) {
David Keitel6ccbf132012-05-30 14:21:24 -07002804 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2805 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002806 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002807 }
2808
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002809 /* AICL only for usb wall charger */
2810 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2811 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002812 && !charging_disabled
2813 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002814 /* only increase iusb_max if vin loop not active */
2815 if (usb_ma < usb_target_ma) {
2816 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302817 if (usb_ma > usb_target_ma)
2818 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002819 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002820 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002821 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002822 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002823 } else {
2824 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002825 }
2826 }
Devin Kim2073afb2012-09-05 13:01:51 -07002827check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002828 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002829 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002830 if (ramp)
2831 schedule_delayed_work(&chip->unplug_check_work,
2832 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2833 else
2834 schedule_delayed_work(&chip->unplug_check_work,
2835 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002836}
2837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002838static irqreturn_t loop_change_irq_handler(int irq, void *data)
2839{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002840 struct pm8921_chg_chip *chip = data;
2841
2842 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2843 pm_chg_get_fsm_state(data),
2844 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002845 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 return IRQ_HANDLED;
2847}
2848
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002849struct ibatmax_max_adj_entry {
2850 int ibat_max_ma;
2851 int max_adj_ma;
2852};
2853
2854static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2855 {975, 300},
2856 {1475, 150},
2857 {1975, 200},
2858 {2475, 250},
2859};
2860
2861static int find_ibat_max_adj_ma(int ibat_target_ma)
2862{
2863 int i = 0;
2864
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002865 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2866 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002867 break;
2868 }
2869
2870 return ibatmax_adj_table[i].max_adj_ma;
2871}
2872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873static irqreturn_t fastchg_irq_handler(int irq, void *data)
2874{
2875 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002876 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002878 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2879 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2880 wake_lock(&chip->eoc_wake_lock);
2881 schedule_delayed_work(&chip->eoc_work,
2882 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002883 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002884 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002885 if (high_transition
2886 && chip->btc_override
2887 && !delayed_work_pending(&chip->btc_override_work)) {
2888 schedule_delayed_work(&chip->btc_override_work,
2889 round_jiffies_relative(msecs_to_jiffies
2890 (chip->btc_delay_ms)));
2891 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002892 power_supply_changed(&chip->batt_psy);
2893 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894 return IRQ_HANDLED;
2895}
2896
2897static irqreturn_t trklchg_irq_handler(int irq, void *data)
2898{
2899 struct pm8921_chg_chip *chip = data;
2900
2901 power_supply_changed(&chip->batt_psy);
2902 return IRQ_HANDLED;
2903}
2904
2905static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2906{
2907 struct pm8921_chg_chip *chip = data;
2908 int status;
2909
2910 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2911 pr_debug("battery present=%d state=%d", !status,
2912 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002913 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002914 power_supply_changed(&chip->batt_psy);
2915 return IRQ_HANDLED;
2916}
2917
2918static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2919{
2920 struct pm8921_chg_chip *chip = data;
2921
Amir Samuelovd31ef502011-10-26 14:41:36 +02002922 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 power_supply_changed(&chip->batt_psy);
2924 return IRQ_HANDLED;
2925}
2926
2927static irqreturn_t chghot_irq_handler(int irq, void *data)
2928{
2929 struct pm8921_chg_chip *chip = data;
2930
2931 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2932 power_supply_changed(&chip->batt_psy);
2933 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002934 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 return IRQ_HANDLED;
2936}
2937
2938static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2939{
2940 struct pm8921_chg_chip *chip = data;
2941
2942 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002943 handle_stop_ext_chg(chip);
2944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 power_supply_changed(&chip->batt_psy);
2946 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947 return IRQ_HANDLED;
2948}
2949
2950static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2951{
2952 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002953 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002954
2955 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2956 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2957
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002958 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2959 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07002960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 power_supply_changed(&chip->batt_psy);
2962 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002963 return IRQ_HANDLED;
2964}
David Keitel52fda532011-11-10 10:43:44 -08002965/*
2966 *
2967 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2968 * fire for two cases:
2969 *
2970 * If the interrupt line switches to high temperature is okay
2971 * and thus charging begins.
2972 * If bat_temp_ok is low this means the temperature is now
2973 * too hot or cold, so charging is stopped.
2974 *
2975 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2977{
David Keitel52fda532011-11-10 10:43:44 -08002978 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002979 struct pm8921_chg_chip *chip = data;
2980
David Keitel52fda532011-11-10 10:43:44 -08002981 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2982
2983 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2984 bat_temp_ok, pm_chg_get_fsm_state(data));
2985
2986 if (bat_temp_ok)
2987 handle_start_ext_chg(chip);
2988 else
2989 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002991 power_supply_changed(&chip->batt_psy);
2992 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002993 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994 return IRQ_HANDLED;
2995}
2996
2997static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2998{
2999 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3000 return IRQ_HANDLED;
3001}
3002
3003static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3004{
3005 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3006 return IRQ_HANDLED;
3007}
3008
3009static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3010{
3011 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3012 return IRQ_HANDLED;
3013}
3014
3015static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3016{
3017 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3018 return IRQ_HANDLED;
3019}
3020
3021static irqreturn_t batfet_irq_handler(int irq, void *data)
3022{
3023 struct pm8921_chg_chip *chip = data;
3024
3025 pr_debug("vreg ov\n");
3026 power_supply_changed(&chip->batt_psy);
3027 return IRQ_HANDLED;
3028}
3029
3030static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3031{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003032 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003033 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003034
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003035 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003036 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003037
3038 if (chip->dc_present ^ dc_present)
3039 pm8921_bms_calibrate_hkadc();
3040
David Keitel88e1b572012-01-11 11:57:14 -08003041 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003042 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003043 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003044 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3045
3046 chip->dc_present = dc_present;
3047
3048 if (chip->ext_psy) {
3049 if (dc_present)
3050 handle_start_ext_chg(chip);
3051 else
3052 handle_stop_ext_chg(chip);
3053 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003054 if (dc_present)
3055 schedule_delayed_work(&chip->unplug_check_work,
3056 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3057 power_supply_changed(&chip->dc_psy);
3058 }
3059
3060 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 return IRQ_HANDLED;
3062}
3063
3064static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3065{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003066 struct pm8921_chg_chip *chip = data;
3067
Amir Samuelovd31ef502011-10-26 14:41:36 +02003068 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 return IRQ_HANDLED;
3070}
3071
3072static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3073{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003074 struct pm8921_chg_chip *chip = data;
3075
Amir Samuelovd31ef502011-10-26 14:41:36 +02003076 handle_stop_ext_chg(chip);
3077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003078 return IRQ_HANDLED;
3079}
3080
David Keitel88e1b572012-01-11 11:57:14 -08003081static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3082{
3083 struct power_supply *psy = &the_chip->batt_psy;
3084 struct power_supply *epsy = dev_get_drvdata(dev);
3085 int i, dcin_irq;
3086
3087 /* Only search for external supply if none is registered */
3088 if (!the_chip->ext_psy) {
3089 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3090 for (i = 0; i < epsy->num_supplicants; i++) {
3091 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3092 if (!strncmp(epsy->name, "dc", 2)) {
3093 the_chip->ext_psy = epsy;
3094 dcin_valid_irq_handler(dcin_irq,
3095 the_chip);
3096 }
3097 }
3098 }
3099 }
3100 return 0;
3101}
3102
3103static void pm_batt_external_power_changed(struct power_supply *psy)
3104{
3105 /* Only look for an external supply if it hasn't been registered */
3106 if (!the_chip->ext_psy)
3107 class_for_each_device(power_supply_class, NULL, psy,
3108 __pm_batt_external_power_changed_work);
3109}
3110
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003111/**
3112 * update_heartbeat - internal function to update userspace
3113 * per update_time minutes
3114 *
3115 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003116#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003117static void update_heartbeat(struct work_struct *work)
3118{
3119 struct delayed_work *dwork = to_delayed_work(work);
3120 struct pm8921_chg_chip *chip = container_of(dwork,
3121 struct pm8921_chg_chip, update_heartbeat_work);
3122
3123 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003124 if (chip->recent_reported_soc <= 20)
3125 schedule_delayed_work(&chip->update_heartbeat_work,
3126 round_jiffies_relative(msecs_to_jiffies
3127 (LOW_SOC_HEARTBEAT_MS)));
3128 else
3129 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003130 round_jiffies_relative(msecs_to_jiffies
3131 (chip->update_time)));
3132}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003133#define VDD_LOOP_ACTIVE_BIT BIT(3)
3134#define VDD_MAX_INCREASE_MV 400
3135static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3136module_param(vdd_max_increase_mv, int, 0644);
3137
3138static int ichg_threshold_ua = -400000;
3139module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003140
3141#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003142static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3143 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003144{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003145 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003146 int vbat_batt_terminal_mv;
3147 int reg_loop;
3148 int delta_mv = 0;
3149
3150 if (chip->rconn_mohm == 0) {
3151 pr_debug("Exiting as rconn_mohm is 0\n");
3152 return;
3153 }
3154 /* adjust vdd_max only in normal temperature zone */
3155 if (chip->is_bat_cool || chip->is_bat_warm) {
3156 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3157 chip->is_bat_cool, chip->is_bat_warm);
3158 return;
3159 }
3160
3161 reg_loop = pm_chg_get_regulation_loop(chip);
3162 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3163 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3164 reg_loop);
3165 return;
3166 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003167 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3168 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3169
3170 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3171
3172 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3173 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3174 delta_mv,
3175 programmed_vdd_max,
3176 adj_vdd_max_mv);
3177
3178 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3179 pr_debug("adj vdd_max lower than default max voltage\n");
3180 return;
3181 }
3182
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003183 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3184 * PM8921_CHG_VDDMAX_RES_MV;
3185
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003186 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3187 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003188 pr_debug("adjusting vdd_max_mv to %d to make "
3189 "vbat_batt_termial_uv = %d to %d\n",
3190 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3191 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3192}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003193
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003194static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3195{
3196 if (chip->is_bat_cool)
3197 pm_chg_vbatdet_set(the_chip,
3198 the_chip->cool_bat_voltage
3199 - the_chip->resume_voltage_delta);
3200 else if (chip->is_bat_warm)
3201 pm_chg_vbatdet_set(the_chip,
3202 the_chip->warm_bat_voltage
3203 - the_chip->resume_voltage_delta);
3204 else
3205 pm_chg_vbatdet_set(the_chip,
3206 the_chip->max_voltage_mv
3207 - the_chip->resume_voltage_delta);
3208}
3209
3210static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3211{
3212 unsigned int chg_current = chip->max_bat_chg_current;
3213
3214 if (chip->is_bat_cool)
3215 chg_current = min(chg_current, chip->cool_bat_chg_current);
3216
3217 if (chip->is_bat_warm)
3218 chg_current = min(chg_current, chip->warm_bat_chg_current);
3219
3220 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3221 chg_current = min(chg_current,
3222 chip->thermal_mitigation[thermal_mitigation]);
3223
3224 pm_chg_ibatmax_set(the_chip, chg_current);
3225}
3226
3227#define TEMP_HYSTERISIS_DECIDEGC 20
3228static void battery_cool(bool enter)
3229{
3230 pr_debug("enter = %d\n", enter);
3231 if (enter == the_chip->is_bat_cool)
3232 return;
3233 the_chip->is_bat_cool = enter;
3234 if (enter)
3235 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3236 else
3237 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3238 set_appropriate_battery_current(the_chip);
3239 set_appropriate_vbatdet(the_chip);
3240}
3241
3242static void battery_warm(bool enter)
3243{
3244 pr_debug("enter = %d\n", enter);
3245 if (enter == the_chip->is_bat_warm)
3246 return;
3247 the_chip->is_bat_warm = enter;
3248 if (enter)
3249 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3250 else
3251 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3252
3253 set_appropriate_battery_current(the_chip);
3254 set_appropriate_vbatdet(the_chip);
3255}
3256
3257static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3258{
3259 int temp = 0;
3260
3261 temp = get_prop_batt_temp(chip);
3262 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3263 temp, chip->warm_temp_dc,
3264 chip->cool_temp_dc);
3265
3266 if (chip->warm_temp_dc != INT_MIN) {
3267 if (chip->is_bat_warm
3268 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3269 battery_warm(false);
3270 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3271 battery_warm(true);
3272 }
3273
3274 if (chip->cool_temp_dc != INT_MIN) {
3275 if (chip->is_bat_cool
3276 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3277 battery_cool(false);
3278 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3279 battery_cool(true);
3280 }
3281}
3282
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003283enum {
3284 CHG_IN_PROGRESS,
3285 CHG_NOT_IN_PROGRESS,
3286 CHG_FINISHED,
3287};
3288
3289#define VBAT_TOLERANCE_MV 70
3290#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003291static int is_charging_finished(struct pm8921_chg_chip *chip,
3292 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003293{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003294 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003295 int regulation_loop, fast_chg, vcp;
3296 int rc;
3297 static int last_vbat_programmed = -EINVAL;
3298
3299 if (!is_ext_charging(chip)) {
3300 /* return if the battery is not being fastcharged */
3301 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3302 pr_debug("fast_chg = %d\n", fast_chg);
3303 if (fast_chg == 0)
3304 return CHG_NOT_IN_PROGRESS;
3305
3306 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3307 pr_debug("vcp = %d\n", vcp);
3308 if (vcp == 1)
3309 return CHG_IN_PROGRESS;
3310
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003311 /* reset count if battery is hot/cold */
3312 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3313 pr_debug("batt_temp_ok = %d\n", rc);
3314 if (rc == 0)
3315 return CHG_IN_PROGRESS;
3316
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003317 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3318 if (rc) {
3319 pr_err("couldnt read vddmax rc = %d\n", rc);
3320 return CHG_IN_PROGRESS;
3321 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003322 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3323 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003324
3325 if (last_vbat_programmed == -EINVAL)
3326 last_vbat_programmed = vbat_programmed;
3327 if (last_vbat_programmed != vbat_programmed) {
3328 /* vddmax changed, reset and check again */
3329 pr_debug("vddmax = %d last_vdd_max=%d\n",
3330 vbat_programmed, last_vbat_programmed);
3331 last_vbat_programmed = vbat_programmed;
3332 return CHG_IN_PROGRESS;
3333 }
3334
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003335 if (chip->is_bat_cool)
3336 vbat_intended = chip->cool_bat_voltage;
3337 else if (chip->is_bat_warm)
3338 vbat_intended = chip->warm_bat_voltage;
3339 else
3340 vbat_intended = chip->max_voltage_mv;
3341
3342 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3343 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3344 vbat_batt_terminal_uv,
3345 vbat_intended);
3346 return CHG_IN_PROGRESS;
3347 }
3348
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003349 regulation_loop = pm_chg_get_regulation_loop(chip);
3350 if (regulation_loop < 0) {
3351 pr_err("couldnt read the regulation loop err=%d\n",
3352 regulation_loop);
3353 return CHG_IN_PROGRESS;
3354 }
3355 pr_debug("regulation_loop=%d\n", regulation_loop);
3356
3357 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3358 return CHG_IN_PROGRESS;
3359 } /* !is_ext_charging */
3360
3361 /* reset count if battery chg current is more than iterm */
3362 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3363 if (rc) {
3364 pr_err("couldnt read iterm rc = %d\n", rc);
3365 return CHG_IN_PROGRESS;
3366 }
3367
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003368 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3369 iterm_programmed, ichg_meas_ma);
3370 /*
3371 * ichg_meas_ma < 0 means battery is drawing current
3372 * ichg_meas_ma > 0 means battery is providing current
3373 */
3374 if (ichg_meas_ma > 0)
3375 return CHG_IN_PROGRESS;
3376
3377 if (ichg_meas_ma * -1 > iterm_programmed)
3378 return CHG_IN_PROGRESS;
3379
3380 return CHG_FINISHED;
3381}
3382
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003383#define COMP_OVERRIDE_HOT_BANK 6
3384#define COMP_OVERRIDE_COLD_BANK 7
3385#define COMP_OVERRIDE_BIT BIT(1)
3386static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3387{
3388 u8 val;
3389 int rc = 0;
3390
3391 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3392
3393 if (flag)
3394 val |= 0x01;
3395
3396 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3397 if (rc < 0)
3398 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3399
3400 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3401 return rc;
3402}
3403
3404static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3405{
3406 u8 val;
3407 int rc = 0;
3408
3409 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3410
3411 if (flag)
3412 val |= 0x01;
3413
3414 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3415 if (rc < 0)
3416 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3417
3418 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3419 return rc;
3420}
3421
3422static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3423{
3424 int rc = 0;
3425 u8 reg;
3426 u8 val;
3427
3428 val = COMP_OVERRIDE_HOT_BANK << 2;
3429 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3430 if (rc < 0) {
3431 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3432 goto cold_init;
3433 }
3434 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3435 if (rc < 0) {
3436 pr_err("Could not read bank %d of override rc = %d\n",
3437 COMP_OVERRIDE_HOT_BANK, rc);
3438 goto cold_init;
3439 }
3440 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3441 /* for now override it as not hot */
3442 rc = pm_chg_override_hot(chip, 0);
3443 if (rc < 0)
3444 pr_err("Could not override hot rc = %d\n", rc);
3445 }
3446
3447cold_init:
3448 val = COMP_OVERRIDE_COLD_BANK << 2;
3449 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3450 if (rc < 0) {
3451 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3452 return;
3453 }
3454 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3455 if (rc < 0) {
3456 pr_err("Could not read bank %d of override rc = %d\n",
3457 COMP_OVERRIDE_COLD_BANK, rc);
3458 return;
3459 }
3460 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3461 /* for now override it as not cold */
3462 rc = pm_chg_override_cold(chip, 0);
3463 if (rc < 0)
3464 pr_err("Could not override cold rc = %d\n", rc);
3465 }
3466}
3467
3468static void btc_override_worker(struct work_struct *work)
3469{
3470 int decidegc;
3471 int temp;
3472 int rc = 0;
3473 struct delayed_work *dwork = to_delayed_work(work);
3474 struct pm8921_chg_chip *chip = container_of(dwork,
3475 struct pm8921_chg_chip, btc_override_work);
3476
3477 if (!chip->btc_override) {
3478 pr_err("called when not enabled\n");
3479 return;
3480 }
3481
3482 decidegc = get_prop_batt_temp(chip);
3483
3484 pr_debug("temp=%d\n", decidegc);
3485
3486 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3487 if (temp) {
3488 if (decidegc < chip->btc_override_hot_decidegc)
3489 /* stop forcing batt hot */
3490 rc = pm_chg_override_hot(chip, 0);
3491 if (rc)
3492 pr_err("Couldnt write 0 to hot comp\n");
3493 } else {
3494 if (decidegc >= chip->btc_override_hot_decidegc)
3495 /* start forcing batt hot */
3496 rc = pm_chg_override_hot(chip, 1);
3497 if (rc && chip->btc_panic_if_cant_stop_chg)
3498 panic("Couldnt override comps to stop chg\n");
3499 }
3500
3501 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3502 if (temp) {
3503 if (decidegc > chip->btc_override_cold_decidegc)
3504 /* stop forcing batt cold */
3505 rc = pm_chg_override_cold(chip, 0);
3506 if (rc)
3507 pr_err("Couldnt write 0 to cold comp\n");
3508 } else {
3509 if (decidegc <= chip->btc_override_cold_decidegc)
3510 /* start forcing batt cold */
3511 rc = pm_chg_override_cold(chip, 1);
3512 if (rc && chip->btc_panic_if_cant_stop_chg)
3513 panic("Couldnt override comps to stop chg\n");
3514 }
3515
3516 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3517 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3518 schedule_delayed_work(&chip->btc_override_work,
3519 round_jiffies_relative(msecs_to_jiffies
3520 (chip->btc_delay_ms)));
3521 return;
3522 }
3523
3524 rc = pm_chg_override_hot(chip, 0);
3525 if (rc)
3526 pr_err("Couldnt write 0 to hot comp\n");
3527 rc = pm_chg_override_cold(chip, 0);
3528 if (rc)
3529 pr_err("Couldnt write 0 to cold comp\n");
3530}
3531
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003532/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003533 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003534 * has happened
3535 *
3536 * If all conditions favouring, if the charge current is
3537 * less than the term current for three consecutive times
3538 * an EOC has happened.
3539 * The wakelock is released if there is no need to reshedule
3540 * - this happens when the battery is removed or EOC has
3541 * happened
3542 */
3543#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003544static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003545{
3546 struct delayed_work *dwork = to_delayed_work(work);
3547 struct pm8921_chg_chip *chip = container_of(dwork,
3548 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003549 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003550 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003551 int vbat_meas_uv, vbat_meas_mv;
3552 int ichg_meas_ua, ichg_meas_ma;
3553 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003554
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003555 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3556 &ichg_meas_ua, &vbat_meas_uv);
3557 vbat_meas_mv = vbat_meas_uv / 1000;
3558 /* rconn_mohm is in milliOhms */
3559 ichg_meas_ma = ichg_meas_ua / 1000;
3560 vbat_batt_terminal_uv = vbat_meas_uv
3561 + ichg_meas_ma
3562 * the_chip->rconn_mohm;
3563
3564 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003565
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003566 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003567 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003568 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003569 }
3570
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003571 if (end == CHG_FINISHED) {
3572 count++;
3573 } else {
3574 count = 0;
3575 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003576
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003577 if (count == CONSECUTIVE_COUNT) {
3578 count = 0;
3579 pr_info("End of Charging\n");
3580
3581 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003582
Amir Samuelovd31ef502011-10-26 14:41:36 +02003583 if (is_ext_charging(chip))
3584 chip->ext_charge_done = true;
3585
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003586 if (chip->is_bat_warm || chip->is_bat_cool)
3587 chip->bms_notify.is_battery_full = 0;
3588 else
3589 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003590 /* declare end of charging by invoking chgdone interrupt */
3591 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003592 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003593 check_temp_thresholds(chip);
3594 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003595 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003596 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003597 round_jiffies_relative(msecs_to_jiffies
3598 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003599 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003600 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003601
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003602eoc_worker_stop:
3603 wake_unlock(&chip->eoc_wake_lock);
3604 /* set the vbatdet back, in case it was changed to trigger charging */
3605 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003606}
3607
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003608/**
3609 * set_disable_status_param -
3610 *
3611 * Internal function to disable battery charging and also disable drawing
3612 * any current from the source. The device is forced to run on a battery
3613 * after this.
3614 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003615static int set_disable_status_param(const char *val, struct kernel_param *kp)
3616{
3617 int ret;
3618 struct pm8921_chg_chip *chip = the_chip;
3619
3620 ret = param_set_int(val, kp);
3621 if (ret) {
3622 pr_err("error setting value %d\n", ret);
3623 return ret;
3624 }
3625 pr_info("factory set disable param to %d\n", charging_disabled);
3626 if (chip) {
3627 pm_chg_auto_enable(chip, !charging_disabled);
3628 pm_chg_charge_dis(chip, charging_disabled);
3629 }
3630 return 0;
3631}
3632module_param_call(disabled, set_disable_status_param, param_get_uint,
3633 &charging_disabled, 0644);
3634
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003635static int rconn_mohm;
3636static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3637{
3638 int ret;
3639 struct pm8921_chg_chip *chip = the_chip;
3640
3641 ret = param_set_int(val, kp);
3642 if (ret) {
3643 pr_err("error setting value %d\n", ret);
3644 return ret;
3645 }
3646 if (chip)
3647 chip->rconn_mohm = rconn_mohm;
3648 return 0;
3649}
3650module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3651 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003652/**
3653 * set_thermal_mitigation_level -
3654 *
3655 * Internal function to control battery charging current to reduce
3656 * temperature
3657 */
3658static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3659{
3660 int ret;
3661 struct pm8921_chg_chip *chip = the_chip;
3662
3663 ret = param_set_int(val, kp);
3664 if (ret) {
3665 pr_err("error setting value %d\n", ret);
3666 return ret;
3667 }
3668
3669 if (!chip) {
3670 pr_err("called before init\n");
3671 return -EINVAL;
3672 }
3673
3674 if (!chip->thermal_mitigation) {
3675 pr_err("no thermal mitigation\n");
3676 return -EINVAL;
3677 }
3678
3679 if (thermal_mitigation < 0
3680 || thermal_mitigation >= chip->thermal_levels) {
3681 pr_err("out of bound level selected\n");
3682 return -EINVAL;
3683 }
3684
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003685 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003686 return ret;
3687}
3688module_param_call(thermal_mitigation, set_therm_mitigation_level,
3689 param_get_uint,
3690 &thermal_mitigation, 0644);
3691
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003692static int set_usb_max_current(const char *val, struct kernel_param *kp)
3693{
3694 int ret, mA;
3695 struct pm8921_chg_chip *chip = the_chip;
3696
3697 ret = param_set_int(val, kp);
3698 if (ret) {
3699 pr_err("error setting value %d\n", ret);
3700 return ret;
3701 }
3702 if (chip) {
3703 pr_warn("setting current max to %d\n", usb_max_current);
3704 pm_chg_iusbmax_get(chip, &mA);
3705 if (mA > usb_max_current)
3706 pm8921_charger_vbus_draw(usb_max_current);
3707 return 0;
3708 }
3709 return -EINVAL;
3710}
David Keitelacf57c82012-03-07 18:48:50 -08003711module_param_call(usb_max_current, set_usb_max_current,
3712 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003714static void free_irqs(struct pm8921_chg_chip *chip)
3715{
3716 int i;
3717
3718 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3719 if (chip->pmic_chg_irq[i]) {
3720 free_irq(chip->pmic_chg_irq[i], chip);
3721 chip->pmic_chg_irq[i] = 0;
3722 }
3723}
3724
David Keitel88e1b572012-01-11 11:57:14 -08003725/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3727{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003729 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730
3731 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3732 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3733
3734 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003735 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003736 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003737 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003738 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003739 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003740
3741 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3742 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3743 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003744 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003745 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3746 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003747 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003748 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3749 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003750 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003752 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3753 if (usb_chg_current)
3754 /*
3755 * Reissue a vbus draw call only if a battery
3756 * or DC is present. We don't want to brown out the
3757 * device if usb is its only source
3758 */
3759 __pm8921_charger_vbus_draw(usb_chg_current);
3760 usb_chg_current = 0;
3761
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003762 /*
3763 * The bootloader could have started charging, a fastchg interrupt
3764 * might not happen. Check the real time status and if it is fast
3765 * charging invoke the handler so that the eoc worker could be
3766 * started
3767 */
3768 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3769 if (is_fast_chg)
3770 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771
3772 fsm_state = pm_chg_get_fsm_state(chip);
3773 if (is_battery_charging(fsm_state)) {
3774 chip->bms_notify.is_charging = 1;
3775 pm8921_bms_charging_began();
3776 }
3777
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003778 check_battery_valid(chip);
3779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3781 chip->usb_present,
3782 chip->dc_present,
3783 get_prop_batt_present(chip),
3784 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003785
3786 /* Determine which USB trim column to use */
3787 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3788 chip->usb_trim_table = usb_trim_8917_table;
3789 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3790 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791}
3792
3793struct pm_chg_irq_init_data {
3794 unsigned int irq_id;
3795 char *name;
3796 unsigned long flags;
3797 irqreturn_t (*handler)(int, void *);
3798};
3799
3800#define CHG_IRQ(_id, _flags, _handler) \
3801{ \
3802 .irq_id = _id, \
3803 .name = #_id, \
3804 .flags = _flags, \
3805 .handler = _handler, \
3806}
3807struct pm_chg_irq_init_data chg_irq_data[] = {
3808 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3809 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3811 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003812 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3813 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003814 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3815 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3816 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3817 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3818 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3819 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3820 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3821 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003822 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3823 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003824 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3825 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3826 batt_removed_irq_handler),
3827 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3828 batttemp_hot_irq_handler),
3829 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3830 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3831 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003832 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3833 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003834 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3835 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003836 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3837 coarse_det_low_irq_handler),
3838 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3839 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3840 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3841 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3842 batfet_irq_handler),
3843 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3844 dcin_valid_irq_handler),
3845 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3846 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003847 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848};
3849
3850static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3851 struct platform_device *pdev)
3852{
3853 struct resource *res;
3854 int ret, i;
3855
3856 ret = 0;
3857 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3858
3859 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3860 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3861 chg_irq_data[i].name);
3862 if (res == NULL) {
3863 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3864 goto err_out;
3865 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003866 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003867 ret = request_irq(res->start, chg_irq_data[i].handler,
3868 chg_irq_data[i].flags,
3869 chg_irq_data[i].name, chip);
3870 if (ret < 0) {
3871 pr_err("couldn't request %d (%s) %d\n", res->start,
3872 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003873 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003874 goto err_out;
3875 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3877 }
3878 return 0;
3879
3880err_out:
3881 free_irqs(chip);
3882 return -EINVAL;
3883}
3884
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003885static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3886{
3887 int err;
3888 u8 temp;
3889
3890 temp = 0xD1;
3891 err = pm_chg_write(chip, CHG_TEST, temp);
3892 if (err) {
3893 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3894 return;
3895 }
3896
3897 temp = 0xD3;
3898 err = pm_chg_write(chip, CHG_TEST, temp);
3899 if (err) {
3900 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3901 return;
3902 }
3903
3904 temp = 0xD1;
3905 err = pm_chg_write(chip, CHG_TEST, temp);
3906 if (err) {
3907 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3908 return;
3909 }
3910
3911 temp = 0xD5;
3912 err = pm_chg_write(chip, CHG_TEST, temp);
3913 if (err) {
3914 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3915 return;
3916 }
3917
3918 udelay(183);
3919
3920 temp = 0xD1;
3921 err = pm_chg_write(chip, CHG_TEST, temp);
3922 if (err) {
3923 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3924 return;
3925 }
3926
3927 temp = 0xD0;
3928 err = pm_chg_write(chip, CHG_TEST, temp);
3929 if (err) {
3930 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3931 return;
3932 }
3933 udelay(32);
3934
3935 temp = 0xD1;
3936 err = pm_chg_write(chip, CHG_TEST, temp);
3937 if (err) {
3938 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3939 return;
3940 }
3941
3942 temp = 0xD3;
3943 err = pm_chg_write(chip, CHG_TEST, temp);
3944 if (err) {
3945 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3946 return;
3947 }
3948}
3949
3950static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3951{
3952 int err;
3953 u8 temp;
3954
3955 temp = 0xD1;
3956 err = pm_chg_write(chip, CHG_TEST, temp);
3957 if (err) {
3958 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3959 return;
3960 }
3961
3962 temp = 0xD0;
3963 err = pm_chg_write(chip, CHG_TEST, temp);
3964 if (err) {
3965 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3966 return;
3967 }
3968}
3969
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003970#define VREF_BATT_THERM_FORCE_ON BIT(7)
3971static void detect_battery_removal(struct pm8921_chg_chip *chip)
3972{
3973 u8 temp;
3974
3975 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3976 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3977
3978 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3979 /*
3980 * batt therm force on bit is battery backed and is default 0
3981 * The charger sets this bit at init time. If this bit is found
3982 * 0 that means the battery was removed. Tell the bms about it
3983 */
3984 pm8921_bms_invalidate_shutdown_soc();
3985}
3986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987#define ENUM_TIMER_STOP_BIT BIT(1)
3988#define BOOT_DONE_BIT BIT(6)
3989#define CHG_BATFET_ON_BIT BIT(3)
3990#define CHG_VCP_EN BIT(0)
3991#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3992#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003993#define PM_SUB_REV 0x001
3994#define MIN_CHARGE_CURRENT_MA 350
3995#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3997{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003998 u8 subrev;
3999 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004000
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004001 /* forcing 19p2mhz before accessing any charger registers */
4002 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004003
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004004 detect_battery_removal(chip);
4005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004007 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 if (rc) {
4009 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4010 return rc;
4011 }
4012
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004013 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4014
4015 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4016 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4017
4018 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004020 if (rc) {
4021 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004022 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004023 return rc;
4024 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004025 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004026 chip->max_voltage_mv
4027 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 if (rc) {
4029 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004030 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004031 return rc;
4032 }
4033
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004034 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004035 if (rc) {
4036 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004037 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004038 return rc;
4039 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004040
4041 if (chip->safe_current_ma == 0)
4042 chip->safe_current_ma = SAFE_CURRENT_MA;
4043
4044 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004045 if (rc) {
4046 pr_err("Failed to set max voltage to %d rc=%d\n",
4047 SAFE_CURRENT_MA, rc);
4048 return rc;
4049 }
4050
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004051 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052 if (rc) {
4053 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4054 return rc;
4055 }
4056
4057 rc = pm_chg_iterm_set(chip, chip->term_current);
4058 if (rc) {
4059 pr_err("Failed to set term current to %d rc=%d\n",
4060 chip->term_current, rc);
4061 return rc;
4062 }
4063
4064 /* Disable the ENUM TIMER */
4065 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4066 ENUM_TIMER_STOP_BIT);
4067 if (rc) {
4068 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4069 return rc;
4070 }
4071
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004072 fcc_uah = pm8921_bms_get_fcc();
4073 if (fcc_uah > 0) {
4074 safety_time = div_s64((s64)fcc_uah * 60,
4075 1000 * MIN_CHARGE_CURRENT_MA);
4076 /* add 20 minutes of buffer time */
4077 safety_time += 20;
4078
4079 /* make sure we do not exceed the maximum programmable time */
4080 if (safety_time > PM8921_CHG_TCHG_MAX)
4081 safety_time = PM8921_CHG_TCHG_MAX;
4082 }
4083
4084 rc = pm_chg_tchg_max_set(chip, safety_time);
4085 if (rc) {
4086 pr_err("Failed to set max time to %d minutes rc=%d\n",
4087 safety_time, rc);
4088 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004089 }
4090
4091 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004092 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004093 if (rc) {
4094 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004095 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004096 return rc;
4097 }
4098 }
4099
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004100 if (chip->vin_min != 0) {
4101 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4102 if (rc) {
4103 pr_err("Failed to set vin min to %d mV rc=%d\n",
4104 chip->vin_min, rc);
4105 return rc;
4106 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004107 } else {
4108 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004109 }
4110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 rc = pm_chg_disable_wd(chip);
4112 if (rc) {
4113 pr_err("Failed to disable wd rc=%d\n", rc);
4114 return rc;
4115 }
4116
4117 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4118 CHG_BAT_TEMP_DIS_BIT, 0);
4119 if (rc) {
4120 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4121 return rc;
4122 }
4123 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004124 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4125 rc = pm_chg_write(chip,
4126 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4127 else
4128 rc = pm_chg_write(chip,
4129 CHG_BUCK_CLOCK_CTRL, 0x15);
4130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 if (rc) {
4132 pr_err("Failed to switch buck clk rc=%d\n", rc);
4133 return rc;
4134 }
4135
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004136 if (chip->trkl_voltage != 0) {
4137 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4138 if (rc) {
4139 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4140 chip->trkl_voltage, rc);
4141 return rc;
4142 }
4143 }
4144
4145 if (chip->weak_voltage != 0) {
4146 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4147 if (rc) {
4148 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4149 chip->weak_voltage, rc);
4150 return rc;
4151 }
4152 }
4153
4154 if (chip->trkl_current != 0) {
4155 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4156 if (rc) {
4157 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4158 chip->trkl_voltage, rc);
4159 return rc;
4160 }
4161 }
4162
4163 if (chip->weak_current != 0) {
4164 rc = pm_chg_iweak_set(chip, chip->weak_current);
4165 if (rc) {
4166 pr_err("Failed to set weak current to %dmA rc=%d\n",
4167 chip->weak_current, rc);
4168 return rc;
4169 }
4170 }
4171
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004172 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4173 if (rc) {
4174 pr_err("Failed to set cold config %d rc=%d\n",
4175 chip->cold_thr, rc);
4176 }
4177
4178 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4179 if (rc) {
4180 pr_err("Failed to set hot config %d rc=%d\n",
4181 chip->hot_thr, rc);
4182 }
4183
Jay Chokshid674a512012-03-15 14:06:04 -07004184 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4185 if (rc) {
4186 pr_err("Failed to set charger LED src config %d rc=%d\n",
4187 chip->led_src_config, rc);
4188 }
4189
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004190 /* Workarounds for die 3.0 */
4191 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4192 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4193 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4194 if (rc) {
4195 pr_err("read failed: addr=%03X, rc=%d\n",
4196 PM_SUB_REV, rc);
4197 return rc;
4198 }
4199 /* Check if die 3.0.1 is present */
4200 if (subrev & 0x1)
4201 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4202 else
4203 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004204 }
4205
David Keitel0789fc62012-06-07 17:43:27 -07004206 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004207 /* Set PM8917 USB_OVP debounce time to 15 ms */
4208 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4209 OVP_DEBOUNCE_TIME, 0x6);
4210 if (rc) {
4211 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4212 return rc;
4213 }
4214
4215 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004216 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004217 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004218 rc = pm_chg_uvd_threshold_set(chip,
4219 chip->uvd_voltage_mv);
4220 if (rc) {
4221 pr_err("Failed to set UVD threshold %drc=%d\n",
4222 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004223 return rc;
4224 }
David Keitel0789fc62012-06-07 17:43:27 -07004225 }
4226 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004227
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004228 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004229
David Keitela3c0d822011-11-03 14:18:52 -07004230 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004231 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004232
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004233 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4234 VREF_BATT_THERM_FORCE_ON);
4235 if (rc)
4236 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004238 rc = pm_chg_charge_dis(chip, charging_disabled);
4239 if (rc) {
4240 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4241 return rc;
4242 }
4243
4244 rc = pm_chg_auto_enable(chip, !charging_disabled);
4245 if (rc) {
4246 pr_err("Failed to enable charging rc=%d\n", rc);
4247 return rc;
4248 }
4249
4250 return 0;
4251}
4252
4253static int get_rt_status(void *data, u64 * val)
4254{
4255 int i = (int)data;
4256 int ret;
4257
4258 /* global irq number is passed in via data */
4259 ret = pm_chg_get_rt_status(the_chip, i);
4260 *val = ret;
4261 return 0;
4262}
4263DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4264
4265static int get_fsm_status(void *data, u64 * val)
4266{
4267 u8 temp;
4268
4269 temp = pm_chg_get_fsm_state(the_chip);
4270 *val = temp;
4271 return 0;
4272}
4273DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4274
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004275static int get_reg_loop(void *data, u64 * val)
4276{
4277 u8 temp;
4278
4279 if (!the_chip) {
4280 pr_err("%s called before init\n", __func__);
4281 return -EINVAL;
4282 }
4283 temp = pm_chg_get_regulation_loop(the_chip);
4284 *val = temp;
4285 return 0;
4286}
4287DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004289static int get_reg(void *data, u64 * val)
4290{
4291 int addr = (int)data;
4292 int ret;
4293 u8 temp;
4294
4295 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4296 if (ret) {
4297 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4298 addr, temp, ret);
4299 return -EAGAIN;
4300 }
4301 *val = temp;
4302 return 0;
4303}
4304
4305static int set_reg(void *data, u64 val)
4306{
4307 int addr = (int)data;
4308 int ret;
4309 u8 temp;
4310
4311 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004312 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004314 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315 addr, temp, ret);
4316 return -EAGAIN;
4317 }
4318 return 0;
4319}
4320DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4321
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004322static int reg_loop;
4323#define MAX_REG_LOOP_CHAR 10
4324static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4325{
4326 u8 temp;
4327
4328 if (!the_chip) {
4329 pr_err("called before init\n");
4330 return -EINVAL;
4331 }
4332 temp = pm_chg_get_regulation_loop(the_chip);
4333 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4334}
4335module_param_call(reg_loop, NULL, get_reg_loop_param,
4336 &reg_loop, 0644);
4337
4338static int max_chg_ma;
4339#define MAX_MA_CHAR 10
4340static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4341{
4342 if (!the_chip) {
4343 pr_err("called before init\n");
4344 return -EINVAL;
4345 }
4346 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4347}
4348module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4349 &max_chg_ma, 0644);
4350static int ibatmax_ma;
4351static int set_ibat_max(const char *val, struct kernel_param *kp)
4352{
4353 int rc;
4354
4355 if (!the_chip) {
4356 pr_err("called before init\n");
4357 return -EINVAL;
4358 }
4359
4360 rc = param_set_int(val, kp);
4361 if (rc) {
4362 pr_err("error setting value %d\n", rc);
4363 return rc;
4364 }
4365
4366 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4367 <= the_chip->ibatmax_max_adj_ma) {
4368 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4369 if (rc) {
4370 pr_err("Failed to set ibatmax rc = %d\n", rc);
4371 return rc;
4372 }
4373 }
4374
4375 return 0;
4376}
4377static int get_ibat_max(char *buf, struct kernel_param *kp)
4378{
4379 int ibat_ma;
4380 int rc;
4381
4382 if (!the_chip) {
4383 pr_err("called before init\n");
4384 return -EINVAL;
4385 }
4386
4387 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4388 if (rc) {
4389 pr_err("ibatmax_get error = %d\n", rc);
4390 return rc;
4391 }
4392
4393 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4394}
4395module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4396 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004397enum {
4398 BAT_WARM_ZONE,
4399 BAT_COOL_ZONE,
4400};
4401static int get_warm_cool(void *data, u64 * val)
4402{
4403 if (!the_chip) {
4404 pr_err("%s called before init\n", __func__);
4405 return -EINVAL;
4406 }
4407 if ((int)data == BAT_WARM_ZONE)
4408 *val = the_chip->is_bat_warm;
4409 if ((int)data == BAT_COOL_ZONE)
4410 *val = the_chip->is_bat_cool;
4411 return 0;
4412}
4413DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004415static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4416{
4417 int i;
4418
4419 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4420
4421 if (IS_ERR(chip->dent)) {
4422 pr_err("pmic charger couldnt create debugfs dir\n");
4423 return;
4424 }
4425
4426 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4427 (void *)CHG_CNTRL, &reg_fops);
4428 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4429 (void *)CHG_CNTRL_2, &reg_fops);
4430 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4431 (void *)CHG_CNTRL_3, &reg_fops);
4432 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4433 (void *)PBL_ACCESS1, &reg_fops);
4434 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4435 (void *)PBL_ACCESS2, &reg_fops);
4436 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4437 (void *)SYS_CONFIG_1, &reg_fops);
4438 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4439 (void *)SYS_CONFIG_2, &reg_fops);
4440 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4441 (void *)CHG_VDD_MAX, &reg_fops);
4442 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4443 (void *)CHG_VDD_SAFE, &reg_fops);
4444 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4445 (void *)CHG_VBAT_DET, &reg_fops);
4446 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4447 (void *)CHG_IBAT_MAX, &reg_fops);
4448 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4449 (void *)CHG_IBAT_SAFE, &reg_fops);
4450 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4451 (void *)CHG_VIN_MIN, &reg_fops);
4452 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4453 (void *)CHG_VTRICKLE, &reg_fops);
4454 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4455 (void *)CHG_ITRICKLE, &reg_fops);
4456 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4457 (void *)CHG_ITERM, &reg_fops);
4458 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4459 (void *)CHG_TCHG_MAX, &reg_fops);
4460 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4461 (void *)CHG_TWDOG, &reg_fops);
4462 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4463 (void *)CHG_TEMP_THRESH, &reg_fops);
4464 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4465 (void *)CHG_COMP_OVR, &reg_fops);
4466 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4467 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4468 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4469 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4470 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4471 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4472 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4473 (void *)CHG_TEST, &reg_fops);
4474
4475 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4476 &fsm_fops);
4477
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004478 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4479 &reg_loop_fops);
4480
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004481 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4482 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4483 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4484 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004486 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4487 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4488 debugfs_create_file(chg_irq_data[i].name, 0444,
4489 chip->dent,
4490 (void *)chg_irq_data[i].irq_id,
4491 &rt_fops);
4492 }
4493}
4494
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004495static int pm8921_charger_suspend_noirq(struct device *dev)
4496{
4497 int rc;
4498 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4499
4500 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4501 if (rc)
4502 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004503
4504 rc = pm8921_chg_set_lpm(chip, 1);
4505 if (rc)
4506 pr_err("Failed to set lpm rc=%d\n", rc);
4507
4508 pm8921_chg_set_hw_clk_switching(chip);
4509
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004510 return 0;
4511}
4512
4513static int pm8921_charger_resume_noirq(struct device *dev)
4514{
4515 int rc;
4516 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4517
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004518 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004519
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004520 rc = pm8921_chg_set_lpm(chip, 0);
4521 if (rc)
4522 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004523
4524 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4525 VREF_BATT_THERM_FORCE_ON);
4526 if (rc)
4527 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4528 return 0;
4529}
4530
David Keitelf2226022011-12-13 15:55:50 -08004531static int pm8921_charger_resume(struct device *dev)
4532{
David Keitelf2226022011-12-13 15:55:50 -08004533 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4534
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004535 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4536 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4537 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4538 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004539
4540 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4541 is_usb_chg_plugged_in(the_chip)))
4542 schedule_delayed_work(&chip->btc_override_work, 0);
4543
David Keitelf2226022011-12-13 15:55:50 -08004544 return 0;
4545}
4546
4547static int pm8921_charger_suspend(struct device *dev)
4548{
David Keitelf2226022011-12-13 15:55:50 -08004549 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4550
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004551 if (chip->btc_override)
4552 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004553
4554 if (is_usb_chg_plugged_in(chip)) {
4555 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4556 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4557 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004558
David Keitelf2226022011-12-13 15:55:50 -08004559 return 0;
4560}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004561static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4562{
4563 int rc = 0;
4564 struct pm8921_chg_chip *chip;
4565 const struct pm8921_charger_platform_data *pdata
4566 = pdev->dev.platform_data;
4567
4568 if (!pdata) {
4569 pr_err("missing platform data\n");
4570 return -EINVAL;
4571 }
4572
4573 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4574 GFP_KERNEL);
4575 if (!chip) {
4576 pr_err("Cannot allocate pm_chg_chip\n");
4577 return -ENOMEM;
4578 }
4579
4580 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004581 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004582 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004583 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004584 chip->alarm_low_mv = pdata->alarm_low_mv;
4585 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004586 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004587 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004588 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004589 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004590 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004591 chip->term_current = pdata->term_current;
4592 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004593 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004594 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4595 chip->batt_id_min = pdata->batt_id_min;
4596 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004597 if (pdata->cool_temp != INT_MIN)
4598 chip->cool_temp_dc = pdata->cool_temp * 10;
4599 else
4600 chip->cool_temp_dc = INT_MIN;
4601
4602 if (pdata->warm_temp != INT_MIN)
4603 chip->warm_temp_dc = pdata->warm_temp * 10;
4604 else
4605 chip->warm_temp_dc = INT_MIN;
4606
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004607 chip->temp_check_period = pdata->temp_check_period;
4608 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004609 /* Assign to corresponding module parameter */
4610 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004611 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4612 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4613 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4614 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004615 chip->trkl_voltage = pdata->trkl_voltage;
4616 chip->weak_voltage = pdata->weak_voltage;
4617 chip->trkl_current = pdata->trkl_current;
4618 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004619 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004620 chip->thermal_mitigation = pdata->thermal_mitigation;
4621 chip->thermal_levels = pdata->thermal_levels;
Anirudh Ghayal0da182f2013-02-22 11:17:19 +05304622 chip->disable_chg_rmvl_wrkarnd = pdata->disable_chg_rmvl_wrkarnd;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004623
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004624 chip->cold_thr = pdata->cold_thr;
4625 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004626 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004627 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004628 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004629 chip->battery_less_hardware = pdata->battery_less_hardware;
4630 chip->btc_override = pdata->btc_override;
4631 if (chip->btc_override) {
4632 chip->btc_delay_ms = pdata->btc_delay_ms;
4633 chip->btc_override_cold_decidegc
4634 = pdata->btc_override_cold_degc * 10;
4635 chip->btc_override_hot_decidegc
4636 = pdata->btc_override_hot_degc * 10;
4637 chip->btc_panic_if_cant_stop_chg
4638 = pdata->btc_panic_if_cant_stop_chg;
4639 }
4640
4641 if (chip->battery_less_hardware)
4642 charging_disabled = 1;
4643
4644 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4645 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004647 rc = pm8921_chg_hw_init(chip);
4648 if (rc) {
4649 pr_err("couldn't init hardware rc=%d\n", rc);
4650 goto free_chip;
4651 }
4652
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004653 if (chip->btc_override)
4654 pm8921_chg_btc_override_init(chip);
4655
4656 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304657 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004658
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004659 chip->usb_psy.name = "usb";
4660 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4661 chip->usb_psy.supplied_to = pm_power_supplied_to;
4662 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4663 chip->usb_psy.properties = pm_power_props_usb;
4664 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4665 chip->usb_psy.get_property = pm_power_get_property_usb;
4666 chip->usb_psy.set_property = pm_power_set_property_usb;
4667 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004669 chip->dc_psy.name = "pm8921-dc";
4670 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4671 chip->dc_psy.supplied_to = pm_power_supplied_to;
4672 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4673 chip->dc_psy.properties = pm_power_props_mains;
4674 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4675 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004676
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004677 chip->batt_psy.name = "battery";
4678 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4679 chip->batt_psy.properties = msm_batt_power_props;
4680 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4681 chip->batt_psy.get_property = pm_batt_power_get_property;
4682 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004683 rc = power_supply_register(chip->dev, &chip->usb_psy);
4684 if (rc < 0) {
4685 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004686 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004687 }
4688
David Keitel6ed71a52012-01-30 12:42:18 -08004689 rc = power_supply_register(chip->dev, &chip->dc_psy);
4690 if (rc < 0) {
4691 pr_err("power_supply_register usb failed rc = %d\n", rc);
4692 goto unregister_usb;
4693 }
4694
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004695 rc = power_supply_register(chip->dev, &chip->batt_psy);
4696 if (rc < 0) {
4697 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004698 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004699 }
4700
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004701 platform_set_drvdata(pdev, chip);
4702 the_chip = chip;
4703
4704 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004705 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004706 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4707 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004708 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004709
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004710 INIT_WORK(&chip->bms_notify.work, bms_notify);
4711 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4712
4713 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4714 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004716 rc = request_irqs(chip, pdev);
4717 if (rc) {
4718 pr_err("couldn't register interrupts rc=%d\n", rc);
4719 goto unregister_batt;
4720 }
4721
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004722 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004723 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004724 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004725 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004727 create_debugfs_entries(chip);
4728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729 /* determine what state the charger is in */
4730 determine_initial_state(chip);
4731
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004732 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004733 schedule_delayed_work(&chip->update_heartbeat_work,
4734 round_jiffies_relative(msecs_to_jiffies
4735 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004736 return 0;
4737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004738unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004739 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004741unregister_dc:
4742 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004743unregister_usb:
4744 power_supply_unregister(&chip->usb_psy);
4745free_chip:
4746 kfree(chip);
4747 return rc;
4748}
4749
4750static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4751{
4752 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4753
4754 free_irqs(chip);
4755 platform_set_drvdata(pdev, NULL);
4756 the_chip = NULL;
4757 kfree(chip);
4758 return 0;
4759}
David Keitelf2226022011-12-13 15:55:50 -08004760static const struct dev_pm_ops pm8921_pm_ops = {
4761 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004762 .suspend_noirq = pm8921_charger_suspend_noirq,
4763 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004764 .resume = pm8921_charger_resume,
4765};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004766static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004767 .probe = pm8921_charger_probe,
4768 .remove = __devexit_p(pm8921_charger_remove),
4769 .driver = {
4770 .name = PM8921_CHARGER_DEV_NAME,
4771 .owner = THIS_MODULE,
4772 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004773 },
4774};
4775
4776static int __init pm8921_charger_init(void)
4777{
4778 return platform_driver_register(&pm8921_charger_driver);
4779}
4780
4781static void __exit pm8921_charger_exit(void)
4782{
4783 platform_driver_unregister(&pm8921_charger_driver);
4784}
4785
4786late_initcall(pm8921_charger_init);
4787module_exit(pm8921_charger_exit);
4788
4789MODULE_LICENSE("GPL v2");
4790MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4791MODULE_VERSION("1.0");
4792MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);