blob: 5f50d3139d785a3de7274ae9c3d68902873d6dc1 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296};
297
David Keitelacf57c82012-03-07 18:48:50 -0800298/* user space parameter to limit usb current */
299static unsigned int usb_max_current;
300/*
301 * usb_target_ma is used for wall charger
302 * adaptive input current limiting only. Use
303 * pm_iusbmax_get() to get current maximum usb current setting.
304 */
305static int usb_target_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306static int charging_disabled;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -0700307static int thermal_mitigation;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308
309static struct pm8921_chg_chip *the_chip;
310
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700311#define LPM_ENABLE_BIT BIT(2)
312static int pm8921_chg_set_lpm(struct pm8921_chg_chip *chip, int enable)
313{
314 int rc;
315 u8 reg;
316
317 rc = pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &reg);
318 if (rc) {
319 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n",
320 CHG_CNTRL, rc);
321 return rc;
322 }
323 reg &= ~LPM_ENABLE_BIT;
324 reg |= (enable ? LPM_ENABLE_BIT : 0);
325
326 rc = pm8xxx_writeb(chip->dev->parent, CHG_CNTRL, reg);
327 if (rc) {
328 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n",
329 CHG_CNTRL, rc);
330 return rc;
331 }
332
333 return rc;
334}
335
336static int pm_chg_write(struct pm8921_chg_chip *chip, u16 addr, u8 reg)
337{
338 int rc;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700339
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -0800340 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
341 if (rc)
342 pr_err("failed: addr=%03X, rc=%d\n", addr, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700343
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700344 return rc;
345}
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -0700346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
348 u8 mask, u8 val)
349{
350 int rc;
351 u8 reg;
352
353 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
354 if (rc) {
355 pr_err("pm8xxx_readb failed: addr=%03X, rc=%d\n", addr, rc);
356 return rc;
357 }
358 reg &= ~mask;
359 reg |= val & mask;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700360 rc = pm_chg_write(chip, addr, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700362 pr_err("pm_chg_write failed: addr=%03X, rc=%d\n", addr, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 return rc;
364 }
365 return 0;
366}
367
David Keitelcf867232012-01-27 18:40:12 -0800368static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
369{
370 return pm8xxx_read_irq_stat(chip->dev->parent,
371 chip->pmic_chg_irq[irq_id]);
372}
373
374/* Treat OverVoltage/UnderVoltage as source missing */
375static int is_usb_chg_plugged_in(struct pm8921_chg_chip *chip)
376{
377 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
378}
379
380/* Treat OverVoltage/UnderVoltage as source missing */
381static int is_dc_chg_plugged_in(struct pm8921_chg_chip *chip)
382{
383 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
384}
385
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -0700386static int is_batfet_closed(struct pm8921_chg_chip *chip)
387{
388 return pm_chg_get_rt_status(chip, BATFET_IRQ);
389}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390#define CAPTURE_FSM_STATE_CMD 0xC2
391#define READ_BANK_7 0x70
392#define READ_BANK_4 0x40
393static int pm_chg_get_fsm_state(struct pm8921_chg_chip *chip)
394{
395 u8 temp;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800396 int err = 0, ret = 0;
397
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 temp = CAPTURE_FSM_STATE_CMD;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800399 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 if (err) {
401 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800402 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 }
404
405 temp = READ_BANK_7;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800406 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 if (err) {
408 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800409 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700410 }
411
412 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
413 if (err) {
414 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800415 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 }
417 /* get the lower 4 bits */
418 ret = temp & 0xF;
419
420 temp = READ_BANK_4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800421 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 if (err) {
423 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800424 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425 }
426
427 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &temp);
428 if (err) {
429 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800430 goto err_out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700431 }
432 /* get the upper 1 bit */
433 ret |= (temp & 0x1) << 4;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800434
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800435err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800436 if (err)
437 return err;
438
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 return ret;
440}
441
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700442#define READ_BANK_6 0x60
443static int pm_chg_get_regulation_loop(struct pm8921_chg_chip *chip)
444{
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800445 u8 temp, data;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800446 int err = 0;
447
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700448 temp = READ_BANK_6;
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800449 err = pm8xxx_writeb(chip->dev->parent, CHG_TEST, temp);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700450 if (err) {
451 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800452 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700453 }
454
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800455 err = pm8xxx_readb(chip->dev->parent, CHG_TEST, &data);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700456 if (err) {
457 pr_err("pm8xxx_readb fail: addr=%03X, rc=%d\n", CHG_TEST, err);
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800458 goto err_out;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700459 }
460
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800461err_out:
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800462 if (err)
463 return err;
464
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700465 /* return the lower 4 bits */
Abhijeet Dharmapurikar7a679a32013-01-07 18:17:46 -0800466 return data & CHG_ALL_LOOPS;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700467}
468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469#define CHG_USB_SUSPEND_BIT BIT(2)
470static int pm_chg_usb_suspend_enable(struct pm8921_chg_chip *chip, int enable)
471{
472 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_USB_SUSPEND_BIT,
473 enable ? CHG_USB_SUSPEND_BIT : 0);
474}
475
476#define CHG_EN_BIT BIT(7)
477static int pm_chg_auto_enable(struct pm8921_chg_chip *chip, int enable)
478{
479 return pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_EN_BIT,
480 enable ? CHG_EN_BIT : 0);
481}
482
David Keitel753ec8d2011-11-02 10:56:37 -0700483#define CHG_FAILED_CLEAR BIT(0)
484#define ATC_FAILED_CLEAR BIT(1)
485static int pm_chg_failed_clear(struct pm8921_chg_chip *chip, int clear)
486{
487 int rc;
488
489 rc = pm_chg_masked_write(chip, CHG_CNTRL_3, ATC_FAILED_CLEAR,
490 clear ? ATC_FAILED_CLEAR : 0);
491 rc |= pm_chg_masked_write(chip, CHG_CNTRL_3, CHG_FAILED_CLEAR,
492 clear ? CHG_FAILED_CLEAR : 0);
493 return rc;
494}
495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496#define CHG_CHARGE_DIS_BIT BIT(1)
497static int pm_chg_charge_dis(struct pm8921_chg_chip *chip, int disable)
498{
499 return pm_chg_masked_write(chip, CHG_CNTRL, CHG_CHARGE_DIS_BIT,
500 disable ? CHG_CHARGE_DIS_BIT : 0);
501}
502
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -0800503static int pm_is_chg_charge_dis(struct pm8921_chg_chip *chip)
504{
505 u8 temp;
506
507 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
508 return temp & CHG_CHARGE_DIS_BIT;
509}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510#define PM8921_CHG_V_MIN_MV 3240
511#define PM8921_CHG_V_STEP_MV 20
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800512#define PM8921_CHG_V_STEP_10MV_OFFSET_BIT BIT(7)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513#define PM8921_CHG_VDDMAX_MAX 4500
514#define PM8921_CHG_VDDMAX_MIN 3400
515#define PM8921_CHG_V_MASK 0x7F
David Keitelcf867232012-01-27 18:40:12 -0800516static int __pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517{
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800518 int remainder;
David Keitelcf867232012-01-27 18:40:12 -0800519 u8 temp = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700520
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800521 if (voltage < PM8921_CHG_VDDMAX_MIN
522 || voltage > PM8921_CHG_VDDMAX_MAX) {
523 pr_err("bad mV=%d asked to set\n", voltage);
524 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525 }
David Keitelcf867232012-01-27 18:40:12 -0800526
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800527 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
528
529 remainder = voltage % 20;
530 if (remainder >= 10) {
531 temp |= PM8921_CHG_V_STEP_10MV_OFFSET_BIT;
532 }
533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 pr_debug("voltage=%d setting %02x\n", voltage, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700535 return pm_chg_write(chip, CHG_VDD_MAX, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536}
537
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700538static int pm_chg_vddmax_get(struct pm8921_chg_chip *chip, int *voltage)
539{
540 u8 temp;
541 int rc;
542
543 rc = pm8xxx_readb(chip->dev->parent, CHG_VDD_MAX, &temp);
544 if (rc) {
545 pr_err("rc = %d while reading vdd max\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700546 *voltage = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700547 return rc;
548 }
Abhijeet Dharmapurikar08e7e0a2012-02-22 19:34:20 -0800549 *voltage = (int)(temp & PM8921_CHG_V_MASK) * PM8921_CHG_V_STEP_MV
550 + PM8921_CHG_V_MIN_MV;
551 if (temp & PM8921_CHG_V_STEP_10MV_OFFSET_BIT)
552 *voltage = *voltage + 10;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700553 return 0;
554}
555
David Keitelcf867232012-01-27 18:40:12 -0800556static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
557{
558 int current_mv, ret, steps, i;
559 bool increase;
560
561 ret = 0;
562
563 if (voltage < PM8921_CHG_VDDMAX_MIN
564 || voltage > PM8921_CHG_VDDMAX_MAX) {
565 pr_err("bad mV=%d asked to set\n", voltage);
566 return -EINVAL;
567 }
568
569 ret = pm_chg_vddmax_get(chip, &current_mv);
570 if (ret) {
571 pr_err("Failed to read vddmax rc=%d\n", ret);
572 return -EINVAL;
573 }
574 if (current_mv == voltage)
575 return 0;
576
577 /* Only change in increments when USB is present */
578 if (is_usb_chg_plugged_in(chip)) {
579 if (current_mv < voltage) {
580 steps = (voltage - current_mv) / PM8921_CHG_V_STEP_MV;
581 increase = true;
582 } else {
583 steps = (current_mv - voltage) / PM8921_CHG_V_STEP_MV;
584 increase = false;
585 }
586 for (i = 0; i < steps; i++) {
587 if (increase)
588 current_mv += PM8921_CHG_V_STEP_MV;
589 else
590 current_mv -= PM8921_CHG_V_STEP_MV;
591 ret |= __pm_chg_vddmax_set(chip, current_mv);
592 }
593 }
594 ret |= __pm_chg_vddmax_set(chip, voltage);
595 return ret;
596}
597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598#define PM8921_CHG_VDDSAFE_MIN 3400
599#define PM8921_CHG_VDDSAFE_MAX 4500
600static int pm_chg_vddsafe_set(struct pm8921_chg_chip *chip, int voltage)
601{
602 u8 temp;
603
604 if (voltage < PM8921_CHG_VDDSAFE_MIN
605 || voltage > PM8921_CHG_VDDSAFE_MAX) {
606 pr_err("bad mV=%d asked to set\n", voltage);
607 return -EINVAL;
608 }
609 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
610 pr_debug("voltage=%d setting %02x\n", voltage, temp);
611 return pm_chg_masked_write(chip, CHG_VDD_SAFE, PM8921_CHG_V_MASK, temp);
612}
613
614#define PM8921_CHG_VBATDET_MIN 3240
615#define PM8921_CHG_VBATDET_MAX 5780
616static int pm_chg_vbatdet_set(struct pm8921_chg_chip *chip, int voltage)
617{
618 u8 temp;
619
620 if (voltage < PM8921_CHG_VBATDET_MIN
621 || voltage > PM8921_CHG_VBATDET_MAX) {
622 pr_err("bad mV=%d asked to set\n", voltage);
623 return -EINVAL;
624 }
625 temp = (voltage - PM8921_CHG_V_MIN_MV) / PM8921_CHG_V_STEP_MV;
626 pr_debug("voltage=%d setting %02x\n", voltage, temp);
627 return pm_chg_masked_write(chip, CHG_VBAT_DET, PM8921_CHG_V_MASK, temp);
628}
629
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -0700630#define PM8921_CHG_VINMIN_MIN_MV 3800
631#define PM8921_CHG_VINMIN_STEP_MV 100
632#define PM8921_CHG_VINMIN_USABLE_MAX 6500
633#define PM8921_CHG_VINMIN_USABLE_MIN 4300
634#define PM8921_CHG_VINMIN_MASK 0x1F
635static int pm_chg_vinmin_set(struct pm8921_chg_chip *chip, int voltage)
636{
637 u8 temp;
638
639 if (voltage < PM8921_CHG_VINMIN_USABLE_MIN
640 || voltage > PM8921_CHG_VINMIN_USABLE_MAX) {
641 pr_err("bad mV=%d asked to set\n", voltage);
642 return -EINVAL;
643 }
644 temp = (voltage - PM8921_CHG_VINMIN_MIN_MV) / PM8921_CHG_VINMIN_STEP_MV;
645 pr_debug("voltage=%d setting %02x\n", voltage, temp);
646 return pm_chg_masked_write(chip, CHG_VIN_MIN, PM8921_CHG_VINMIN_MASK,
647 temp);
648}
649
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -0800650static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
651{
652 u8 temp;
653 int rc, voltage_mv;
654
655 rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
656 temp &= PM8921_CHG_VINMIN_MASK;
657
658 voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
659 (int)temp * PM8921_CHG_VINMIN_STEP_MV;
660
661 return voltage_mv;
662}
663
David Keitel0789fc62012-06-07 17:43:27 -0700664#define PM8917_USB_UVD_MIN_MV 3850
665#define PM8917_USB_UVD_MAX_MV 4350
666#define PM8917_USB_UVD_STEP_MV 100
667#define PM8917_USB_UVD_MASK 0x7
668static int pm_chg_uvd_threshold_set(struct pm8921_chg_chip *chip, int thresh_mv)
669{
670 u8 temp;
671
672 if (thresh_mv < PM8917_USB_UVD_MIN_MV
673 || thresh_mv > PM8917_USB_UVD_MAX_MV) {
674 pr_err("bad mV=%d asked to set\n", thresh_mv);
675 return -EINVAL;
676 }
677 temp = (thresh_mv - PM8917_USB_UVD_MIN_MV) / PM8917_USB_UVD_STEP_MV;
678 return pm_chg_masked_write(chip, OVP_USB_UVD,
679 PM8917_USB_UVD_MASK, temp);
680}
681
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682#define PM8921_CHG_IBATMAX_MIN 325
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700683#define PM8921_CHG_IBATMAX_MAX 3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684#define PM8921_CHG_I_MIN_MA 225
685#define PM8921_CHG_I_STEP_MA 50
686#define PM8921_CHG_I_MASK 0x3F
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700687static int pm_chg_ibatmax_get(struct pm8921_chg_chip *chip, int *ibat_ma)
688{
689 u8 temp;
690 int rc;
691
692 rc = pm8xxx_readb(chip->dev->parent, CHG_IBAT_MAX, &temp);
693 if (rc) {
694 pr_err("rc = %d while reading ibat max\n", rc);
695 *ibat_ma = 0;
696 return rc;
697 }
698 *ibat_ma = (int)(temp & PM8921_CHG_I_MASK) * PM8921_CHG_I_STEP_MA
699 + PM8921_CHG_I_MIN_MA;
700 return 0;
701}
702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703static int pm_chg_ibatmax_set(struct pm8921_chg_chip *chip, int chg_current)
704{
705 u8 temp;
706
707 if (chg_current < PM8921_CHG_IBATMAX_MIN
708 || chg_current > PM8921_CHG_IBATMAX_MAX) {
709 pr_err("bad mA=%d asked to set\n", chg_current);
710 return -EINVAL;
711 }
712 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
713 return pm_chg_masked_write(chip, CHG_IBAT_MAX, PM8921_CHG_I_MASK, temp);
714}
715
716#define PM8921_CHG_IBATSAFE_MIN 225
717#define PM8921_CHG_IBATSAFE_MAX 3375
718static int pm_chg_ibatsafe_set(struct pm8921_chg_chip *chip, int chg_current)
719{
720 u8 temp;
721
722 if (chg_current < PM8921_CHG_IBATSAFE_MIN
723 || chg_current > PM8921_CHG_IBATSAFE_MAX) {
724 pr_err("bad mA=%d asked to set\n", chg_current);
725 return -EINVAL;
726 }
727 temp = (chg_current - PM8921_CHG_I_MIN_MA) / PM8921_CHG_I_STEP_MA;
728 return pm_chg_masked_write(chip, CHG_IBAT_SAFE,
729 PM8921_CHG_I_MASK, temp);
730}
731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732#define PM8921_CHG_ITERM_MIN_MA 50
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700733#define PM8921_CHG_ITERM_MAX_MA 200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700734#define PM8921_CHG_ITERM_STEP_MA 10
735#define PM8921_CHG_ITERM_MASK 0xF
736static int pm_chg_iterm_set(struct pm8921_chg_chip *chip, int chg_current)
737{
738 u8 temp;
739
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700740 if (chg_current < PM8921_CHG_ITERM_MIN_MA
741 || chg_current > PM8921_CHG_ITERM_MAX_MA) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742 pr_err("bad mA=%d asked to set\n", chg_current);
743 return -EINVAL;
744 }
745
746 temp = (chg_current - PM8921_CHG_ITERM_MIN_MA)
747 / PM8921_CHG_ITERM_STEP_MA;
Abhijeet Dharmapurikar71816fd2011-08-12 17:14:10 -0700748 return pm_chg_masked_write(chip, CHG_ITERM, PM8921_CHG_ITERM_MASK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 temp);
750}
751
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700752static int pm_chg_iterm_get(struct pm8921_chg_chip *chip, int *chg_current)
753{
754 u8 temp;
755 int rc;
756
757 rc = pm8xxx_readb(chip->dev->parent, CHG_ITERM, &temp);
758 if (rc) {
759 pr_err("err=%d reading CHG_ITEM\n", rc);
Stephen Boyd81982232011-09-26 12:08:38 -0700760 *chg_current = 0;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -0700761 return rc;
762 }
763 temp &= PM8921_CHG_ITERM_MASK;
764 *chg_current = (int)temp * PM8921_CHG_ITERM_STEP_MA
765 + PM8921_CHG_ITERM_MIN_MA;
766 return 0;
767}
768
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800769struct usb_ma_limit_entry {
David Keitel38bdd4f2012-04-19 15:39:13 -0700770 int usb_ma;
771 u8 value;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800772};
773
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700774/* USB Trim tables */
775static int usb_trim_8038_table[USB_TRIM_ENTRIES] = {
776 0x0,
777 0x0,
778 -0x9,
779 0x0,
780 -0xD,
781 0x0,
782 -0x10,
783 -0x11,
784 0x0,
785 0x0,
786 -0x25,
787 0x0,
788 -0x28,
789 0x0,
790 -0x32,
791 0x0
792};
793
794static int usb_trim_8917_table[USB_TRIM_ENTRIES] = {
795 0x0,
796 0x0,
797 0xA,
798 0xC,
799 0x10,
800 0x10,
801 0x13,
802 0x14,
803 0x13,
804 0x3,
805 0x1A,
806 0x1D,
807 0x1D,
808 0x21,
809 0x24,
810 0x26
811};
812
813/* Maximum USB setting table */
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800814static struct usb_ma_limit_entry usb_ma_table[] = {
David Keitel38bdd4f2012-04-19 15:39:13 -0700815 {100, 0x0},
816 {200, 0x1},
817 {500, 0x2},
818 {600, 0x3},
819 {700, 0x4},
820 {800, 0x5},
821 {850, 0x6},
822 {900, 0x8},
823 {950, 0x7},
824 {1000, 0x9},
825 {1100, 0xA},
826 {1200, 0xB},
827 {1300, 0xC},
828 {1400, 0xD},
829 {1500, 0xE},
830 {1600, 0xF},
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800831};
832
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700833#define REG_SBI_CONFIG 0x04F
834#define PAGE3_ENABLE_MASK 0x6
835#define USB_OVP_TRIM_MASK 0x3F
836#define USB_OVP_TRIM_PM8917_MASK 0x7F
837#define USB_OVP_TRIM_MIN 0x00
838#define REG_USB_OVP_TRIM_ORIG_LSB 0x10A
839#define REG_USB_OVP_TRIM_ORIG_MSB 0x09C
840#define REG_USB_OVP_TRIM_PM8917 0x2B5
841#define REG_USB_OVP_TRIM_PM8917_BIT BIT(0)
842static int pm_chg_usb_trim(struct pm8921_chg_chip *chip, int index)
843{
844 u8 temp, sbi_config, msb, lsb, mask;
845 s8 trim;
846 int rc = 0;
847 static u8 usb_trim_reg_orig = 0xFF;
848
849 /* No trim data for PM8921 */
850 if (!chip->usb_trim_table)
851 return 0;
852
853 if (usb_trim_reg_orig == 0xFF) {
854 rc = pm8xxx_readb(chip->dev->parent,
855 REG_USB_OVP_TRIM_ORIG_MSB, &msb);
856 if (rc) {
857 pr_err("error = %d reading sbi config reg\n", rc);
858 return rc;
859 }
860
861 rc = pm8xxx_readb(chip->dev->parent,
862 REG_USB_OVP_TRIM_ORIG_LSB, &lsb);
863 if (rc) {
864 pr_err("error = %d reading sbi config reg\n", rc);
865 return rc;
866 }
867
868 msb = msb >> 5;
869 lsb = lsb >> 5;
870 usb_trim_reg_orig = msb << 3 | lsb;
871
872 if (pm8xxx_get_version(chip->dev->parent)
873 == PM8XXX_VERSION_8917) {
874 rc = pm8xxx_readb(chip->dev->parent,
875 REG_USB_OVP_TRIM_PM8917, &msb);
876 if (rc) {
877 pr_err("error = %d reading config reg\n", rc);
878 return rc;
879 }
880
881 msb = msb & REG_USB_OVP_TRIM_PM8917_BIT;
882 usb_trim_reg_orig |= msb << 6;
883 }
884 }
885
886 /* use the original trim value */
887 trim = usb_trim_reg_orig;
888
889 trim += chip->usb_trim_table[index];
890 if (trim < 0)
891 trim = 0;
892
893 pr_debug("trim_orig %d write 0x%x index=%d value 0x%x to USB_OVP_TRIM\n",
894 usb_trim_reg_orig, trim, index, chip->usb_trim_table[index]);
895
896 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
897 if (rc) {
898 pr_err("error = %d reading sbi config reg\n", rc);
899 return rc;
900 }
901
902 temp = sbi_config | PAGE3_ENABLE_MASK;
903 rc = pm_chg_write(chip, REG_SBI_CONFIG, temp);
904 if (rc) {
905 pr_err("error = %d writing sbi config reg\n", rc);
906 return rc;
907 }
908
909 mask = USB_OVP_TRIM_MASK;
910
911 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
912 mask = USB_OVP_TRIM_PM8917_MASK;
913
914 rc = pm_chg_masked_write(chip, USB_OVP_TRIM, mask, trim);
915 if (rc) {
916 pr_err("error = %d writing USB_OVP_TRIM\n", rc);
917 return rc;
918 }
919
920 rc = pm_chg_write(chip, REG_SBI_CONFIG, sbi_config);
921 if (rc) {
922 pr_err("error = %d writing sbi config reg\n", rc);
923 return rc;
924 }
925 return rc;
926}
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928#define PM8921_CHG_IUSB_MASK 0x1C
David Keitel38bdd4f2012-04-19 15:39:13 -0700929#define PM8921_CHG_IUSB_SHIFT 2
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930#define PM8921_CHG_IUSB_MAX 7
931#define PM8921_CHG_IUSB_MIN 0
David Keitel38bdd4f2012-04-19 15:39:13 -0700932#define PM8917_IUSB_FINE_RES BIT(0)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700933static int pm_chg_iusbmax_set(struct pm8921_chg_chip *chip, int index)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700935 u8 temp, fineres, reg_val;
David Keitel38bdd4f2012-04-19 15:39:13 -0700936 int rc;
937
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700938 reg_val = usb_ma_table[index].value >> 1;
939 fineres = PM8917_IUSB_FINE_RES & usb_ma_table[index].value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940
Abhijeet Dharmapurikar485a0532011-08-12 17:18:10 -0700941 if (reg_val < PM8921_CHG_IUSB_MIN || reg_val > PM8921_CHG_IUSB_MAX) {
942 pr_err("bad mA=%d asked to set\n", reg_val);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 return -EINVAL;
944 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700945 temp = reg_val << PM8921_CHG_IUSB_SHIFT;
946
947 /* IUSB_FINE_RES */
948 if (chip->iusb_fine_res) {
949 /* Clear IUSB_FINE_RES bit to avoid overshoot */
950 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
951 PM8917_IUSB_FINE_RES, 0);
952
953 rc |= pm_chg_masked_write(chip, PBL_ACCESS2,
954 PM8921_CHG_IUSB_MASK, temp);
955
956 if (rc) {
957 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
958 return rc;
959 }
960
961 if (fineres) {
962 rc = pm_chg_masked_write(chip, IUSB_FINE_RES,
963 PM8917_IUSB_FINE_RES, fineres);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700964 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700965 pr_err("Failed to write ISUB_FINE_RES rc=%d\n",
966 rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700967 return rc;
968 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700969 }
970 } else {
971 rc = pm_chg_masked_write(chip, PBL_ACCESS2,
972 PM8921_CHG_IUSB_MASK, temp);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700973 if (rc) {
David Keitel38bdd4f2012-04-19 15:39:13 -0700974 pr_err("Failed to write PBL_ACCESS2 rc=%d\n", rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700975 return rc;
976 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700977 }
978
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -0700979 rc = pm_chg_usb_trim(chip, index);
980 if (rc)
981 pr_err("unable to set usb trim rc = %d\n", rc);
982
David Keitel38bdd4f2012-04-19 15:39:13 -0700983 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700984}
985
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800986static int pm_chg_iusbmax_get(struct pm8921_chg_chip *chip, int *mA)
987{
David Keitel38bdd4f2012-04-19 15:39:13 -0700988 u8 temp, fineres;
989 int rc, i;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800990
David Keitel38bdd4f2012-04-19 15:39:13 -0700991 fineres = 0;
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -0800992 *mA = 0;
993 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS2, &temp);
994 if (rc) {
995 pr_err("err=%d reading PBL_ACCESS2\n", rc);
996 return rc;
997 }
David Keitel38bdd4f2012-04-19 15:39:13 -0700998
999 if (chip->iusb_fine_res) {
1000 rc = pm8xxx_readb(chip->dev->parent, IUSB_FINE_RES, &fineres);
1001 if (rc) {
1002 pr_err("err=%d reading IUSB_FINE_RES\n", rc);
1003 return rc;
1004 }
1005 }
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001006 temp &= PM8921_CHG_IUSB_MASK;
David Keitel38bdd4f2012-04-19 15:39:13 -07001007 temp = temp >> PM8921_CHG_IUSB_SHIFT;
1008
1009 temp = (temp << 1) | (fineres & PM8917_IUSB_FINE_RES);
1010 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1011 if (usb_ma_table[i].value == temp)
1012 break;
1013 }
1014
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001015 if (i < 0) {
1016 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1017 i = 0;
1018 }
1019
Willie Ruan13c972d2012-11-15 11:56:36 -08001020 if (i < 0) {
1021 pr_err("can't find %d in usb_ma_table. Use min.\n", temp);
1022 i = 0;
1023 }
1024
David Keitel38bdd4f2012-04-19 15:39:13 -07001025 *mA = usb_ma_table[i].usb_ma;
1026
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08001027 return rc;
1028}
1029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030#define PM8921_CHG_WD_MASK 0x1F
1031static int pm_chg_disable_wd(struct pm8921_chg_chip *chip)
1032{
1033 /* writing 0 to the wd timer disables it */
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001034 return pm_chg_masked_write(chip, CHG_TWDOG, PM8921_CHG_WD_MASK, 0);
1035}
1036
Abhijeet Dharmapurikarc26cd902011-10-26 18:07:45 -07001037#define PM8921_CHG_TCHG_MASK 0x7F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001038#define PM8921_CHG_TCHG_MIN 4
1039#define PM8921_CHG_TCHG_MAX 512
1040#define PM8921_CHG_TCHG_STEP 4
1041static int pm_chg_tchg_max_set(struct pm8921_chg_chip *chip, int minutes)
1042{
1043 u8 temp;
1044
1045 if (minutes < PM8921_CHG_TCHG_MIN || minutes > PM8921_CHG_TCHG_MAX) {
1046 pr_err("bad max minutes =%d asked to set\n", minutes);
1047 return -EINVAL;
1048 }
1049
1050 temp = (minutes - 1)/PM8921_CHG_TCHG_STEP;
1051 return pm_chg_masked_write(chip, CHG_TCHG_MAX, PM8921_CHG_TCHG_MASK,
1052 temp);
1053}
1054
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001055#define PM8921_CHG_TTRKL_MASK 0x3F
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001056#define PM8921_CHG_TTRKL_MIN 1
1057#define PM8921_CHG_TTRKL_MAX 64
1058static int pm_chg_ttrkl_max_set(struct pm8921_chg_chip *chip, int minutes)
1059{
1060 u8 temp;
1061
1062 if (minutes < PM8921_CHG_TTRKL_MIN || minutes > PM8921_CHG_TTRKL_MAX) {
1063 pr_err("bad max minutes =%d asked to set\n", minutes);
1064 return -EINVAL;
1065 }
1066
1067 temp = minutes - 1;
1068 return pm_chg_masked_write(chip, CHG_TTRKL_MAX, PM8921_CHG_TTRKL_MASK,
1069 temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070}
1071
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07001072#define PM8921_CHG_VTRKL_MIN_MV 2050
1073#define PM8921_CHG_VTRKL_MAX_MV 2800
1074#define PM8921_CHG_VTRKL_STEP_MV 50
1075#define PM8921_CHG_VTRKL_SHIFT 4
1076#define PM8921_CHG_VTRKL_MASK 0xF0
1077static int pm_chg_vtrkl_low_set(struct pm8921_chg_chip *chip, int millivolts)
1078{
1079 u8 temp;
1080
1081 if (millivolts < PM8921_CHG_VTRKL_MIN_MV
1082 || millivolts > PM8921_CHG_VTRKL_MAX_MV) {
1083 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1084 return -EINVAL;
1085 }
1086
1087 temp = (millivolts - PM8921_CHG_VTRKL_MIN_MV)/PM8921_CHG_VTRKL_STEP_MV;
1088 temp = temp << PM8921_CHG_VTRKL_SHIFT;
1089 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VTRKL_MASK,
1090 temp);
1091}
1092
1093#define PM8921_CHG_VWEAK_MIN_MV 2100
1094#define PM8921_CHG_VWEAK_MAX_MV 3600
1095#define PM8921_CHG_VWEAK_STEP_MV 100
1096#define PM8921_CHG_VWEAK_MASK 0x0F
1097static int pm_chg_vweak_set(struct pm8921_chg_chip *chip, int millivolts)
1098{
1099 u8 temp;
1100
1101 if (millivolts < PM8921_CHG_VWEAK_MIN_MV
1102 || millivolts > PM8921_CHG_VWEAK_MAX_MV) {
1103 pr_err("bad voltage = %dmV asked to set\n", millivolts);
1104 return -EINVAL;
1105 }
1106
1107 temp = (millivolts - PM8921_CHG_VWEAK_MIN_MV)/PM8921_CHG_VWEAK_STEP_MV;
1108 return pm_chg_masked_write(chip, CHG_VTRICKLE, PM8921_CHG_VWEAK_MASK,
1109 temp);
1110}
1111
1112#define PM8921_CHG_ITRKL_MIN_MA 50
1113#define PM8921_CHG_ITRKL_MAX_MA 200
1114#define PM8921_CHG_ITRKL_MASK 0x0F
1115#define PM8921_CHG_ITRKL_STEP_MA 10
1116static int pm_chg_itrkl_set(struct pm8921_chg_chip *chip, int milliamps)
1117{
1118 u8 temp;
1119
1120 if (milliamps < PM8921_CHG_ITRKL_MIN_MA
1121 || milliamps > PM8921_CHG_ITRKL_MAX_MA) {
1122 pr_err("bad current = %dmA asked to set\n", milliamps);
1123 return -EINVAL;
1124 }
1125
1126 temp = (milliamps - PM8921_CHG_ITRKL_MIN_MA)/PM8921_CHG_ITRKL_STEP_MA;
1127
1128 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_ITRKL_MASK,
1129 temp);
1130}
1131
1132#define PM8921_CHG_IWEAK_MIN_MA 325
1133#define PM8921_CHG_IWEAK_MAX_MA 525
1134#define PM8921_CHG_IWEAK_SHIFT 7
1135#define PM8921_CHG_IWEAK_MASK 0x80
1136static int pm_chg_iweak_set(struct pm8921_chg_chip *chip, int milliamps)
1137{
1138 u8 temp;
1139
1140 if (milliamps < PM8921_CHG_IWEAK_MIN_MA
1141 || milliamps > PM8921_CHG_IWEAK_MAX_MA) {
1142 pr_err("bad current = %dmA asked to set\n", milliamps);
1143 return -EINVAL;
1144 }
1145
1146 if (milliamps < PM8921_CHG_IWEAK_MAX_MA)
1147 temp = 0;
1148 else
1149 temp = 1;
1150
1151 temp = temp << PM8921_CHG_IWEAK_SHIFT;
1152 return pm_chg_masked_write(chip, CHG_ITRICKLE, PM8921_CHG_IWEAK_MASK,
1153 temp);
1154}
1155
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07001156#define PM8921_CHG_BATT_TEMP_THR_COLD BIT(1)
1157#define PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT 1
1158static int pm_chg_batt_cold_temp_config(struct pm8921_chg_chip *chip,
1159 enum pm8921_chg_cold_thr cold_thr)
1160{
1161 u8 temp;
1162
1163 temp = cold_thr << PM8921_CHG_BATT_TEMP_THR_COLD_SHIFT;
1164 temp = temp & PM8921_CHG_BATT_TEMP_THR_COLD;
1165 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1166 PM8921_CHG_BATT_TEMP_THR_COLD,
1167 temp);
1168}
1169
1170#define PM8921_CHG_BATT_TEMP_THR_HOT BIT(0)
1171#define PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT 0
1172static int pm_chg_batt_hot_temp_config(struct pm8921_chg_chip *chip,
1173 enum pm8921_chg_hot_thr hot_thr)
1174{
1175 u8 temp;
1176
1177 temp = hot_thr << PM8921_CHG_BATT_TEMP_THR_HOT_SHIFT;
1178 temp = temp & PM8921_CHG_BATT_TEMP_THR_HOT;
1179 return pm_chg_masked_write(chip, CHG_CNTRL_2,
1180 PM8921_CHG_BATT_TEMP_THR_HOT,
1181 temp);
1182}
1183
Jay Chokshid674a512012-03-15 14:06:04 -07001184#define PM8921_CHG_LED_SRC_CONFIG_SHIFT 4
1185#define PM8921_CHG_LED_SRC_CONFIG_MASK 0x30
1186static int pm_chg_led_src_config(struct pm8921_chg_chip *chip,
1187 enum pm8921_chg_led_src_config led_src_config)
1188{
1189 u8 temp;
1190
1191 if (led_src_config < LED_SRC_GND ||
1192 led_src_config > LED_SRC_BYPASS)
1193 return -EINVAL;
1194
1195 if (led_src_config == LED_SRC_BYPASS)
1196 return 0;
1197
1198 temp = led_src_config << PM8921_CHG_LED_SRC_CONFIG_SHIFT;
1199
1200 return pm_chg_masked_write(chip, CHG_CNTRL_3,
1201 PM8921_CHG_LED_SRC_CONFIG_MASK, temp);
1202}
1203
David Keitel8c5201a2012-02-24 16:08:54 -08001204
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001205static int64_t read_battery_id(struct pm8921_chg_chip *chip)
1206{
1207 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001208 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001209
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001210 rc = pm8xxx_adc_read(chip->batt_id_channel, &result);
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001211 if (rc) {
1212 pr_err("error reading batt id channel = %d, rc = %d\n",
1213 chip->vbat_channel, rc);
1214 return rc;
1215 }
1216 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1217 result.measurement);
1218 return result.physical;
1219}
1220
1221static int is_battery_valid(struct pm8921_chg_chip *chip)
1222{
1223 int64_t rc;
1224
1225 if (chip->batt_id_min == 0 && chip->batt_id_max == 0)
1226 return 1;
1227
1228 rc = read_battery_id(chip);
1229 if (rc < 0) {
1230 pr_err("error reading batt id channel = %d, rc = %lld\n",
1231 chip->vbat_channel, rc);
1232 /* assume battery id is valid when adc error happens */
1233 return 1;
1234 }
1235
1236 if (rc < chip->batt_id_min || rc > chip->batt_id_max) {
1237 pr_err("batt_id phy =%lld is not valid\n", rc);
1238 return 0;
1239 }
1240 return 1;
1241}
1242
1243static void check_battery_valid(struct pm8921_chg_chip *chip)
1244{
1245 if (is_battery_valid(chip) == 0) {
1246 pr_err("batt_id not valid, disbling charging\n");
1247 pm_chg_auto_enable(chip, 0);
1248 } else {
1249 pm_chg_auto_enable(chip, !charging_disabled);
1250 }
1251}
1252
1253static void battery_id_valid(struct work_struct *work)
1254{
1255 struct pm8921_chg_chip *chip = container_of(work,
1256 struct pm8921_chg_chip, battery_id_valid_work);
1257
1258 check_battery_valid(chip);
1259}
1260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261static void pm8921_chg_enable_irq(struct pm8921_chg_chip *chip, int interrupt)
1262{
1263 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
1264 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1265 enable_irq(chip->pmic_chg_irq[interrupt]);
1266 }
1267}
1268
1269static void pm8921_chg_disable_irq(struct pm8921_chg_chip *chip, int interrupt)
1270{
1271 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
1272 dev_dbg(chip->dev, "%d\n", chip->pmic_chg_irq[interrupt]);
1273 disable_irq_nosync(chip->pmic_chg_irq[interrupt]);
1274 }
1275}
1276
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08001277static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
1278{
1279 return test_bit(interrupt, chip->enabled_irqs);
1280}
1281
Amir Samuelovd31ef502011-10-26 14:41:36 +02001282static bool is_ext_charging(struct pm8921_chg_chip *chip)
1283{
David Keitel88e1b572012-01-11 11:57:14 -08001284 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001285
David Keitel88e1b572012-01-11 11:57:14 -08001286 if (!chip->ext_psy)
1287 return false;
1288 if (chip->ext_psy->get_property(chip->ext_psy,
1289 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1290 return false;
1291 if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
1292 return ret.intval;
Amir Samuelovd31ef502011-10-26 14:41:36 +02001293
1294 return false;
1295}
1296
1297static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
1298{
David Keitel88e1b572012-01-11 11:57:14 -08001299 union power_supply_propval ret = {0,};
Amir Samuelovd31ef502011-10-26 14:41:36 +02001300
David Keitel88e1b572012-01-11 11:57:14 -08001301 if (!chip->ext_psy)
1302 return false;
1303 if (chip->ext_psy->get_property(chip->ext_psy,
1304 POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
1305 return false;
1306 if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
Amir Samuelovd31ef502011-10-26 14:41:36 +02001307 return true;
1308
1309 return false;
1310}
1311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312static int is_battery_charging(int fsm_state)
1313{
Amir Samuelovd31ef502011-10-26 14:41:36 +02001314 if (is_ext_charging(the_chip))
1315 return 1;
1316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317 switch (fsm_state) {
1318 case FSM_STATE_ATC_2A:
1319 case FSM_STATE_ATC_2B:
1320 case FSM_STATE_ON_CHG_AND_BAT_6:
1321 case FSM_STATE_FAST_CHG_7:
1322 case FSM_STATE_TRKL_CHG_8:
1323 return 1;
1324 }
1325 return 0;
1326}
1327
1328static void bms_notify(struct work_struct *work)
1329{
1330 struct bms_notify *n = container_of(work, struct bms_notify, work);
1331
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001332 if (n->is_charging) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 pm8921_bms_charging_began();
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07001334 } else {
1335 pm8921_bms_charging_end(n->is_battery_full);
1336 n->is_battery_full = 0;
1337 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338}
1339
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07001340static void bms_notify_check(struct pm8921_chg_chip *chip)
1341{
1342 int fsm_state, new_is_charging;
1343
1344 fsm_state = pm_chg_get_fsm_state(chip);
1345 new_is_charging = is_battery_charging(fsm_state);
1346
1347 if (chip->bms_notify.is_charging ^ new_is_charging) {
1348 chip->bms_notify.is_charging = new_is_charging;
1349 schedule_work(&(chip->bms_notify.work));
1350 }
1351}
1352
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001353static enum power_supply_property pm_power_props_usb[] = {
1354 POWER_SUPPLY_PROP_PRESENT,
1355 POWER_SUPPLY_PROP_ONLINE,
1356 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001357 POWER_SUPPLY_PROP_SCOPE,
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001358 POWER_SUPPLY_PROP_HEALTH,
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001359};
1360
1361static enum power_supply_property pm_power_props_mains[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 POWER_SUPPLY_PROP_PRESENT,
Willie Ruan9ad6d832011-08-19 11:58:42 -07001363 POWER_SUPPLY_PROP_ONLINE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364};
1365
1366static char *pm_power_supplied_to[] = {
1367 "battery",
1368};
1369
David Keitel6ed71a52012-01-30 12:42:18 -08001370#define USB_WALL_THRESHOLD_MA 500
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001371static int pm_power_get_property_mains(struct power_supply *psy,
1372 enum power_supply_property psp,
1373 union power_supply_propval *val)
1374{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001375 int type;
1376
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001377 /* Check if called before init */
1378 if (!the_chip)
1379 return -EINVAL;
1380
1381 switch (psp) {
1382 case POWER_SUPPLY_PROP_PRESENT:
1383 case POWER_SUPPLY_PROP_ONLINE:
1384 val->intval = 0;
David Keitelff4f9ce2012-08-24 15:11:23 -07001385
1386 if (the_chip->has_dc_supply) {
1387 val->intval = 1;
1388 return 0;
1389 }
1390
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001391 if (the_chip->dc_present) {
1392 val->intval = 1;
1393 return 0;
1394 }
1395
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301396 type = the_chip->usb_type;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001397 if (type == POWER_SUPPLY_TYPE_USB_DCP ||
1398 type == POWER_SUPPLY_TYPE_USB_ACA ||
1399 type == POWER_SUPPLY_TYPE_USB_CDP)
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001400 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001401
1402 break;
1403 default:
1404 return -EINVAL;
1405 }
1406 return 0;
1407}
1408
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001409static int disable_aicl(int disable)
1410{
1411 if (disable != POWER_SUPPLY_HEALTH_UNKNOWN
1412 && disable != POWER_SUPPLY_HEALTH_GOOD) {
1413 pr_err("called with invalid param :%d\n", disable);
1414 return -EINVAL;
1415 }
1416
1417 if (!the_chip) {
1418 pr_err("%s called before init\n", __func__);
1419 return -EINVAL;
1420 }
1421
1422 pr_debug("Disable AICL = %d\n", disable);
1423 the_chip->disable_aicl = disable;
1424 return 0;
1425}
1426
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001427static int switch_usb_to_charge_mode(struct pm8921_chg_chip *chip)
1428{
1429 int rc;
1430
1431 if (!chip->host_mode)
1432 return 0;
1433
1434 /* enable usbin valid comparator and remove force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001435 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB2);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001436 if (rc < 0) {
1437 pr_err("Failed to write 0xB2 to USB_OVP_TEST rc = %d\n", rc);
1438 return rc;
1439 }
1440
1441 chip->host_mode = 0;
1442
1443 return 0;
1444}
1445
1446static int switch_usb_to_host_mode(struct pm8921_chg_chip *chip)
1447{
1448 int rc;
1449
1450 if (chip->host_mode)
1451 return 0;
1452
1453 /* disable usbin valid comparator and force usb ovp fet off */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001454 rc = pm_chg_write(chip, USB_OVP_TEST, 0xB3);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001455 if (rc < 0) {
1456 pr_err("Failed to write 0xB3 to USB_OVP_TEST rc = %d\n", rc);
1457 return rc;
1458 }
1459
1460 chip->host_mode = 1;
1461
1462 return 0;
1463}
1464
1465static int pm_power_set_property_usb(struct power_supply *psy,
1466 enum power_supply_property psp,
1467 const union power_supply_propval *val)
1468{
1469 /* Check if called before init */
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001470 if (!the_chip)
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001471 return -EINVAL;
1472
1473 switch (psp) {
1474 case POWER_SUPPLY_PROP_SCOPE:
1475 if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001476 return switch_usb_to_host_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001477 if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001478 return switch_usb_to_charge_mode(the_chip);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001479 else
1480 return -EINVAL;
1481 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001482 case POWER_SUPPLY_PROP_TYPE:
1483 return pm8921_set_usb_power_supply_type(val->intval);
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001484 case POWER_SUPPLY_PROP_HEALTH:
1485 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1486 return disable_aicl(val->intval);
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001487 default:
1488 return -EINVAL;
1489 }
1490 return 0;
1491}
1492
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001493static int usb_property_is_writeable(struct power_supply *psy,
1494 enum power_supply_property psp)
1495{
1496 switch (psp) {
1497 case POWER_SUPPLY_PROP_HEALTH:
1498 return 1;
1499 default:
1500 break;
1501 }
1502
1503 return 0;
1504}
1505
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001506static int pm_power_get_property_usb(struct power_supply *psy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 enum power_supply_property psp,
1508 union power_supply_propval *val)
1509{
David Keitel6ed71a52012-01-30 12:42:18 -08001510 int current_max;
1511
1512 /* Check if called before init */
1513 if (!the_chip)
1514 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515
1516 switch (psp) {
David Keitel6ed71a52012-01-30 12:42:18 -08001517 case POWER_SUPPLY_PROP_CURRENT_MAX:
Abhijeet Dharmapurikar9da392d2012-02-22 18:59:57 -08001518 if (pm_is_chg_charge_dis(the_chip)) {
1519 val->intval = 0;
1520 } else {
1521 pm_chg_iusbmax_get(the_chip, &current_max);
1522 val->intval = current_max;
1523 }
David Keitel6ed71a52012-01-30 12:42:18 -08001524 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 case POWER_SUPPLY_PROP_PRESENT:
Willie Ruan9ad6d832011-08-19 11:58:42 -07001526 case POWER_SUPPLY_PROP_ONLINE:
David Keitel63f71662012-02-08 20:30:00 -08001527 val->intval = 0;
David Keitel63f71662012-02-08 20:30:00 -08001528
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05301529 if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
David Keitel86034022012-04-18 12:33:58 -07001530 val->intval = is_usb_chg_plugged_in(the_chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 break;
Abhijeet Dharmapurikar5e96aaa2012-06-26 11:21:03 -07001533
1534 case POWER_SUPPLY_PROP_SCOPE:
1535 if (the_chip->host_mode)
1536 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1537 else
1538 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1539 break;
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001540 case POWER_SUPPLY_PROP_HEALTH:
1541 /* UNKNOWN(0) means enable aicl, GOOD(1) means disable aicl */
1542 val->intval = the_chip->disable_aicl;
1543 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 default:
1545 return -EINVAL;
1546 }
1547 return 0;
1548}
1549
1550static enum power_supply_property msm_batt_power_props[] = {
1551 POWER_SUPPLY_PROP_STATUS,
1552 POWER_SUPPLY_PROP_CHARGE_TYPE,
1553 POWER_SUPPLY_PROP_HEALTH,
1554 POWER_SUPPLY_PROP_PRESENT,
1555 POWER_SUPPLY_PROP_TECHNOLOGY,
1556 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
1557 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
1558 POWER_SUPPLY_PROP_VOLTAGE_NOW,
1559 POWER_SUPPLY_PROP_CAPACITY,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001560 POWER_SUPPLY_PROP_CURRENT_MAX,
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001561 POWER_SUPPLY_PROP_CURRENT_NOW,
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001562 POWER_SUPPLY_PROP_TEMP,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001563 POWER_SUPPLY_PROP_CHARGE_FULL,
1564 POWER_SUPPLY_PROP_CHARGE_NOW,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565};
1566
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001567static int get_prop_battery_uvolts(struct pm8921_chg_chip *chip)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568{
1569 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001570 struct pm8xxx_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001572 rc = pm8xxx_adc_read(chip->vbat_channel, &result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001573 if (rc) {
1574 pr_err("error reading adc channel = %d, rc = %d\n",
1575 chip->vbat_channel, rc);
1576 return rc;
1577 }
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07001578 pr_debug("mvolts phy = %lld meas = 0x%llx\n", result.physical,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 result.measurement);
1580 return (int)result.physical;
1581}
1582
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001583static unsigned int voltage_based_capacity(struct pm8921_chg_chip *chip)
1584{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001585 unsigned int current_voltage_uv = get_prop_battery_uvolts(chip);
1586 unsigned int current_voltage_mv = current_voltage_uv / 1000;
1587 unsigned int low_voltage = chip->min_voltage_mv;
1588 unsigned int high_voltage = chip->max_voltage_mv;
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001589
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001590 if (current_voltage_mv <= low_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001591 return 0;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001592 else if (current_voltage_mv >= high_voltage)
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001593 return 100;
1594 else
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001595 return (current_voltage_mv - low_voltage) * 100
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001596 / (high_voltage - low_voltage);
1597}
1598
David Keitel4f9397b2012-04-16 11:46:16 -07001599static int get_prop_batt_present(struct pm8921_chg_chip *chip)
1600{
1601 return pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
1602}
1603
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001604static int get_prop_batt_status(struct pm8921_chg_chip *chip)
1605{
1606 int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
1607 int fsm_state = pm_chg_get_fsm_state(chip);
1608 int i;
1609
1610 if (chip->ext_psy) {
1611 if (chip->ext_charge_done)
1612 return POWER_SUPPLY_STATUS_FULL;
1613 if (chip->ext_charging)
1614 return POWER_SUPPLY_STATUS_CHARGING;
1615 }
1616
1617 for (i = 0; i < ARRAY_SIZE(map); i++)
1618 if (map[i].fsm_state == fsm_state)
1619 batt_state = map[i].batt_state;
1620
1621 if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
1622 if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
1623 || !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
1624 || pm_chg_get_rt_status(chip, CHGHOT_IRQ)
1625 || pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
1626
1627 batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
1628 }
1629 return batt_state;
1630}
1631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632static int get_prop_batt_capacity(struct pm8921_chg_chip *chip)
1633{
David Keitel4f9397b2012-04-16 11:46:16 -07001634 int percent_soc;
1635
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001636 if (chip->battery_less_hardware)
1637 return 100;
1638
David Keitel4f9397b2012-04-16 11:46:16 -07001639 if (!get_prop_batt_present(chip))
1640 percent_soc = voltage_based_capacity(chip);
1641 else
1642 percent_soc = pm8921_bms_get_percent_charge();
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001643
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001644 if (percent_soc == -ENXIO)
1645 percent_soc = voltage_based_capacity(chip);
1646
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001647 if (percent_soc <= 10)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001648 pr_warn_ratelimited("low battery charge = %d%%\n",
1649 percent_soc);
1650
1651 if (percent_soc <= chip->resume_charge_percent
1652 && get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL) {
1653 pr_debug("soc fell below %d. charging enabled.\n",
1654 chip->resume_charge_percent);
1655 if (chip->is_bat_warm)
1656 pr_warn_ratelimited("battery is warm = %d, do not resume charging at %d%%.\n",
1657 chip->is_bat_warm,
1658 chip->resume_charge_percent);
1659 else if (chip->is_bat_cool)
1660 pr_warn_ratelimited("battery is cool = %d, do not resume charging at %d%%.\n",
1661 chip->is_bat_cool,
1662 chip->resume_charge_percent);
1663 else
1664 pm_chg_vbatdet_set(the_chip, PM8921_CHG_VBATDET_MAX);
1665 }
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001666
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07001667 chip->recent_reported_soc = percent_soc;
Abhijeet Dharmapurikar5a7df4e2011-07-27 13:16:24 -07001668 return percent_soc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669}
1670
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001671static int get_prop_batt_current_max(struct pm8921_chg_chip *chip)
1672{
1673 return pm8921_bms_get_current_max();
1674}
1675
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001676static int get_prop_batt_current(struct pm8921_chg_chip *chip)
1677{
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001678 int result_ua, rc;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001679
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001680 rc = pm8921_bms_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001681 if (rc == -ENXIO) {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001682 rc = pm8xxx_ccadc_get_battery_current(&result_ua);
Abhijeet Dharmapurikar4ffea2c2011-11-11 18:25:02 -08001683 }
1684
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001685 if (rc) {
1686 pr_err("unable to get batt current rc = %d\n", rc);
1687 return rc;
1688 } else {
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001689 return result_ua;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001690 }
1691}
1692
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001693static int get_prop_batt_fcc(struct pm8921_chg_chip *chip)
1694{
1695 int rc;
1696
1697 rc = pm8921_bms_get_fcc();
1698 if (rc < 0)
1699 pr_err("unable to get batt fcc rc = %d\n", rc);
1700 return rc;
1701}
1702
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001703static int get_prop_batt_charge_now(struct pm8921_chg_chip *chip)
1704{
1705 int rc;
1706 int cc_uah;
1707
1708 rc = pm8921_bms_cc_uah(&cc_uah);
1709
1710 if (rc == 0)
1711 return cc_uah;
1712
1713 pr_err("unable to get batt fcc rc = %d\n", rc);
1714 return rc;
1715}
1716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717static int get_prop_batt_health(struct pm8921_chg_chip *chip)
1718{
1719 int temp;
1720
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001721 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
1722 if (temp)
1723 return POWER_SUPPLY_HEALTH_OVERHEAT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001725 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
1726 if (temp)
1727 return POWER_SUPPLY_HEALTH_COLD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08001729 return POWER_SUPPLY_HEALTH_GOOD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730}
1731
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732static int get_prop_charge_type(struct pm8921_chg_chip *chip)
1733{
1734 int temp;
1735
Amir Samuelovd31ef502011-10-26 14:41:36 +02001736 if (!get_prop_batt_present(chip))
1737 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1738
1739 if (is_ext_trickle_charging(chip))
1740 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1741
1742 if (is_ext_charging(chip))
1743 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1744
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 temp = pm_chg_get_rt_status(chip, TRKLCHG_IRQ);
1746 if (temp)
1747 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1748
1749 temp = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
1750 if (temp)
1751 return POWER_SUPPLY_CHARGE_TYPE_FAST;
1752
1753 return POWER_SUPPLY_CHARGE_TYPE_NONE;
1754}
1755
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001756#define MAX_TOLERABLE_BATT_TEMP_DDC 680
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001757static int get_prop_batt_temp(struct pm8921_chg_chip *chip)
1758{
1759 int rc;
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001760 struct pm8xxx_adc_chan_result result;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001761
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001762 if (chip->battery_less_hardware)
1763 return 300;
1764
Siddartha Mohanadossaf91d902011-10-20 10:23:34 -07001765 rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001766 if (rc) {
1767 pr_err("error reading adc channel = %d, rc = %d\n",
1768 chip->vbat_channel, rc);
1769 return rc;
1770 }
1771 pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
1772 result.measurement);
Abhijeet Dharmapurikar728bc4d2012-01-03 11:08:33 -08001773 if (result.physical > MAX_TOLERABLE_BATT_TEMP_DDC)
1774 pr_err("BATT_TEMP= %d > 68degC, device will be shutdown\n",
1775 (int) result.physical);
1776
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001777 return (int)result.physical;
1778}
1779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780static int pm_batt_power_get_property(struct power_supply *psy,
1781 enum power_supply_property psp,
1782 union power_supply_propval *val)
1783{
1784 struct pm8921_chg_chip *chip = container_of(psy, struct pm8921_chg_chip,
1785 batt_psy);
1786
1787 switch (psp) {
1788 case POWER_SUPPLY_PROP_STATUS:
1789 val->intval = get_prop_batt_status(chip);
1790 break;
1791 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1792 val->intval = get_prop_charge_type(chip);
1793 break;
1794 case POWER_SUPPLY_PROP_HEALTH:
1795 val->intval = get_prop_batt_health(chip);
1796 break;
1797 case POWER_SUPPLY_PROP_PRESENT:
1798 val->intval = get_prop_batt_present(chip);
1799 break;
1800 case POWER_SUPPLY_PROP_TECHNOLOGY:
1801 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
1802 break;
1803 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001804 val->intval = chip->max_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 break;
1806 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001807 val->intval = chip->min_voltage_mv * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 break;
1809 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08001810 val->intval = get_prop_battery_uvolts(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 break;
1812 case POWER_SUPPLY_PROP_CAPACITY:
1813 val->intval = get_prop_batt_capacity(chip);
1814 break;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001815 case POWER_SUPPLY_PROP_CURRENT_NOW:
1816 val->intval = get_prop_batt_current(chip);
1817 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001818 case POWER_SUPPLY_PROP_CURRENT_MAX:
1819 val->intval = get_prop_batt_current_max(chip);
1820 break;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001821 case POWER_SUPPLY_PROP_TEMP:
1822 val->intval = get_prop_batt_temp(chip);
1823 break;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001824 case POWER_SUPPLY_PROP_CHARGE_FULL:
1825 val->intval = get_prop_batt_fcc(chip);
1826 break;
1827 case POWER_SUPPLY_PROP_CHARGE_NOW:
1828 val->intval = get_prop_batt_charge_now(chip);
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -07001829 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001830 default:
1831 return -EINVAL;
1832 }
1833
1834 return 0;
1835}
1836
1837static void (*notify_vbus_state_func_ptr)(int);
1838static int usb_chg_current;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839
1840int pm8921_charger_register_vbus_sn(void (*callback)(int))
1841{
1842 pr_debug("%p\n", callback);
1843 notify_vbus_state_func_ptr = callback;
1844 return 0;
1845}
1846EXPORT_SYMBOL_GPL(pm8921_charger_register_vbus_sn);
1847
1848/* this is passed to the hsusb via platform_data msm_otg_pdata */
1849void pm8921_charger_unregister_vbus_sn(void (*callback)(int))
1850{
1851 pr_debug("%p\n", callback);
1852 notify_vbus_state_func_ptr = NULL;
1853}
1854EXPORT_SYMBOL_GPL(pm8921_charger_unregister_vbus_sn);
1855
1856static void notify_usb_of_the_plugin_event(int plugin)
1857{
1858 plugin = !!plugin;
1859 if (notify_vbus_state_func_ptr) {
1860 pr_debug("notifying plugin\n");
1861 (*notify_vbus_state_func_ptr) (plugin);
1862 } else {
1863 pr_debug("unable to notify plugin\n");
1864 }
1865}
1866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867static void __pm8921_charger_vbus_draw(unsigned int mA)
1868{
1869 int i, rc;
David Keitel38bdd4f2012-04-19 15:39:13 -07001870 if (!the_chip) {
1871 pr_err("called before init\n");
1872 return;
1873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001875 if (usb_max_current && mA > usb_max_current) {
1876 pr_debug("restricting usb current to %d instead of %d\n",
1877 usb_max_current, mA);
1878 mA = usb_max_current;
1879 }
1880
1881 if (mA <= 2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 usb_chg_current = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001883 rc = pm_chg_iusbmax_set(the_chip, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884 if (rc) {
David Keitelacf57c82012-03-07 18:48:50 -08001885 pr_err("unable to set iusb to %d rc = %d\n", 0, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 }
1887 rc = pm_chg_usb_suspend_enable(the_chip, 1);
1888 if (rc)
1889 pr_err("fail to set suspend bit rc=%d\n", rc);
1890 } else {
1891 rc = pm_chg_usb_suspend_enable(the_chip, 0);
1892 if (rc)
1893 pr_err("fail to reset suspend bit rc=%d\n", rc);
1894 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
1895 if (usb_ma_table[i].usb_ma <= mA)
1896 break;
1897 }
David Keitel38bdd4f2012-04-19 15:39:13 -07001898
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001899 if (i < 0) {
1900 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1901 mA);
1902 i = 0;
1903 }
1904
Willie Ruan13c972d2012-11-15 11:56:36 -08001905 if (i < 0) {
1906 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
1907 mA);
1908 i = 0;
1909 }
1910
David Keitel38bdd4f2012-04-19 15:39:13 -07001911 /* Check if IUSB_FINE_RES is available */
David Keitel1454bc82012-10-01 11:12:59 -07001912 while ((usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
David Keitel38bdd4f2012-04-19 15:39:13 -07001913 && !the_chip->iusb_fine_res)
1914 i--;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915 if (i < 0)
1916 i = 0;
David Keitelacf57c82012-03-07 18:48:50 -08001917 rc = pm_chg_iusbmax_set(the_chip, i);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07001918 if (rc)
David Keitelacf57c82012-03-07 18:48:50 -08001919 pr_err("unable to set iusb to %d rc = %d\n", i, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920 }
1921}
1922
1923/* USB calls these to tell us how much max usb current the system can draw */
1924void pm8921_charger_vbus_draw(unsigned int mA)
1925{
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001926 int set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927
1928 pr_debug("Enter charge=%d\n", mA);
David Keitelacf57c82012-03-07 18:48:50 -08001929
David Keitel62c6a4b2012-05-17 12:54:59 -07001930 /*
1931 * Reject VBUS requests if USB connection is the only available
1932 * power source. This makes sure that if booting without
1933 * battery the iusb_max value is not decreased avoiding potential
1934 * brown_outs.
1935 *
1936 * This would also apply when the battery has been
1937 * removed from the running system.
1938 */
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001939 if (mA == 0 && the_chip && !get_prop_batt_present(the_chip)
David Keitel62c6a4b2012-05-17 12:54:59 -07001940 && !is_dc_chg_plugged_in(the_chip)) {
David Keitelff4f9ce2012-08-24 15:11:23 -07001941 if (!the_chip->has_dc_supply) {
Abhijeet Dharmapurikar55cf35b2013-02-20 18:40:59 -08001942 pr_err("rejected: no other power source mA = %d\n", mA);
David Keitelff4f9ce2012-08-24 15:11:23 -07001943 return;
1944 }
David Keitel62c6a4b2012-05-17 12:54:59 -07001945 }
1946
David Keitelacf57c82012-03-07 18:48:50 -08001947 if (usb_max_current && mA > usb_max_current) {
1948 pr_warn("restricting usb current to %d instead of %d\n",
1949 usb_max_current, mA);
1950 mA = usb_max_current;
1951 }
Devin Kim2073afb2012-09-05 13:01:51 -07001952 if (usb_target_ma == 0 && mA > USB_WALL_THRESHOLD_MA)
1953 usb_target_ma = mA;
David Keitelacf57c82012-03-07 18:48:50 -08001954
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05301955 if (usb_target_ma)
1956 usb_target_ma = mA;
1957
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001958
1959 if (mA > USB_WALL_THRESHOLD_MA)
1960 set_usb_now_ma = USB_WALL_THRESHOLD_MA;
1961 else
1962 set_usb_now_ma = mA;
1963
1964 if (the_chip && the_chip->disable_aicl)
1965 set_usb_now_ma = mA;
1966
1967 if (the_chip)
1968 __pm8921_charger_vbus_draw(set_usb_now_ma);
1969 else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970 /*
1971 * called before pmic initialized,
1972 * save this value and use it at probe
1973 */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08001974 usb_chg_current = set_usb_now_ma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975}
1976EXPORT_SYMBOL_GPL(pm8921_charger_vbus_draw);
1977
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07001978int pm8921_is_usb_chg_plugged_in(void)
1979{
1980 if (!the_chip) {
1981 pr_err("called before init\n");
1982 return -EINVAL;
1983 }
1984 return is_usb_chg_plugged_in(the_chip);
1985}
1986EXPORT_SYMBOL(pm8921_is_usb_chg_plugged_in);
1987
1988int pm8921_is_dc_chg_plugged_in(void)
1989{
1990 if (!the_chip) {
1991 pr_err("called before init\n");
1992 return -EINVAL;
1993 }
1994 return is_dc_chg_plugged_in(the_chip);
1995}
1996EXPORT_SYMBOL(pm8921_is_dc_chg_plugged_in);
1997
1998int pm8921_is_battery_present(void)
1999{
2000 if (!the_chip) {
2001 pr_err("called before init\n");
2002 return -EINVAL;
2003 }
2004 return get_prop_batt_present(the_chip);
2005}
2006EXPORT_SYMBOL(pm8921_is_battery_present);
2007
Abhijeet Dharmapurikarb2680132012-05-15 16:32:51 -07002008int pm8921_is_batfet_closed(void)
2009{
2010 if (!the_chip) {
2011 pr_err("called before init\n");
2012 return -EINVAL;
2013 }
2014 return is_batfet_closed(the_chip);
2015}
2016EXPORT_SYMBOL(pm8921_is_batfet_closed);
David Keitel012deef2011-12-02 11:49:33 -08002017/*
2018 * Disabling the charge current limit causes current
2019 * current limits to have no monitoring. An adequate charger
2020 * capable of supplying high current while sustaining VIN_MIN
2021 * is required if the limiting is disabled.
2022 */
2023int pm8921_disable_input_current_limit(bool disable)
2024{
2025 if (!the_chip) {
2026 pr_err("called before init\n");
2027 return -EINVAL;
2028 }
2029 if (disable) {
2030 pr_warn("Disabling input current limit!\n");
2031
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002032 return pm_chg_write(the_chip, CHG_BUCK_CTRL_TEST3, 0xF2);
David Keitel012deef2011-12-02 11:49:33 -08002033 }
2034 return 0;
2035}
2036EXPORT_SYMBOL(pm8921_disable_input_current_limit);
2037
David Keitel0789fc62012-06-07 17:43:27 -07002038int pm8917_set_under_voltage_detection_threshold(int mv)
2039{
2040 if (!the_chip) {
2041 pr_err("called before init\n");
2042 return -EINVAL;
2043 }
2044 return pm_chg_uvd_threshold_set(the_chip, mv);
2045}
2046EXPORT_SYMBOL(pm8917_set_under_voltage_detection_threshold);
2047
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002048int pm8921_set_max_battery_charge_current(int ma)
2049{
2050 if (!the_chip) {
2051 pr_err("called before init\n");
2052 return -EINVAL;
2053 }
2054 return pm_chg_ibatmax_set(the_chip, ma);
2055}
2056EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
2057
2058int pm8921_disable_source_current(bool disable)
2059{
2060 if (!the_chip) {
2061 pr_err("called before init\n");
2062 return -EINVAL;
2063 }
2064 if (disable)
2065 pr_warn("current drawn from chg=0, battery provides current\n");
David Keitel0fe15c42012-09-04 09:33:28 -07002066
2067 pm_chg_usb_suspend_enable(the_chip, disable);
2068
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002069 return pm_chg_charge_dis(the_chip, disable);
2070}
2071EXPORT_SYMBOL(pm8921_disable_source_current);
2072
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002073int pm8921_regulate_input_voltage(int voltage)
2074{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002075 int rc;
2076
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002077 if (!the_chip) {
2078 pr_err("called before init\n");
2079 return -EINVAL;
2080 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002081 rc = pm_chg_vinmin_set(the_chip, voltage);
2082
2083 if (rc == 0)
2084 the_chip->vin_min = voltage;
2085
2086 return rc;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07002087}
2088
Abhijeet Dharmapurikar28669302011-12-21 08:31:28 -08002089#define USB_OV_THRESHOLD_MASK 0x60
2090#define USB_OV_THRESHOLD_SHIFT 5
2091int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
2092{
2093 u8 temp;
2094
2095 if (!the_chip) {
2096 pr_err("called before init\n");
2097 return -EINVAL;
2098 }
2099
2100 if (ov > PM_USB_OV_7V) {
2101 pr_err("limiting to over voltage threshold to 7volts\n");
2102 ov = PM_USB_OV_7V;
2103 }
2104
2105 temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
2106
2107 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2108 USB_OV_THRESHOLD_MASK, temp);
2109}
2110EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
2111
2112#define USB_DEBOUNCE_TIME_MASK 0x06
2113#define USB_DEBOUNCE_TIME_SHIFT 1
2114int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
2115{
2116 u8 temp;
2117
2118 if (!the_chip) {
2119 pr_err("called before init\n");
2120 return -EINVAL;
2121 }
2122
2123 if (ms > PM_USB_DEBOUNCE_80P5MS) {
2124 pr_err("limiting debounce to 80.5ms\n");
2125 ms = PM_USB_DEBOUNCE_80P5MS;
2126 }
2127
2128 temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
2129
2130 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2131 USB_DEBOUNCE_TIME_MASK, temp);
2132}
2133EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
2134
2135#define USB_OVP_DISABLE_MASK 0x80
2136int pm8921_usb_ovp_disable(int disable)
2137{
2138 u8 temp = 0;
2139
2140 if (!the_chip) {
2141 pr_err("called before init\n");
2142 return -EINVAL;
2143 }
2144
2145 if (disable)
2146 temp = USB_OVP_DISABLE_MASK;
2147
2148 return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
2149 USB_OVP_DISABLE_MASK, temp);
2150}
2151
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002152bool pm8921_is_battery_charging(int *source)
2153{
2154 int fsm_state, is_charging, dc_present, usb_present;
2155
2156 if (!the_chip) {
2157 pr_err("called before init\n");
2158 return -EINVAL;
2159 }
2160 fsm_state = pm_chg_get_fsm_state(the_chip);
2161 is_charging = is_battery_charging(fsm_state);
2162 if (is_charging == 0) {
2163 *source = PM8921_CHG_SRC_NONE;
2164 return is_charging;
2165 }
2166
2167 if (source == NULL)
2168 return is_charging;
2169
2170 /* the battery is charging, the source is requested, find it */
2171 dc_present = is_dc_chg_plugged_in(the_chip);
2172 usb_present = is_usb_chg_plugged_in(the_chip);
2173
2174 if (dc_present && !usb_present)
2175 *source = PM8921_CHG_SRC_DC;
2176
2177 if (usb_present && !dc_present)
2178 *source = PM8921_CHG_SRC_USB;
2179
2180 if (usb_present && dc_present)
2181 /*
2182 * The system always chooses dc for charging since it has
2183 * higher priority.
2184 */
2185 *source = PM8921_CHG_SRC_DC;
2186
2187 return is_charging;
2188}
2189EXPORT_SYMBOL(pm8921_is_battery_charging);
2190
David Keitel86034022012-04-18 12:33:58 -07002191int pm8921_set_usb_power_supply_type(enum power_supply_type type)
2192{
2193 if (!the_chip) {
2194 pr_err("called before init\n");
2195 return -EINVAL;
2196 }
2197
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002198 if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
David Keitel86034022012-04-18 12:33:58 -07002199 return -EINVAL;
2200
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05302201 the_chip->usb_type = type;
David Keitel86034022012-04-18 12:33:58 -07002202 power_supply_changed(&the_chip->usb_psy);
2203 power_supply_changed(&the_chip->dc_psy);
2204 return 0;
2205}
2206EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
2207
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07002208int pm8921_batt_temperature(void)
2209{
2210 if (!the_chip) {
2211 pr_err("called before init\n");
2212 return -EINVAL;
2213 }
2214 return get_prop_batt_temp(the_chip);
2215}
2216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
2218{
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08002219 int usb_present;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08002221 pm_chg_failed_clear(chip, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002222 usb_present = is_usb_chg_plugged_in(chip);
2223 if (chip->usb_present ^ usb_present) {
2224 notify_usb_of_the_plugin_event(usb_present);
2225 chip->usb_present = usb_present;
2226 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikar0c4bc152011-10-27 10:22:24 -07002227 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarc9ba2712012-02-23 12:42:24 -08002228 pm8921_bms_calibrate_hkadc();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002229 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002230 if (usb_present) {
2231 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002232 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08002233 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
2234 } else {
David Keitelacf57c82012-03-07 18:48:50 -08002235 /* USB unplugged reset target current */
Devin Kim2073afb2012-09-05 13:01:51 -07002236 usb_target_ma = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002237 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002238 }
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002239 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240}
2241
Amir Samuelovd31ef502011-10-26 14:41:36 +02002242static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
2243{
David Keitel88e1b572012-01-11 11:57:14 -08002244 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002245 pr_debug("external charger not registered.\n");
2246 return;
2247 }
2248
2249 if (!chip->ext_charging) {
2250 pr_debug("already not charging.\n");
2251 return;
2252 }
2253
David Keitel88e1b572012-01-11 11:57:14 -08002254 power_supply_set_charge_type(chip->ext_psy,
2255 POWER_SUPPLY_CHARGE_TYPE_NONE);
2256 pm8921_disable_source_current(false); /* release BATFET */
David Keitel63f71662012-02-08 20:30:00 -08002257 power_supply_changed(&chip->dc_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002258 chip->ext_charging = false;
David Keiteld4e59ef2011-11-09 17:38:31 -08002259 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002260 bms_notify_check(chip);
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002261 /* Update battery charging LEDs and user space battery info */
2262 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002263}
2264
2265static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
2266{
2267 int dc_present;
2268 int batt_present;
2269 int batt_temp_ok;
Amir Samuelovd31ef502011-10-26 14:41:36 +02002270 unsigned long delay =
2271 round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
2272
David Keitel88e1b572012-01-11 11:57:14 -08002273 if (!chip->ext_psy) {
Amir Samuelovd31ef502011-10-26 14:41:36 +02002274 pr_debug("external charger not registered.\n");
2275 return;
2276 }
2277
2278 if (chip->ext_charging) {
2279 pr_debug("already charging.\n");
2280 return;
2281 }
2282
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002283 dc_present = is_dc_chg_plugged_in(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002284 batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2285 batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002286
2287 if (!dc_present) {
2288 pr_warn("%s. dc not present.\n", __func__);
2289 return;
2290 }
2291 if (!batt_present) {
2292 pr_warn("%s. battery not present.\n", __func__);
2293 return;
2294 }
2295 if (!batt_temp_ok) {
2296 pr_warn("%s. battery temperature not ok.\n", __func__);
2297 return;
2298 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002299
2300 /* Force BATFET=ON */
2301 pm8921_disable_source_current(true);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002302
David Keitel6ccbf132012-05-30 14:21:24 -07002303 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002304 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
David Keitel6ccbf132012-05-30 14:21:24 -07002305
David Keitel63f71662012-02-08 20:30:00 -08002306 power_supply_set_online(chip->ext_psy, dc_present);
David Keitel88e1b572012-01-11 11:57:14 -08002307 power_supply_set_charge_type(chip->ext_psy,
2308 POWER_SUPPLY_CHARGE_TYPE_FAST);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002309 chip->ext_charging = true;
2310 chip->ext_charge_done = false;
David Keitel88e1b572012-01-11 11:57:14 -08002311 bms_notify_check(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002312 /*
2313 * since we wont get a fastchg irq from external charger
2314 * use eoc worker to detect end of charging
2315 */
Amir Samuelovd31ef502011-10-26 14:41:36 +02002316 schedule_delayed_work(&chip->eoc_work, delay);
2317 wake_lock(&chip->eoc_wake_lock);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002318 if (chip->btc_override)
2319 schedule_delayed_work(&chip->btc_override_work,
2320 round_jiffies_relative(msecs_to_jiffies
2321 (chip->btc_delay_ms)));
Amir Samuelov4ffc8ec2012-05-16 09:38:43 +03002322 /* Update battery charging LEDs and user space battery info */
2323 power_supply_changed(&chip->batt_psy);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002324}
2325
David Keitel6ccbf132012-05-30 14:21:24 -07002326static void turn_off_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002327{
2328 u8 temp;
2329 int rc;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002330
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002331 rc = pm_chg_write(chip, ovptestreg, 0x30);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002332 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002333 pr_err("Failed to write 0x30 to ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002334 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002335 }
David Keitel6ccbf132012-05-30 14:21:24 -07002336 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002337 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002338 pr_err("Failed to read from ovptestreg rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002339 return;
2340 }
2341 /* set ovp fet disable bit and the write bit */
2342 temp |= 0x81;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002343 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002344 if (rc) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002345 pr_err("Failed to write 0x%x ovptestreg rc=%d\n", temp, rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002346 return;
2347 }
2348}
2349
David Keitel6ccbf132012-05-30 14:21:24 -07002350static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
David Keitel8c5201a2012-02-24 16:08:54 -08002351{
2352 u8 temp;
2353 int rc;
2354
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002355 rc = pm_chg_write(chip, ovptestreg, 0x30);
David Keitel8c5201a2012-02-24 16:08:54 -08002356 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002357 pr_err("Failed to write 0x30 to OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002358 return;
2359 }
David Keitel6ccbf132012-05-30 14:21:24 -07002360 rc = pm8xxx_readb(chip->dev->parent, ovptestreg, &temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002361 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002362 pr_err("Failed to read from OVP_TEST rc = %d\n", rc);
David Keitel8c5201a2012-02-24 16:08:54 -08002363 return;
2364 }
2365 /* unset ovp fet disable bit and set the write bit */
2366 temp &= 0xFE;
2367 temp |= 0x80;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002368 rc = pm_chg_write(chip, ovptestreg, temp);
David Keitel8c5201a2012-02-24 16:08:54 -08002369 if (rc) {
David Keitel6ccbf132012-05-30 14:21:24 -07002370 pr_err("Failed to write 0x%x to OVP_TEST rc = %d\n",
David Keitel8c5201a2012-02-24 16:08:54 -08002371 temp, rc);
2372 return;
2373 }
2374}
2375
2376static int param_open_ovp_counter = 10;
2377module_param(param_open_ovp_counter, int, 0644);
2378
David Keitel6ccbf132012-05-30 14:21:24 -07002379#define USB_ACTIVE_BIT BIT(5)
2380#define DC_ACTIVE_BIT BIT(6)
2381static int is_active_chg_plugged_in(struct pm8921_chg_chip *chip,
2382 u8 active_chg_mask)
2383{
2384 if (active_chg_mask & USB_ACTIVE_BIT)
2385 return pm_chg_get_rt_status(chip, USBIN_VALID_IRQ);
2386 else if (active_chg_mask & DC_ACTIVE_BIT)
2387 return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
2388 else
2389 return 0;
2390}
2391
David Keitel8c5201a2012-02-24 16:08:54 -08002392#define WRITE_BANK_4 0xC0
David Keitel6ccbf132012-05-30 14:21:24 -07002393#define OVP_DEBOUNCE_TIME 0x06
David Keitelc3e15bd2012-05-25 17:07:25 -07002394static void unplug_ovp_fet_open(struct pm8921_chg_chip *chip)
David Keitel8c5201a2012-02-24 16:08:54 -08002395{
David Keitel6ccbf132012-05-30 14:21:24 -07002396 int chg_gone = 0, active_chg_plugged_in = 0;
David Keitel8c5201a2012-02-24 16:08:54 -08002397 int count = 0;
David Keitel6ccbf132012-05-30 14:21:24 -07002398 u8 active_mask = 0;
2399 u16 ovpreg, ovptestreg;
2400
2401 if (is_usb_chg_plugged_in(chip) &&
2402 (chip->active_path & USB_ACTIVE_BIT)) {
2403 ovpreg = USB_OVP_CONTROL;
2404 ovptestreg = USB_OVP_TEST;
2405 active_mask = USB_ACTIVE_BIT;
2406 } else if (is_dc_chg_plugged_in(chip) &&
2407 (chip->active_path & DC_ACTIVE_BIT)) {
2408 ovpreg = DC_OVP_CONTROL;
2409 ovptestreg = DC_OVP_TEST;
2410 active_mask = DC_ACTIVE_BIT;
2411 } else {
2412 return;
2413 }
David Keitel8c5201a2012-02-24 16:08:54 -08002414
2415 while (count++ < param_open_ovp_counter) {
David Keitel6ccbf132012-05-30 14:21:24 -07002416 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x0);
David Keitel8c5201a2012-02-24 16:08:54 -08002417 usleep(10);
David Keitel6ccbf132012-05-30 14:21:24 -07002418 active_chg_plugged_in
2419 = is_active_chg_plugged_in(chip, active_mask);
David Keitel8c5201a2012-02-24 16:08:54 -08002420 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
David Keitel6ccbf132012-05-30 14:21:24 -07002421 pr_debug("OVP FET count = %d chg_gone=%d, active_valid = %d\n",
2422 count, chg_gone, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002423
2424 /* note usb_chg_plugged_in=0 => chg_gone=1 */
David Keitel6ccbf132012-05-30 14:21:24 -07002425 if (chg_gone == 1 && active_chg_plugged_in == 1) {
David Keitel8c5201a2012-02-24 16:08:54 -08002426 pr_debug("since chg_gone = 1 dis ovp_fet for 20msec\n");
David Keitel6ccbf132012-05-30 14:21:24 -07002427 turn_off_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002428
2429 msleep(20);
2430
David Keitel6ccbf132012-05-30 14:21:24 -07002431 turn_on_ovp_fet(chip, ovptestreg);
David Keitel8c5201a2012-02-24 16:08:54 -08002432 } else {
David Keitel712782e2012-03-29 14:11:47 -07002433 break;
David Keitel8c5201a2012-02-24 16:08:54 -08002434 }
2435 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002436 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
2437 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x6);
2438 else
2439 pm_chg_masked_write(chip, ovpreg, OVP_DEBOUNCE_TIME, 0x2);
2440
David Keitel6ccbf132012-05-30 14:21:24 -07002441 pr_debug("Exit count=%d chg_gone=%d, active_valid=%d\n",
2442 count, chg_gone, active_chg_plugged_in);
David Keitel712782e2012-03-29 14:11:47 -07002443 return;
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002444}
David Keitelacf57c82012-03-07 18:48:50 -08002445
2446static int find_usb_ma_value(int value)
2447{
2448 int i;
2449
2450 for (i = ARRAY_SIZE(usb_ma_table) - 1; i >= 0; i--) {
2451 if (value >= usb_ma_table[i].usb_ma)
2452 break;
2453 }
2454
2455 return i;
2456}
2457
2458static void decrease_usb_ma_value(int *value)
2459{
2460 int i;
2461
2462 if (value) {
2463 i = find_usb_ma_value(*value);
2464 if (i > 0)
2465 i--;
David Keitelc7bba2f2012-06-15 17:05:52 -07002466 while (!the_chip->iusb_fine_res && i > 0
2467 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES))
2468 i--;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002469
2470 if (i < 0) {
2471 pr_err("can't find %dmA in usb_ma_table. Use min.\n",
2472 *value);
2473 i = 0;
2474 }
2475
David Keitelacf57c82012-03-07 18:48:50 -08002476 *value = usb_ma_table[i].usb_ma;
2477 }
2478}
2479
2480static void increase_usb_ma_value(int *value)
2481{
2482 int i;
2483
2484 if (value) {
2485 i = find_usb_ma_value(*value);
2486
2487 if (i < (ARRAY_SIZE(usb_ma_table) - 1))
2488 i++;
David Keitel38bdd4f2012-04-19 15:39:13 -07002489 /* Get next correct entry if IUSB_FINE_RES is not available */
2490 while (!the_chip->iusb_fine_res
2491 && (usb_ma_table[i].value & PM8917_IUSB_FINE_RES)
2492 && i < (ARRAY_SIZE(usb_ma_table) - 1))
2493 i++;
2494
David Keitelacf57c82012-03-07 18:48:50 -08002495 *value = usb_ma_table[i].usb_ma;
2496 }
2497}
2498
2499static void vin_collapse_check_worker(struct work_struct *work)
2500{
2501 struct delayed_work *dwork = to_delayed_work(work);
2502 struct pm8921_chg_chip *chip = container_of(dwork,
2503 struct pm8921_chg_chip, vin_collapse_check_work);
2504
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002505 /*
2506 * AICL only for wall-chargers. If the charger appears to be plugged
2507 * back in now, the corresponding unplug must have been because of we
2508 * were trying to draw more current than the charger can support. In
2509 * such a case reset usb current to 500mA and decrease the target.
2510 * The AICL algorithm will step up the current from 500mA to target
2511 */
2512 if (is_usb_chg_plugged_in(chip)
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002513 && usb_target_ma > USB_WALL_THRESHOLD_MA
2514 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002515 /* decrease usb_target_ma */
2516 decrease_usb_ma_value(&usb_target_ma);
2517 /* reset here, increase in unplug_check_worker */
2518 __pm8921_charger_vbus_draw(USB_WALL_THRESHOLD_MA);
2519 pr_debug("usb_now=%d, usb_target = %d\n",
2520 USB_WALL_THRESHOLD_MA, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002521 if (!delayed_work_pending(&chip->unplug_check_work))
2522 schedule_delayed_work(&chip->unplug_check_work,
2523 msecs_to_jiffies
2524 (UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitelacf57c82012-03-07 18:48:50 -08002525 } else {
2526 handle_usb_insertion_removal(chip);
2527 }
2528}
2529
2530#define VIN_MIN_COLLAPSE_CHECK_MS 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
2532{
David Keitelacf57c82012-03-07 18:48:50 -08002533 if (usb_target_ma)
2534 schedule_delayed_work(&the_chip->vin_collapse_check_work,
2535 round_jiffies_relative(msecs_to_jiffies
2536 (VIN_MIN_COLLAPSE_CHECK_MS)));
2537 else
2538 handle_usb_insertion_removal(data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 return IRQ_HANDLED;
2540}
2541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
2543{
2544 struct pm8921_chg_chip *chip = data;
2545 int status;
2546
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07002547 status = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
2548 schedule_work(&chip->battery_id_valid_work);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002549 handle_start_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 pr_debug("battery present=%d", status);
2551 power_supply_changed(&chip->batt_psy);
2552 return IRQ_HANDLED;
2553}
Amir Samuelovd31ef502011-10-26 14:41:36 +02002554
2555/*
2556 * this interrupt used to restart charging a battery.
2557 *
2558 * Note: When DC-inserted the VBAT can't go low.
2559 * VPH_PWR is provided by the ext-charger.
2560 * After End-Of-Charging from DC, charging can be resumed only
2561 * if DC is removed and then inserted after the battery was in use.
2562 * Therefore the handle_start_ext_chg() is not called.
2563 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
2565{
2566 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002567 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002569 high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
Abhijeet Dharmapurikar07e48bf2011-09-26 19:46:40 -07002570
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002571 if (high_transition) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002572 /* enable auto charging */
2573 pm_chg_auto_enable(chip, !charging_disabled);
2574 pr_info("batt fell below resume voltage %s\n",
2575 charging_disabled ? "" : "charger enabled");
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002576 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 power_supply_changed(&chip->batt_psy);
2580 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002581 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002582
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 return IRQ_HANDLED;
2584}
2585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586static irqreturn_t chgwdog_irq_handler(int irq, void *data)
2587{
2588 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2589 return IRQ_HANDLED;
2590}
2591
2592static irqreturn_t vcp_irq_handler(int irq, void *data)
2593{
David Keitel8c5201a2012-02-24 16:08:54 -08002594 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595 return IRQ_HANDLED;
2596}
2597
2598static irqreturn_t atcdone_irq_handler(int irq, void *data)
2599{
2600 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2601 return IRQ_HANDLED;
2602}
2603
2604static irqreturn_t atcfail_irq_handler(int irq, void *data)
2605{
2606 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2607 return IRQ_HANDLED;
2608}
2609
2610static irqreturn_t chgdone_irq_handler(int irq, void *data)
2611{
2612 struct pm8921_chg_chip *chip = data;
2613
2614 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002615
2616 handle_stop_ext_chg(chip);
2617
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 power_supply_changed(&chip->batt_psy);
2619 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002620 power_supply_changed(&chip->dc_psy);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002621
Abhijeet Dharmapurikarfad72352011-09-25 23:06:05 -07002622 bms_notify_check(chip);
2623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002624 return IRQ_HANDLED;
2625}
2626
2627static irqreturn_t chgfail_irq_handler(int irq, void *data)
2628{
2629 struct pm8921_chg_chip *chip = data;
David Keitel753ec8d2011-11-02 10:56:37 -07002630 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002631
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002632 if (!chip->stop_chg_upon_expiry) {
2633 ret = pm_chg_failed_clear(chip, 1);
2634 if (ret)
2635 pr_err("Failed to write CHG_FAILED_CLEAR bit\n");
2636 }
David Keitel753ec8d2011-11-02 10:56:37 -07002637
2638 pr_err("batt_present = %d, batt_temp_ok = %d, state_changed_to=%d\n",
2639 get_prop_batt_present(chip),
2640 pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ),
2641 pm_chg_get_fsm_state(data));
2642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 power_supply_changed(&chip->batt_psy);
2644 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002645 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646 return IRQ_HANDLED;
2647}
2648
2649static irqreturn_t chgstate_irq_handler(int irq, void *data)
2650{
2651 struct pm8921_chg_chip *chip = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002652
2653 pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
2654 power_supply_changed(&chip->batt_psy);
2655 power_supply_changed(&chip->usb_psy);
David Keitel63f71662012-02-08 20:30:00 -08002656 power_supply_changed(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002658 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 return IRQ_HANDLED;
2661}
2662
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002663enum {
2664 PON_TIME_25NS = 0x04,
2665 PON_TIME_50NS = 0x08,
2666 PON_TIME_100NS = 0x0C,
2667};
David Keitel8c5201a2012-02-24 16:08:54 -08002668
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002669static void set_min_pon_time(struct pm8921_chg_chip *chip, int pon_time_ns)
David Keitel8c5201a2012-02-24 16:08:54 -08002670{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002671 u8 temp;
2672 int rc;
David Keitel8c5201a2012-02-24 16:08:54 -08002673
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002674 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x40);
2675 if (rc) {
2676 pr_err("Failed to write 0x70 to CTRL_TEST3 rc = %d\n", rc);
2677 return;
2678 }
2679 rc = pm8xxx_readb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, &temp);
2680 if (rc) {
2681 pr_err("Failed to read CTRL_TEST3 rc = %d\n", rc);
2682 return;
2683 }
2684 /* clear the min pon time select bit */
2685 temp &= 0xF3;
2686 /* set the pon time */
2687 temp |= (u8)pon_time_ns;
2688 /* write enable bank 4 */
2689 temp |= 0x80;
2690 rc = pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, temp);
2691 if (rc) {
2692 pr_err("Failed to write 0x%x to CTRL_TEST3 rc=%d\n", temp, rc);
2693 return;
2694 }
2695}
David Keitel8c5201a2012-02-24 16:08:54 -08002696
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002697static void attempt_reverse_boost_fix(struct pm8921_chg_chip *chip)
2698{
2699 pr_debug("Start\n");
2700 set_min_pon_time(chip, PON_TIME_100NS);
2701 pm_chg_vinmin_set(chip, chip->vin_min + 200);
2702 msleep(250);
2703 pm_chg_vinmin_set(chip, chip->vin_min);
2704 set_min_pon_time(chip, PON_TIME_25NS);
2705 pr_debug("End\n");
David Keitel8c5201a2012-02-24 16:08:54 -08002706}
2707
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002708#define VIN_ACTIVE_BIT BIT(0)
David Keitel6ccbf132012-05-30 14:21:24 -07002709#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
2710#define VIN_MIN_INCREASE_MV 100
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002711static void unplug_check_worker(struct work_struct *work)
2712{
2713 struct delayed_work *dwork = to_delayed_work(work);
2714 struct pm8921_chg_chip *chip = container_of(dwork,
2715 struct pm8921_chg_chip, unplug_check_work);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002716 u8 reg_loop = 0, active_path;
David Keitel6ccbf132012-05-30 14:21:24 -07002717 int rc, ibat, active_chg_plugged_in, usb_ma;
David Keitel8c5201a2012-02-24 16:08:54 -08002718 int chg_gone = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002719 bool ramp = false;
David Keitel6ccbf132012-05-30 14:21:24 -07002720
2721 rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
2722 if (rc) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002723 pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
2724 return;
David Keitel6ccbf132012-05-30 14:21:24 -07002725 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002726
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002727 chip->active_path = active_path;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002728 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002729 pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
2730 active_path, active_chg_plugged_in);
2731 if (active_path & USB_ACTIVE_BIT) {
2732 pr_debug("USB charger active\n");
2733
2734 pm_chg_iusbmax_get(chip, &usb_ma);
Devin Kim2073afb2012-09-05 13:01:51 -07002735
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002736 if (usb_ma <= 100) {
2737 pr_debug(
2738 "Unenumerated or suspended usb_ma = %d skip\n",
2739 usb_ma);
2740 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002741 }
2742 } else if (active_path & DC_ACTIVE_BIT) {
2743 pr_debug("DC charger active\n");
2744 } else {
2745 /* No charger active */
2746 if (!(is_usb_chg_plugged_in(chip)
2747 && !(is_dc_chg_plugged_in(chip)))) {
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002748 pr_debug(
David Keitel6ccbf132012-05-30 14:21:24 -07002749 "Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
2750 pm_chg_get_regulation_loop(chip),
2751 pm_chg_get_fsm_state(chip),
2752 get_prop_batt_current(chip)
2753 );
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002754 return;
2755 } else {
2756 goto check_again_later;
David Keitel6ccbf132012-05-30 14:21:24 -07002757 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002758 }
David Keitel8c5201a2012-02-24 16:08:54 -08002759
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002760 /* AICL only for usb wall charger */
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002761 if ((active_path & USB_ACTIVE_BIT) && usb_target_ma > 0 &&
2762 !chip->disable_aicl) {
David Keitel6ccbf132012-05-30 14:21:24 -07002763 reg_loop = pm_chg_get_regulation_loop(chip);
2764 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2765 if ((reg_loop & VIN_ACTIVE_BIT) &&
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002766 (usb_ma > USB_WALL_THRESHOLD_MA)
2767 && !charging_disabled) {
David Keitel6ccbf132012-05-30 14:21:24 -07002768 decrease_usb_ma_value(&usb_ma);
2769 usb_target_ma = usb_ma;
2770 /* end AICL here */
2771 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002772 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitel6ccbf132012-05-30 14:21:24 -07002773 usb_ma, usb_target_ma);
2774 }
David Keitelacf57c82012-03-07 18:48:50 -08002775 }
2776
2777 reg_loop = pm_chg_get_regulation_loop(chip);
2778 pr_debug("reg_loop=0x%x usb_ma = %d\n", reg_loop, usb_ma);
2779
David Keitel6ccbf132012-05-30 14:21:24 -07002780 ibat = get_prop_batt_current(chip);
David Keitelacf57c82012-03-07 18:48:50 -08002781 if (reg_loop & VIN_ACTIVE_BIT) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002782 if (ibat > 0) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002783 pr_debug("revboost ibat = %d fsm = %d loop = 0x%x\n",
2784 ibat, pm_chg_get_fsm_state(chip), reg_loop);
2785 attempt_reverse_boost_fix(chip);
2786 /* after reverse boost fix check if the active
2787 * charger was detected as removed */
2788 active_chg_plugged_in
2789 = is_active_chg_plugged_in(chip,
2790 active_path);
2791 pr_debug("revboost post: active_chg_plugged_in = %d\n",
2792 active_chg_plugged_in);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002793 }
2794 }
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002795
2796 active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
David Keitel6ccbf132012-05-30 14:21:24 -07002797 pr_debug("active_path = 0x%x, active_chg = %d\n",
2798 active_path, active_chg_plugged_in);
David Keitel8c5201a2012-02-24 16:08:54 -08002799 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2800
David Keitel6ccbf132012-05-30 14:21:24 -07002801 if (chg_gone == 1 && active_chg_plugged_in == 1) {
2802 pr_debug("chg_gone=%d, active_chg_plugged_in = %d\n",
2803 chg_gone, active_chg_plugged_in);
David Keitelc3e15bd2012-05-25 17:07:25 -07002804 unplug_ovp_fet_open(chip);
David Keitel8c5201a2012-02-24 16:08:54 -08002805 }
2806
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002807 /* AICL only for usb wall charger */
2808 if (!(reg_loop & VIN_ACTIVE_BIT) && (active_path & USB_ACTIVE_BIT)
2809 && usb_target_ma > 0
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08002810 && !charging_disabled
2811 && !chip->disable_aicl) {
David Keitelacf57c82012-03-07 18:48:50 -08002812 /* only increase iusb_max if vin loop not active */
2813 if (usb_ma < usb_target_ma) {
2814 increase_usb_ma_value(&usb_ma);
Anirudh Ghayal0ddca632013-01-23 16:43:31 +05302815 if (usb_ma > usb_target_ma)
2816 usb_ma = usb_target_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002817 __pm8921_charger_vbus_draw(usb_ma);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002818 pr_debug("usb_now=%d, usb_target = %d\n",
David Keitelacf57c82012-03-07 18:48:50 -08002819 usb_ma, usb_target_ma);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002820 ramp = true;
Devin Kim2073afb2012-09-05 13:01:51 -07002821 } else {
2822 usb_target_ma = usb_ma;
David Keitelacf57c82012-03-07 18:48:50 -08002823 }
2824 }
Devin Kim2073afb2012-09-05 13:01:51 -07002825check_again_later:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002826 pr_debug("ramp: %d\n", ramp);
David Keitelacf57c82012-03-07 18:48:50 -08002827 /* schedule to check again later */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002828 if (ramp)
2829 schedule_delayed_work(&chip->unplug_check_work,
2830 msecs_to_jiffies(UNPLUG_CHECK_RAMP_MS));
2831 else
2832 schedule_delayed_work(&chip->unplug_check_work,
2833 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002834}
2835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836static irqreturn_t loop_change_irq_handler(int irq, void *data)
2837{
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08002838 struct pm8921_chg_chip *chip = data;
2839
2840 pr_debug("fsm_state=%d reg_loop=0x%x\n",
2841 pm_chg_get_fsm_state(data),
2842 pm_chg_get_regulation_loop(data));
David Keitelb57db9e2012-03-28 16:08:43 -07002843 schedule_work(&chip->unplug_check_work.work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 return IRQ_HANDLED;
2845}
2846
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002847struct ibatmax_max_adj_entry {
2848 int ibat_max_ma;
2849 int max_adj_ma;
2850};
2851
2852static struct ibatmax_max_adj_entry ibatmax_adj_table[] = {
2853 {975, 300},
2854 {1475, 150},
2855 {1975, 200},
2856 {2475, 250},
2857};
2858
2859static int find_ibat_max_adj_ma(int ibat_target_ma)
2860{
2861 int i = 0;
2862
Abhijeet Dharmapurikare7e27af2013-02-12 14:44:04 -08002863 for (i = ARRAY_SIZE(ibatmax_adj_table); i > 0; i--) {
2864 if (ibat_target_ma >= ibatmax_adj_table[i - 1].ibat_max_ma)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002865 break;
2866 }
2867
2868 return ibatmax_adj_table[i].max_adj_ma;
2869}
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871static irqreturn_t fastchg_irq_handler(int irq, void *data)
2872{
2873 struct pm8921_chg_chip *chip = data;
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002874 int high_transition;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002875
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002876 high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
2877 if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
2878 wake_lock(&chip->eoc_wake_lock);
2879 schedule_delayed_work(&chip->eoc_work,
2880 round_jiffies_relative(msecs_to_jiffies
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07002881 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002882 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07002883 if (high_transition
2884 && chip->btc_override
2885 && !delayed_work_pending(&chip->btc_override_work)) {
2886 schedule_delayed_work(&chip->btc_override_work,
2887 round_jiffies_relative(msecs_to_jiffies
2888 (chip->btc_delay_ms)));
2889 }
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07002890 power_supply_changed(&chip->batt_psy);
2891 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892 return IRQ_HANDLED;
2893}
2894
2895static irqreturn_t trklchg_irq_handler(int irq, void *data)
2896{
2897 struct pm8921_chg_chip *chip = data;
2898
2899 power_supply_changed(&chip->batt_psy);
2900 return IRQ_HANDLED;
2901}
2902
2903static irqreturn_t batt_removed_irq_handler(int irq, void *data)
2904{
2905 struct pm8921_chg_chip *chip = data;
2906 int status;
2907
2908 status = pm_chg_get_rt_status(chip, BATT_REMOVED_IRQ);
2909 pr_debug("battery present=%d state=%d", !status,
2910 pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002911 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 power_supply_changed(&chip->batt_psy);
2913 return IRQ_HANDLED;
2914}
2915
2916static irqreturn_t batttemp_hot_irq_handler(int irq, void *data)
2917{
2918 struct pm8921_chg_chip *chip = data;
2919
Amir Samuelovd31ef502011-10-26 14:41:36 +02002920 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002921 power_supply_changed(&chip->batt_psy);
2922 return IRQ_HANDLED;
2923}
2924
2925static irqreturn_t chghot_irq_handler(int irq, void *data)
2926{
2927 struct pm8921_chg_chip *chip = data;
2928
2929 pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
2930 power_supply_changed(&chip->batt_psy);
2931 power_supply_changed(&chip->usb_psy);
David Keitel88e1b572012-01-11 11:57:14 -08002932 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933 return IRQ_HANDLED;
2934}
2935
2936static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
2937{
2938 struct pm8921_chg_chip *chip = data;
2939
2940 pr_debug("Batt cold fsm_state=%d\n", pm_chg_get_fsm_state(data));
Amir Samuelovd31ef502011-10-26 14:41:36 +02002941 handle_stop_ext_chg(chip);
2942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 power_supply_changed(&chip->batt_psy);
2944 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 return IRQ_HANDLED;
2946}
2947
2948static irqreturn_t chg_gone_irq_handler(int irq, void *data)
2949{
2950 struct pm8921_chg_chip *chip = data;
David Keitelc3e15bd2012-05-25 17:07:25 -07002951 int chg_gone, usb_chg_plugged_in;
David Keitel8c5201a2012-02-24 16:08:54 -08002952
2953 usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
2954 chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
2955
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08002956 pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
2957 pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
David Keitel0873d0f2012-03-29 11:44:49 -07002958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959 power_supply_changed(&chip->batt_psy);
2960 power_supply_changed(&chip->usb_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 return IRQ_HANDLED;
2962}
David Keitel52fda532011-11-10 10:43:44 -08002963/*
2964 *
2965 * bat_temp_ok_irq_handler - is edge triggered, hence it will
2966 * fire for two cases:
2967 *
2968 * If the interrupt line switches to high temperature is okay
2969 * and thus charging begins.
2970 * If bat_temp_ok is low this means the temperature is now
2971 * too hot or cold, so charging is stopped.
2972 *
2973 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002974static irqreturn_t bat_temp_ok_irq_handler(int irq, void *data)
2975{
David Keitel52fda532011-11-10 10:43:44 -08002976 int bat_temp_ok;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977 struct pm8921_chg_chip *chip = data;
2978
David Keitel52fda532011-11-10 10:43:44 -08002979 bat_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
2980
2981 pr_debug("batt_temp_ok = %d fsm_state%d\n",
2982 bat_temp_ok, pm_chg_get_fsm_state(data));
2983
2984 if (bat_temp_ok)
2985 handle_start_ext_chg(chip);
2986 else
2987 handle_stop_ext_chg(chip);
Amir Samuelovd31ef502011-10-26 14:41:36 +02002988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 power_supply_changed(&chip->batt_psy);
2990 power_supply_changed(&chip->usb_psy);
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07002991 bms_notify_check(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992 return IRQ_HANDLED;
2993}
2994
2995static irqreturn_t coarse_det_low_irq_handler(int irq, void *data)
2996{
2997 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
2998 return IRQ_HANDLED;
2999}
3000
3001static irqreturn_t vdd_loop_irq_handler(int irq, void *data)
3002{
3003 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3004 return IRQ_HANDLED;
3005}
3006
3007static irqreturn_t vreg_ov_irq_handler(int irq, void *data)
3008{
3009 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3010 return IRQ_HANDLED;
3011}
3012
3013static irqreturn_t vbatdet_irq_handler(int irq, void *data)
3014{
3015 pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
3016 return IRQ_HANDLED;
3017}
3018
3019static irqreturn_t batfet_irq_handler(int irq, void *data)
3020{
3021 struct pm8921_chg_chip *chip = data;
3022
3023 pr_debug("vreg ov\n");
3024 power_supply_changed(&chip->batt_psy);
3025 return IRQ_HANDLED;
3026}
3027
3028static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
3029{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003030 struct pm8921_chg_chip *chip = data;
David Keitel88e1b572012-01-11 11:57:14 -08003031 int dc_present;
Amir Samuelovd31ef502011-10-26 14:41:36 +02003032
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003033 pm_chg_failed_clear(chip, 1);
David Keitel88e1b572012-01-11 11:57:14 -08003034 dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003035
3036 if (chip->dc_present ^ dc_present)
3037 pm8921_bms_calibrate_hkadc();
3038
David Keitel88e1b572012-01-11 11:57:14 -08003039 if (dc_present)
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003040 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
David Keitel88e1b572012-01-11 11:57:14 -08003041 else
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003042 pm8921_chg_disable_irq(chip, CHG_GONE_IRQ);
3043
3044 chip->dc_present = dc_present;
3045
3046 if (chip->ext_psy) {
3047 if (dc_present)
3048 handle_start_ext_chg(chip);
3049 else
3050 handle_stop_ext_chg(chip);
3051 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003052 if (dc_present)
3053 schedule_delayed_work(&chip->unplug_check_work,
3054 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
3055 power_supply_changed(&chip->dc_psy);
3056 }
3057
3058 power_supply_changed(&chip->batt_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059 return IRQ_HANDLED;
3060}
3061
3062static irqreturn_t dcin_ov_irq_handler(int irq, void *data)
3063{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003064 struct pm8921_chg_chip *chip = data;
3065
Amir Samuelovd31ef502011-10-26 14:41:36 +02003066 handle_stop_ext_chg(chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003067 return IRQ_HANDLED;
3068}
3069
3070static irqreturn_t dcin_uv_irq_handler(int irq, void *data)
3071{
Amir Samuelovd31ef502011-10-26 14:41:36 +02003072 struct pm8921_chg_chip *chip = data;
3073
Amir Samuelovd31ef502011-10-26 14:41:36 +02003074 handle_stop_ext_chg(chip);
3075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 return IRQ_HANDLED;
3077}
3078
David Keitel88e1b572012-01-11 11:57:14 -08003079static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
3080{
3081 struct power_supply *psy = &the_chip->batt_psy;
3082 struct power_supply *epsy = dev_get_drvdata(dev);
3083 int i, dcin_irq;
3084
3085 /* Only search for external supply if none is registered */
3086 if (!the_chip->ext_psy) {
3087 dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
3088 for (i = 0; i < epsy->num_supplicants; i++) {
3089 if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
3090 if (!strncmp(epsy->name, "dc", 2)) {
3091 the_chip->ext_psy = epsy;
3092 dcin_valid_irq_handler(dcin_irq,
3093 the_chip);
3094 }
3095 }
3096 }
3097 }
3098 return 0;
3099}
3100
3101static void pm_batt_external_power_changed(struct power_supply *psy)
3102{
3103 /* Only look for an external supply if it hasn't been registered */
3104 if (!the_chip->ext_psy)
3105 class_for_each_device(power_supply_class, NULL, psy,
3106 __pm_batt_external_power_changed_work);
3107}
3108
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003109/**
3110 * update_heartbeat - internal function to update userspace
3111 * per update_time minutes
3112 *
3113 */
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003114#define LOW_SOC_HEARTBEAT_MS 20000
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003115static void update_heartbeat(struct work_struct *work)
3116{
3117 struct delayed_work *dwork = to_delayed_work(work);
3118 struct pm8921_chg_chip *chip = container_of(dwork,
3119 struct pm8921_chg_chip, update_heartbeat_work);
3120
3121 power_supply_changed(&chip->batt_psy);
Abhijeet Dharmapurikarde9c7e72012-07-15 16:29:51 -07003122 if (chip->recent_reported_soc <= 20)
3123 schedule_delayed_work(&chip->update_heartbeat_work,
3124 round_jiffies_relative(msecs_to_jiffies
3125 (LOW_SOC_HEARTBEAT_MS)));
3126 else
3127 schedule_delayed_work(&chip->update_heartbeat_work,
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003128 round_jiffies_relative(msecs_to_jiffies
3129 (chip->update_time)));
3130}
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003131#define VDD_LOOP_ACTIVE_BIT BIT(3)
3132#define VDD_MAX_INCREASE_MV 400
3133static int vdd_max_increase_mv = VDD_MAX_INCREASE_MV;
3134module_param(vdd_max_increase_mv, int, 0644);
3135
3136static int ichg_threshold_ua = -400000;
3137module_param(ichg_threshold_ua, int, 0644);
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003138
3139#define PM8921_CHG_VDDMAX_RES_MV 10
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003140static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip,
3141 int vbat_batt_terminal_uv)
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003142{
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003143 int adj_vdd_max_mv, programmed_vdd_max;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003144 int vbat_batt_terminal_mv;
3145 int reg_loop;
3146 int delta_mv = 0;
3147
3148 if (chip->rconn_mohm == 0) {
3149 pr_debug("Exiting as rconn_mohm is 0\n");
3150 return;
3151 }
3152 /* adjust vdd_max only in normal temperature zone */
3153 if (chip->is_bat_cool || chip->is_bat_warm) {
3154 pr_debug("Exiting is_bat_cool = %d is_batt_warm = %d\n",
3155 chip->is_bat_cool, chip->is_bat_warm);
3156 return;
3157 }
3158
3159 reg_loop = pm_chg_get_regulation_loop(chip);
3160 if (!(reg_loop & VDD_LOOP_ACTIVE_BIT)) {
3161 pr_debug("Exiting Vdd loop is not active reg loop=0x%x\n",
3162 reg_loop);
3163 return;
3164 }
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003165 vbat_batt_terminal_mv = vbat_batt_terminal_uv/1000;
3166 pm_chg_vddmax_get(the_chip, &programmed_vdd_max);
3167
3168 delta_mv = chip->max_voltage_mv - vbat_batt_terminal_mv;
3169
3170 adj_vdd_max_mv = programmed_vdd_max + delta_mv;
3171 pr_debug("vdd_max needs to be changed by %d mv from %d to %d\n",
3172 delta_mv,
3173 programmed_vdd_max,
3174 adj_vdd_max_mv);
3175
3176 if (adj_vdd_max_mv < chip->max_voltage_mv) {
3177 pr_debug("adj vdd_max lower than default max voltage\n");
3178 return;
3179 }
3180
Abhijeet Dharmapurikardc3323a2012-08-10 15:47:31 -07003181 adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
3182 * PM8921_CHG_VDDMAX_RES_MV;
3183
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003184 if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
3185 adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003186 pr_debug("adjusting vdd_max_mv to %d to make "
3187 "vbat_batt_termial_uv = %d to %d\n",
3188 adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
3189 pm_chg_vddmax_set(chip, adj_vdd_max_mv);
3190}
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07003191
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003192static void set_appropriate_vbatdet(struct pm8921_chg_chip *chip)
3193{
3194 if (chip->is_bat_cool)
3195 pm_chg_vbatdet_set(the_chip,
3196 the_chip->cool_bat_voltage
3197 - the_chip->resume_voltage_delta);
3198 else if (chip->is_bat_warm)
3199 pm_chg_vbatdet_set(the_chip,
3200 the_chip->warm_bat_voltage
3201 - the_chip->resume_voltage_delta);
3202 else
3203 pm_chg_vbatdet_set(the_chip,
3204 the_chip->max_voltage_mv
3205 - the_chip->resume_voltage_delta);
3206}
3207
3208static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
3209{
3210 unsigned int chg_current = chip->max_bat_chg_current;
3211
3212 if (chip->is_bat_cool)
3213 chg_current = min(chg_current, chip->cool_bat_chg_current);
3214
3215 if (chip->is_bat_warm)
3216 chg_current = min(chg_current, chip->warm_bat_chg_current);
3217
3218 if (thermal_mitigation != 0 && chip->thermal_mitigation)
3219 chg_current = min(chg_current,
3220 chip->thermal_mitigation[thermal_mitigation]);
3221
3222 pm_chg_ibatmax_set(the_chip, chg_current);
3223}
3224
3225#define TEMP_HYSTERISIS_DECIDEGC 20
3226static void battery_cool(bool enter)
3227{
3228 pr_debug("enter = %d\n", enter);
3229 if (enter == the_chip->is_bat_cool)
3230 return;
3231 the_chip->is_bat_cool = enter;
3232 if (enter)
3233 pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
3234 else
3235 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3236 set_appropriate_battery_current(the_chip);
3237 set_appropriate_vbatdet(the_chip);
3238}
3239
3240static void battery_warm(bool enter)
3241{
3242 pr_debug("enter = %d\n", enter);
3243 if (enter == the_chip->is_bat_warm)
3244 return;
3245 the_chip->is_bat_warm = enter;
3246 if (enter)
3247 pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
3248 else
3249 pm_chg_vddmax_set(the_chip, the_chip->max_voltage_mv);
3250
3251 set_appropriate_battery_current(the_chip);
3252 set_appropriate_vbatdet(the_chip);
3253}
3254
3255static void check_temp_thresholds(struct pm8921_chg_chip *chip)
3256{
3257 int temp = 0;
3258
3259 temp = get_prop_batt_temp(chip);
3260 pr_debug("temp = %d, warm_thr_temp = %d, cool_thr_temp = %d\n",
3261 temp, chip->warm_temp_dc,
3262 chip->cool_temp_dc);
3263
3264 if (chip->warm_temp_dc != INT_MIN) {
3265 if (chip->is_bat_warm
3266 && temp < chip->warm_temp_dc - TEMP_HYSTERISIS_DECIDEGC)
3267 battery_warm(false);
3268 else if (!chip->is_bat_warm && temp >= chip->warm_temp_dc)
3269 battery_warm(true);
3270 }
3271
3272 if (chip->cool_temp_dc != INT_MIN) {
3273 if (chip->is_bat_cool
3274 && temp > chip->cool_temp_dc + TEMP_HYSTERISIS_DECIDEGC)
3275 battery_cool(false);
3276 else if (!chip->is_bat_cool && temp <= chip->cool_temp_dc)
3277 battery_cool(true);
3278 }
3279}
3280
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003281enum {
3282 CHG_IN_PROGRESS,
3283 CHG_NOT_IN_PROGRESS,
3284 CHG_FINISHED,
3285};
3286
3287#define VBAT_TOLERANCE_MV 70
3288#define CHG_DISABLE_MSLEEP 100
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003289static int is_charging_finished(struct pm8921_chg_chip *chip,
3290 int vbat_batt_terminal_uv, int ichg_meas_ma)
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003291{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003292 int vbat_programmed, iterm_programmed, vbat_intended;
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003293 int regulation_loop, fast_chg, vcp;
3294 int rc;
3295 static int last_vbat_programmed = -EINVAL;
3296
3297 if (!is_ext_charging(chip)) {
3298 /* return if the battery is not being fastcharged */
3299 fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3300 pr_debug("fast_chg = %d\n", fast_chg);
3301 if (fast_chg == 0)
3302 return CHG_NOT_IN_PROGRESS;
3303
3304 vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
3305 pr_debug("vcp = %d\n", vcp);
3306 if (vcp == 1)
3307 return CHG_IN_PROGRESS;
3308
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003309 /* reset count if battery is hot/cold */
3310 rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
3311 pr_debug("batt_temp_ok = %d\n", rc);
3312 if (rc == 0)
3313 return CHG_IN_PROGRESS;
3314
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003315 rc = pm_chg_vddmax_get(chip, &vbat_programmed);
3316 if (rc) {
3317 pr_err("couldnt read vddmax rc = %d\n", rc);
3318 return CHG_IN_PROGRESS;
3319 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003320 pr_debug("vddmax = %d vbat_batt_terminal_uv=%d\n",
3321 vbat_programmed, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003322
3323 if (last_vbat_programmed == -EINVAL)
3324 last_vbat_programmed = vbat_programmed;
3325 if (last_vbat_programmed != vbat_programmed) {
3326 /* vddmax changed, reset and check again */
3327 pr_debug("vddmax = %d last_vdd_max=%d\n",
3328 vbat_programmed, last_vbat_programmed);
3329 last_vbat_programmed = vbat_programmed;
3330 return CHG_IN_PROGRESS;
3331 }
3332
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003333 if (chip->is_bat_cool)
3334 vbat_intended = chip->cool_bat_voltage;
3335 else if (chip->is_bat_warm)
3336 vbat_intended = chip->warm_bat_voltage;
3337 else
3338 vbat_intended = chip->max_voltage_mv;
3339
3340 if (vbat_batt_terminal_uv / 1000 < vbat_intended) {
3341 pr_debug("terminal_uv:%d < vbat_intended:%d.\n",
3342 vbat_batt_terminal_uv,
3343 vbat_intended);
3344 return CHG_IN_PROGRESS;
3345 }
3346
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003347 regulation_loop = pm_chg_get_regulation_loop(chip);
3348 if (regulation_loop < 0) {
3349 pr_err("couldnt read the regulation loop err=%d\n",
3350 regulation_loop);
3351 return CHG_IN_PROGRESS;
3352 }
3353 pr_debug("regulation_loop=%d\n", regulation_loop);
3354
3355 if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
3356 return CHG_IN_PROGRESS;
3357 } /* !is_ext_charging */
3358
3359 /* reset count if battery chg current is more than iterm */
3360 rc = pm_chg_iterm_get(chip, &iterm_programmed);
3361 if (rc) {
3362 pr_err("couldnt read iterm rc = %d\n", rc);
3363 return CHG_IN_PROGRESS;
3364 }
3365
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003366 pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
3367 iterm_programmed, ichg_meas_ma);
3368 /*
3369 * ichg_meas_ma < 0 means battery is drawing current
3370 * ichg_meas_ma > 0 means battery is providing current
3371 */
3372 if (ichg_meas_ma > 0)
3373 return CHG_IN_PROGRESS;
3374
3375 if (ichg_meas_ma * -1 > iterm_programmed)
3376 return CHG_IN_PROGRESS;
3377
3378 return CHG_FINISHED;
3379}
3380
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003381#define COMP_OVERRIDE_HOT_BANK 6
3382#define COMP_OVERRIDE_COLD_BANK 7
3383#define COMP_OVERRIDE_BIT BIT(1)
3384static int pm_chg_override_cold(struct pm8921_chg_chip *chip, int flag)
3385{
3386 u8 val;
3387 int rc = 0;
3388
3389 val = 0x80 | COMP_OVERRIDE_COLD_BANK << 2 | COMP_OVERRIDE_BIT;
3390
3391 if (flag)
3392 val |= 0x01;
3393
3394 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3395 if (rc < 0)
3396 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3397
3398 pr_debug("btc cold = %d val = 0x%x\n", flag, val);
3399 return rc;
3400}
3401
3402static int pm_chg_override_hot(struct pm8921_chg_chip *chip, int flag)
3403{
3404 u8 val;
3405 int rc = 0;
3406
3407 val = 0x80 | COMP_OVERRIDE_HOT_BANK << 2 | COMP_OVERRIDE_BIT;
3408
3409 if (flag)
3410 val |= 0x01;
3411
3412 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3413 if (rc < 0)
3414 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3415
3416 pr_debug("btc hot = %d val = 0x%x\n", flag, val);
3417 return rc;
3418}
3419
3420static void __devinit pm8921_chg_btc_override_init(struct pm8921_chg_chip *chip)
3421{
3422 int rc = 0;
3423 u8 reg;
3424 u8 val;
3425
3426 val = COMP_OVERRIDE_HOT_BANK << 2;
3427 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3428 if (rc < 0) {
3429 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3430 goto cold_init;
3431 }
3432 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3433 if (rc < 0) {
3434 pr_err("Could not read bank %d of override rc = %d\n",
3435 COMP_OVERRIDE_HOT_BANK, rc);
3436 goto cold_init;
3437 }
3438 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3439 /* for now override it as not hot */
3440 rc = pm_chg_override_hot(chip, 0);
3441 if (rc < 0)
3442 pr_err("Could not override hot rc = %d\n", rc);
3443 }
3444
3445cold_init:
3446 val = COMP_OVERRIDE_COLD_BANK << 2;
3447 rc = pm_chg_write(chip, COMPARATOR_OVERRIDE, val);
3448 if (rc < 0) {
3449 pr_err("Could not write 0x%x to override rc = %d\n", val, rc);
3450 return;
3451 }
3452 rc = pm8xxx_readb(chip->dev->parent, COMPARATOR_OVERRIDE, &reg);
3453 if (rc < 0) {
3454 pr_err("Could not read bank %d of override rc = %d\n",
3455 COMP_OVERRIDE_COLD_BANK, rc);
3456 return;
3457 }
3458 if ((reg & COMP_OVERRIDE_BIT) != COMP_OVERRIDE_BIT) {
3459 /* for now override it as not cold */
3460 rc = pm_chg_override_cold(chip, 0);
3461 if (rc < 0)
3462 pr_err("Could not override cold rc = %d\n", rc);
3463 }
3464}
3465
3466static void btc_override_worker(struct work_struct *work)
3467{
3468 int decidegc;
3469 int temp;
3470 int rc = 0;
3471 struct delayed_work *dwork = to_delayed_work(work);
3472 struct pm8921_chg_chip *chip = container_of(dwork,
3473 struct pm8921_chg_chip, btc_override_work);
3474
3475 if (!chip->btc_override) {
3476 pr_err("called when not enabled\n");
3477 return;
3478 }
3479
3480 decidegc = get_prop_batt_temp(chip);
3481
3482 pr_debug("temp=%d\n", decidegc);
3483
3484 temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
3485 if (temp) {
3486 if (decidegc < chip->btc_override_hot_decidegc)
3487 /* stop forcing batt hot */
3488 rc = pm_chg_override_hot(chip, 0);
3489 if (rc)
3490 pr_err("Couldnt write 0 to hot comp\n");
3491 } else {
3492 if (decidegc >= chip->btc_override_hot_decidegc)
3493 /* start forcing batt hot */
3494 rc = pm_chg_override_hot(chip, 1);
3495 if (rc && chip->btc_panic_if_cant_stop_chg)
3496 panic("Couldnt override comps to stop chg\n");
3497 }
3498
3499 temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
3500 if (temp) {
3501 if (decidegc > chip->btc_override_cold_decidegc)
3502 /* stop forcing batt cold */
3503 rc = pm_chg_override_cold(chip, 0);
3504 if (rc)
3505 pr_err("Couldnt write 0 to cold comp\n");
3506 } else {
3507 if (decidegc <= chip->btc_override_cold_decidegc)
3508 /* start forcing batt cold */
3509 rc = pm_chg_override_cold(chip, 1);
3510 if (rc && chip->btc_panic_if_cant_stop_chg)
3511 panic("Couldnt override comps to stop chg\n");
3512 }
3513
3514 if ((is_dc_chg_plugged_in(the_chip) || is_usb_chg_plugged_in(the_chip))
3515 && get_prop_batt_status(chip) != POWER_SUPPLY_STATUS_FULL) {
3516 schedule_delayed_work(&chip->btc_override_work,
3517 round_jiffies_relative(msecs_to_jiffies
3518 (chip->btc_delay_ms)));
3519 return;
3520 }
3521
3522 rc = pm_chg_override_hot(chip, 0);
3523 if (rc)
3524 pr_err("Couldnt write 0 to hot comp\n");
3525 rc = pm_chg_override_cold(chip, 0);
3526 if (rc)
3527 pr_err("Couldnt write 0 to cold comp\n");
3528}
3529
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003530/**
Amir Samuelovd31ef502011-10-26 14:41:36 +02003531 * eoc_worker - internal function to check if battery EOC
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003532 * has happened
3533 *
3534 * If all conditions favouring, if the charge current is
3535 * less than the term current for three consecutive times
3536 * an EOC has happened.
3537 * The wakelock is released if there is no need to reshedule
3538 * - this happens when the battery is removed or EOC has
3539 * happened
3540 */
3541#define CONSECUTIVE_COUNT 3
Amir Samuelovd31ef502011-10-26 14:41:36 +02003542static void eoc_worker(struct work_struct *work)
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003543{
3544 struct delayed_work *dwork = to_delayed_work(work);
3545 struct pm8921_chg_chip *chip = container_of(dwork,
3546 struct pm8921_chg_chip, eoc_work);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003547 static int count;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003548 int end;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003549 int vbat_meas_uv, vbat_meas_mv;
3550 int ichg_meas_ua, ichg_meas_ma;
3551 int vbat_batt_terminal_uv;
Abhijeet Dharmapurikare451f342012-02-23 16:39:42 -08003552
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003553 pm8921_bms_get_simultaneous_battery_voltage_and_current(
3554 &ichg_meas_ua, &vbat_meas_uv);
3555 vbat_meas_mv = vbat_meas_uv / 1000;
3556 /* rconn_mohm is in milliOhms */
3557 ichg_meas_ma = ichg_meas_ua / 1000;
3558 vbat_batt_terminal_uv = vbat_meas_uv
3559 + ichg_meas_ma
3560 * the_chip->rconn_mohm;
3561
3562 end = is_charging_finished(chip, vbat_batt_terminal_uv, ichg_meas_ma);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003563
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003564 if (end == CHG_NOT_IN_PROGRESS) {
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003565 count = 0;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003566 goto eoc_worker_stop;
Ajay Dudani11aeb7b2012-06-28 19:14:30 -07003567 }
3568
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003569 if (end == CHG_FINISHED) {
3570 count++;
3571 } else {
3572 count = 0;
3573 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003574
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003575 if (count == CONSECUTIVE_COUNT) {
3576 count = 0;
3577 pr_info("End of Charging\n");
3578
3579 pm_chg_auto_enable(chip, 0);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003580
Amir Samuelovd31ef502011-10-26 14:41:36 +02003581 if (is_ext_charging(chip))
3582 chip->ext_charge_done = true;
3583
Abhijeet Dharmapurikareb882f52011-12-22 09:02:34 -08003584 if (chip->is_bat_warm || chip->is_bat_cool)
3585 chip->bms_notify.is_battery_full = 0;
3586 else
3587 chip->bms_notify.is_battery_full = 1;
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003588 /* declare end of charging by invoking chgdone interrupt */
3589 chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003590 } else {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003591 check_temp_thresholds(chip);
3592 adjust_vdd_max_for_fastchg(chip, vbat_batt_terminal_uv);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003593 pr_debug("EOC count = %d\n", count);
Abhijeet Dharmapurikar75c03502012-01-09 12:45:57 -08003594 schedule_delayed_work(&chip->eoc_work,
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003595 round_jiffies_relative(msecs_to_jiffies
3596 (EOC_CHECK_PERIOD_MS)));
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003597 return;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003598 }
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003599
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003600eoc_worker_stop:
3601 wake_unlock(&chip->eoc_wake_lock);
3602 /* set the vbatdet back, in case it was changed to trigger charging */
3603 set_appropriate_vbatdet(chip);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07003604}
3605
Abhijeet Dharmapurikar1f52c412011-08-12 17:11:45 -07003606/**
3607 * set_disable_status_param -
3608 *
3609 * Internal function to disable battery charging and also disable drawing
3610 * any current from the source. The device is forced to run on a battery
3611 * after this.
3612 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003613static int set_disable_status_param(const char *val, struct kernel_param *kp)
3614{
3615 int ret;
3616 struct pm8921_chg_chip *chip = the_chip;
3617
3618 ret = param_set_int(val, kp);
3619 if (ret) {
3620 pr_err("error setting value %d\n", ret);
3621 return ret;
3622 }
3623 pr_info("factory set disable param to %d\n", charging_disabled);
3624 if (chip) {
3625 pm_chg_auto_enable(chip, !charging_disabled);
3626 pm_chg_charge_dis(chip, charging_disabled);
3627 }
3628 return 0;
3629}
3630module_param_call(disabled, set_disable_status_param, param_get_uint,
3631 &charging_disabled, 0644);
3632
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08003633static int rconn_mohm;
3634static int set_rconn_mohm(const char *val, struct kernel_param *kp)
3635{
3636 int ret;
3637 struct pm8921_chg_chip *chip = the_chip;
3638
3639 ret = param_set_int(val, kp);
3640 if (ret) {
3641 pr_err("error setting value %d\n", ret);
3642 return ret;
3643 }
3644 if (chip)
3645 chip->rconn_mohm = rconn_mohm;
3646 return 0;
3647}
3648module_param_call(rconn_mohm, set_rconn_mohm, param_get_uint,
3649 &rconn_mohm, 0644);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003650/**
3651 * set_thermal_mitigation_level -
3652 *
3653 * Internal function to control battery charging current to reduce
3654 * temperature
3655 */
3656static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
3657{
3658 int ret;
3659 struct pm8921_chg_chip *chip = the_chip;
3660
3661 ret = param_set_int(val, kp);
3662 if (ret) {
3663 pr_err("error setting value %d\n", ret);
3664 return ret;
3665 }
3666
3667 if (!chip) {
3668 pr_err("called before init\n");
3669 return -EINVAL;
3670 }
3671
3672 if (!chip->thermal_mitigation) {
3673 pr_err("no thermal mitigation\n");
3674 return -EINVAL;
3675 }
3676
3677 if (thermal_mitigation < 0
3678 || thermal_mitigation >= chip->thermal_levels) {
3679 pr_err("out of bound level selected\n");
3680 return -EINVAL;
3681 }
3682
Abhijeet Dharmapurikard585ff22011-11-10 14:27:25 -08003683 set_appropriate_battery_current(chip);
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07003684 return ret;
3685}
3686module_param_call(thermal_mitigation, set_therm_mitigation_level,
3687 param_get_uint,
3688 &thermal_mitigation, 0644);
3689
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003690static int set_usb_max_current(const char *val, struct kernel_param *kp)
3691{
3692 int ret, mA;
3693 struct pm8921_chg_chip *chip = the_chip;
3694
3695 ret = param_set_int(val, kp);
3696 if (ret) {
3697 pr_err("error setting value %d\n", ret);
3698 return ret;
3699 }
3700 if (chip) {
3701 pr_warn("setting current max to %d\n", usb_max_current);
3702 pm_chg_iusbmax_get(chip, &mA);
3703 if (mA > usb_max_current)
3704 pm8921_charger_vbus_draw(usb_max_current);
3705 return 0;
3706 }
3707 return -EINVAL;
3708}
David Keitelacf57c82012-03-07 18:48:50 -08003709module_param_call(usb_max_current, set_usb_max_current,
3710 param_get_uint, &usb_max_current, 0644);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08003711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712static void free_irqs(struct pm8921_chg_chip *chip)
3713{
3714 int i;
3715
3716 for (i = 0; i < PM_CHG_MAX_INTS; i++)
3717 if (chip->pmic_chg_irq[i]) {
3718 free_irq(chip->pmic_chg_irq[i], chip);
3719 chip->pmic_chg_irq[i] = 0;
3720 }
3721}
3722
David Keitel88e1b572012-01-11 11:57:14 -08003723/* determines the initial present states */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003724static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
3725{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726 int fsm_state;
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003727 int is_fast_chg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003728
3729 chip->dc_present = !!is_dc_chg_plugged_in(chip);
3730 chip->usb_present = !!is_usb_chg_plugged_in(chip);
3731
3732 notify_usb_of_the_plugin_event(chip->usb_present);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003733 if (chip->usb_present || chip->dc_present) {
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003734 schedule_delayed_work(&chip->unplug_check_work,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003735 msecs_to_jiffies(UNPLUG_CHECK_WAIT_PERIOD_MS));
David Keitel8c5201a2012-02-24 16:08:54 -08003736 pm8921_chg_enable_irq(chip, CHG_GONE_IRQ);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08003737 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003738
3739 pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
3740 pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
3741 pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003742 pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07003743 pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
3744 pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
David Keitel753ec8d2011-11-02 10:56:37 -07003745 pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003746 pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
3747 pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08003748 pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003749
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08003750 if (get_prop_batt_present(the_chip) || is_dc_chg_plugged_in(the_chip))
3751 if (usb_chg_current)
3752 /*
3753 * Reissue a vbus draw call only if a battery
3754 * or DC is present. We don't want to brown out the
3755 * device if usb is its only source
3756 */
3757 __pm8921_charger_vbus_draw(usb_chg_current);
3758 usb_chg_current = 0;
3759
Abhijeet Dharmapurikard9ad07e2012-09-17 16:59:36 -07003760 /*
3761 * The bootloader could have started charging, a fastchg interrupt
3762 * might not happen. Check the real time status and if it is fast
3763 * charging invoke the handler so that the eoc worker could be
3764 * started
3765 */
3766 is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
3767 if (is_fast_chg)
3768 fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769
3770 fsm_state = pm_chg_get_fsm_state(chip);
3771 if (is_battery_charging(fsm_state)) {
3772 chip->bms_notify.is_charging = 1;
3773 pm8921_bms_charging_began();
3774 }
3775
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07003776 check_battery_valid(chip);
3777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003778 pr_debug("usb = %d, dc = %d batt = %d state=%d\n",
3779 chip->usb_present,
3780 chip->dc_present,
3781 get_prop_batt_present(chip),
3782 fsm_state);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003783
3784 /* Determine which USB trim column to use */
3785 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917)
3786 chip->usb_trim_table = usb_trim_8917_table;
3787 else if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8038)
3788 chip->usb_trim_table = usb_trim_8038_table;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003789}
3790
3791struct pm_chg_irq_init_data {
3792 unsigned int irq_id;
3793 char *name;
3794 unsigned long flags;
3795 irqreturn_t (*handler)(int, void *);
3796};
3797
3798#define CHG_IRQ(_id, _flags, _handler) \
3799{ \
3800 .irq_id = _id, \
3801 .name = #_id, \
3802 .flags = _flags, \
3803 .handler = _handler, \
3804}
3805struct pm_chg_irq_init_data chg_irq_data[] = {
3806 CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3807 usbin_valid_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003808 CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3809 batt_inserted_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003810 CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3811 vbatdet_low_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003812 CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
3813 CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
3814 CHG_IRQ(ATCDONE_IRQ, IRQF_TRIGGER_RISING, atcdone_irq_handler),
3815 CHG_IRQ(ATCFAIL_IRQ, IRQF_TRIGGER_RISING, atcfail_irq_handler),
3816 CHG_IRQ(CHGDONE_IRQ, IRQF_TRIGGER_RISING, chgdone_irq_handler),
3817 CHG_IRQ(CHGFAIL_IRQ, IRQF_TRIGGER_RISING, chgfail_irq_handler),
3818 CHG_IRQ(CHGSTATE_IRQ, IRQF_TRIGGER_RISING, chgstate_irq_handler),
3819 CHG_IRQ(LOOP_CHANGE_IRQ, IRQF_TRIGGER_RISING, loop_change_irq_handler),
Abhijeet Dharmapurikar19e38132011-11-03 12:03:36 -07003820 CHG_IRQ(FASTCHG_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3821 fastchg_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003822 CHG_IRQ(TRKLCHG_IRQ, IRQF_TRIGGER_RISING, trklchg_irq_handler),
3823 CHG_IRQ(BATT_REMOVED_IRQ, IRQF_TRIGGER_RISING,
3824 batt_removed_irq_handler),
3825 CHG_IRQ(BATTTEMP_HOT_IRQ, IRQF_TRIGGER_RISING,
3826 batttemp_hot_irq_handler),
3827 CHG_IRQ(CHGHOT_IRQ, IRQF_TRIGGER_RISING, chghot_irq_handler),
3828 CHG_IRQ(BATTTEMP_COLD_IRQ, IRQF_TRIGGER_RISING,
3829 batttemp_cold_irq_handler),
David Keitel8c5201a2012-02-24 16:08:54 -08003830 CHG_IRQ(CHG_GONE_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3831 chg_gone_irq_handler),
Abhijeet Dharmapurikarf2471052011-09-25 22:18:36 -07003832 CHG_IRQ(BAT_TEMP_OK_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3833 bat_temp_ok_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003834 CHG_IRQ(COARSE_DET_LOW_IRQ, IRQF_TRIGGER_RISING,
3835 coarse_det_low_irq_handler),
3836 CHG_IRQ(VDD_LOOP_IRQ, IRQF_TRIGGER_RISING, vdd_loop_irq_handler),
3837 CHG_IRQ(VREG_OV_IRQ, IRQF_TRIGGER_RISING, vreg_ov_irq_handler),
3838 CHG_IRQ(VBATDET_IRQ, IRQF_TRIGGER_RISING, vbatdet_irq_handler),
3839 CHG_IRQ(BATFET_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3840 batfet_irq_handler),
3841 CHG_IRQ(DCIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3842 dcin_valid_irq_handler),
3843 CHG_IRQ(DCIN_OV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
3844 dcin_ov_irq_handler),
Abhijeet Dharmapurikar956215b2011-10-19 15:30:14 -07003845 CHG_IRQ(DCIN_UV_IRQ, IRQF_TRIGGER_RISING, dcin_uv_irq_handler),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003846};
3847
3848static int __devinit request_irqs(struct pm8921_chg_chip *chip,
3849 struct platform_device *pdev)
3850{
3851 struct resource *res;
3852 int ret, i;
3853
3854 ret = 0;
3855 bitmap_fill(chip->enabled_irqs, PM_CHG_MAX_INTS);
3856
3857 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
3858 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
3859 chg_irq_data[i].name);
3860 if (res == NULL) {
3861 pr_err("couldn't find %s\n", chg_irq_data[i].name);
3862 goto err_out;
3863 }
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003864 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = res->start;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003865 ret = request_irq(res->start, chg_irq_data[i].handler,
3866 chg_irq_data[i].flags,
3867 chg_irq_data[i].name, chip);
3868 if (ret < 0) {
3869 pr_err("couldn't request %d (%s) %d\n", res->start,
3870 chg_irq_data[i].name, ret);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07003871 chip->pmic_chg_irq[chg_irq_data[i].irq_id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003872 goto err_out;
3873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003874 pm8921_chg_disable_irq(chip, chg_irq_data[i].irq_id);
3875 }
3876 return 0;
3877
3878err_out:
3879 free_irqs(chip);
3880 return -EINVAL;
3881}
3882
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003883static void pm8921_chg_force_19p2mhz_clk(struct pm8921_chg_chip *chip)
3884{
3885 int err;
3886 u8 temp;
3887
3888 temp = 0xD1;
3889 err = pm_chg_write(chip, CHG_TEST, temp);
3890 if (err) {
3891 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3892 return;
3893 }
3894
3895 temp = 0xD3;
3896 err = pm_chg_write(chip, CHG_TEST, temp);
3897 if (err) {
3898 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3899 return;
3900 }
3901
3902 temp = 0xD1;
3903 err = pm_chg_write(chip, CHG_TEST, temp);
3904 if (err) {
3905 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3906 return;
3907 }
3908
3909 temp = 0xD5;
3910 err = pm_chg_write(chip, CHG_TEST, temp);
3911 if (err) {
3912 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3913 return;
3914 }
3915
3916 udelay(183);
3917
3918 temp = 0xD1;
3919 err = pm_chg_write(chip, CHG_TEST, temp);
3920 if (err) {
3921 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3922 return;
3923 }
3924
3925 temp = 0xD0;
3926 err = pm_chg_write(chip, CHG_TEST, temp);
3927 if (err) {
3928 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3929 return;
3930 }
3931 udelay(32);
3932
3933 temp = 0xD1;
3934 err = pm_chg_write(chip, CHG_TEST, temp);
3935 if (err) {
3936 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3937 return;
3938 }
3939
3940 temp = 0xD3;
3941 err = pm_chg_write(chip, CHG_TEST, temp);
3942 if (err) {
3943 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3944 return;
3945 }
3946}
3947
3948static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
3949{
3950 int err;
3951 u8 temp;
3952
3953 temp = 0xD1;
3954 err = pm_chg_write(chip, CHG_TEST, temp);
3955 if (err) {
3956 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3957 return;
3958 }
3959
3960 temp = 0xD0;
3961 err = pm_chg_write(chip, CHG_TEST, temp);
3962 if (err) {
3963 pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
3964 return;
3965 }
3966}
3967
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07003968#define VREF_BATT_THERM_FORCE_ON BIT(7)
3969static void detect_battery_removal(struct pm8921_chg_chip *chip)
3970{
3971 u8 temp;
3972
3973 pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
3974 pr_debug("upon restart CHG_CNTRL = 0x%x\n", temp);
3975
3976 if (!(temp & VREF_BATT_THERM_FORCE_ON))
3977 /*
3978 * batt therm force on bit is battery backed and is default 0
3979 * The charger sets this bit at init time. If this bit is found
3980 * 0 that means the battery was removed. Tell the bms about it
3981 */
3982 pm8921_bms_invalidate_shutdown_soc();
3983}
3984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003985#define ENUM_TIMER_STOP_BIT BIT(1)
3986#define BOOT_DONE_BIT BIT(6)
3987#define CHG_BATFET_ON_BIT BIT(3)
3988#define CHG_VCP_EN BIT(0)
3989#define CHG_BAT_TEMP_DIS_BIT BIT(2)
3990#define SAFE_CURRENT_MA 1500
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003991#define PM_SUB_REV 0x001
3992#define MIN_CHARGE_CURRENT_MA 350
3993#define DEFAULT_SAFETY_MINUTES 500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003994static int __devinit pm8921_chg_hw_init(struct pm8921_chg_chip *chip)
3995{
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07003996 u8 subrev;
3997 int rc, vdd_safe, fcc_uah, safety_time = DEFAULT_SAFETY_MINUTES;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003998
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08003999 /* forcing 19p2mhz before accessing any charger registers */
4000 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikarc3695de2012-06-22 14:50:23 -07004001
Abhijeet Dharmapurikared2d87e2012-06-26 20:15:36 -07004002 detect_battery_removal(chip);
4003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004005 BOOT_DONE_BIT, BOOT_DONE_BIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006 if (rc) {
4007 pr_err("Failed to set BOOT_DONE_BIT rc=%d\n", rc);
4008 return rc;
4009 }
4010
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004011 vdd_safe = chip->max_voltage_mv + VDD_MAX_INCREASE_MV;
4012
4013 if (vdd_safe > PM8921_CHG_VDDSAFE_MAX)
4014 vdd_safe = PM8921_CHG_VDDSAFE_MAX;
4015
4016 rc = pm_chg_vddsafe_set(chip, vdd_safe);
4017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004018 if (rc) {
4019 pr_err("Failed to set safe voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004020 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004021 return rc;
4022 }
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004023 rc = pm_chg_vbatdet_set(chip,
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004024 chip->max_voltage_mv
4025 - chip->resume_voltage_delta);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 if (rc) {
4027 pr_err("Failed to set vbatdet comprator voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004028 chip->max_voltage_mv - chip->resume_voltage_delta, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029 return rc;
4030 }
4031
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004032 rc = pm_chg_vddmax_set(chip, chip->max_voltage_mv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004033 if (rc) {
4034 pr_err("Failed to set max voltage to %d rc=%d\n",
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004035 chip->max_voltage_mv, rc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004036 return rc;
4037 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004038
4039 if (chip->safe_current_ma == 0)
4040 chip->safe_current_ma = SAFE_CURRENT_MA;
4041
4042 rc = pm_chg_ibatsafe_set(chip, chip->safe_current_ma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004043 if (rc) {
4044 pr_err("Failed to set max voltage to %d rc=%d\n",
4045 SAFE_CURRENT_MA, rc);
4046 return rc;
4047 }
4048
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004049 rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004050 if (rc) {
4051 pr_err("Failed to set max current to 400 rc=%d\n", rc);
4052 return rc;
4053 }
4054
4055 rc = pm_chg_iterm_set(chip, chip->term_current);
4056 if (rc) {
4057 pr_err("Failed to set term current to %d rc=%d\n",
4058 chip->term_current, rc);
4059 return rc;
4060 }
4061
4062 /* Disable the ENUM TIMER */
4063 rc = pm_chg_masked_write(chip, PBL_ACCESS2, ENUM_TIMER_STOP_BIT,
4064 ENUM_TIMER_STOP_BIT);
4065 if (rc) {
4066 pr_err("Failed to set enum timer stop rc=%d\n", rc);
4067 return rc;
4068 }
4069
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004070 fcc_uah = pm8921_bms_get_fcc();
4071 if (fcc_uah > 0) {
4072 safety_time = div_s64((s64)fcc_uah * 60,
4073 1000 * MIN_CHARGE_CURRENT_MA);
4074 /* add 20 minutes of buffer time */
4075 safety_time += 20;
4076
4077 /* make sure we do not exceed the maximum programmable time */
4078 if (safety_time > PM8921_CHG_TCHG_MAX)
4079 safety_time = PM8921_CHG_TCHG_MAX;
4080 }
4081
4082 rc = pm_chg_tchg_max_set(chip, safety_time);
4083 if (rc) {
4084 pr_err("Failed to set max time to %d minutes rc=%d\n",
4085 safety_time, rc);
4086 return rc;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004087 }
4088
4089 if (chip->ttrkl_time != 0) {
Abhijeet Dharmapurikare45c3d32011-10-19 19:46:48 -07004090 rc = pm_chg_ttrkl_max_set(chip, chip->ttrkl_time);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004091 if (rc) {
4092 pr_err("Failed to set trkl time to %d minutes rc=%d\n",
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004093 chip->ttrkl_time, rc);
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004094 return rc;
4095 }
4096 }
4097
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004098 if (chip->vin_min != 0) {
4099 rc = pm_chg_vinmin_set(chip, chip->vin_min);
4100 if (rc) {
4101 pr_err("Failed to set vin min to %d mV rc=%d\n",
4102 chip->vin_min, rc);
4103 return rc;
4104 }
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004105 } else {
4106 chip->vin_min = pm_chg_vinmin_get(chip);
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004107 }
4108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 rc = pm_chg_disable_wd(chip);
4110 if (rc) {
4111 pr_err("Failed to disable wd rc=%d\n", rc);
4112 return rc;
4113 }
4114
4115 rc = pm_chg_masked_write(chip, CHG_CNTRL_2,
4116 CHG_BAT_TEMP_DIS_BIT, 0);
4117 if (rc) {
4118 pr_err("Failed to enable temp control chg rc=%d\n", rc);
4119 return rc;
4120 }
4121 /* switch to a 3.2Mhz for the buck */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004122 if (pm8xxx_get_revision(chip->dev->parent) >= PM8XXX_REVISION_8038_1p0)
4123 rc = pm_chg_write(chip,
4124 CHG_BUCK_CLOCK_CTRL_8038, 0x15);
4125 else
4126 rc = pm_chg_write(chip,
4127 CHG_BUCK_CLOCK_CTRL, 0x15);
4128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129 if (rc) {
4130 pr_err("Failed to switch buck clk rc=%d\n", rc);
4131 return rc;
4132 }
4133
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004134 if (chip->trkl_voltage != 0) {
4135 rc = pm_chg_vtrkl_low_set(chip, chip->trkl_voltage);
4136 if (rc) {
4137 pr_err("Failed to set trkl voltage to %dmv rc=%d\n",
4138 chip->trkl_voltage, rc);
4139 return rc;
4140 }
4141 }
4142
4143 if (chip->weak_voltage != 0) {
4144 rc = pm_chg_vweak_set(chip, chip->weak_voltage);
4145 if (rc) {
4146 pr_err("Failed to set weak voltage to %dmv rc=%d\n",
4147 chip->weak_voltage, rc);
4148 return rc;
4149 }
4150 }
4151
4152 if (chip->trkl_current != 0) {
4153 rc = pm_chg_itrkl_set(chip, chip->trkl_current);
4154 if (rc) {
4155 pr_err("Failed to set trkl current to %dmA rc=%d\n",
4156 chip->trkl_voltage, rc);
4157 return rc;
4158 }
4159 }
4160
4161 if (chip->weak_current != 0) {
4162 rc = pm_chg_iweak_set(chip, chip->weak_current);
4163 if (rc) {
4164 pr_err("Failed to set weak current to %dmA rc=%d\n",
4165 chip->weak_current, rc);
4166 return rc;
4167 }
4168 }
4169
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004170 rc = pm_chg_batt_cold_temp_config(chip, chip->cold_thr);
4171 if (rc) {
4172 pr_err("Failed to set cold config %d rc=%d\n",
4173 chip->cold_thr, rc);
4174 }
4175
4176 rc = pm_chg_batt_hot_temp_config(chip, chip->hot_thr);
4177 if (rc) {
4178 pr_err("Failed to set hot config %d rc=%d\n",
4179 chip->hot_thr, rc);
4180 }
4181
Jay Chokshid674a512012-03-15 14:06:04 -07004182 rc = pm_chg_led_src_config(chip, chip->led_src_config);
4183 if (rc) {
4184 pr_err("Failed to set charger LED src config %d rc=%d\n",
4185 chip->led_src_config, rc);
4186 }
4187
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004188 /* Workarounds for die 3.0 */
4189 if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
4190 && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921) {
4191 rc = pm8xxx_readb(chip->dev->parent, PM_SUB_REV, &subrev);
4192 if (rc) {
4193 pr_err("read failed: addr=%03X, rc=%d\n",
4194 PM_SUB_REV, rc);
4195 return rc;
4196 }
4197 /* Check if die 3.0.1 is present */
4198 if (subrev & 0x1)
4199 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xA4);
4200 else
4201 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xAC);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004202 }
4203
David Keitel0789fc62012-06-07 17:43:27 -07004204 if (pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8917) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004205 /* Set PM8917 USB_OVP debounce time to 15 ms */
4206 rc = pm_chg_masked_write(chip, USB_OVP_CONTROL,
4207 OVP_DEBOUNCE_TIME, 0x6);
4208 if (rc) {
4209 pr_err("Failed to set USB OVP db rc=%d\n", rc);
4210 return rc;
4211 }
4212
4213 /* Enable isub_fine resolution AICL for PM8917 */
David Keitel38bdd4f2012-04-19 15:39:13 -07004214 chip->iusb_fine_res = true;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004215 if (chip->uvd_voltage_mv) {
David Keitel0789fc62012-06-07 17:43:27 -07004216 rc = pm_chg_uvd_threshold_set(chip,
4217 chip->uvd_voltage_mv);
4218 if (rc) {
4219 pr_err("Failed to set UVD threshold %drc=%d\n",
4220 chip->uvd_voltage_mv, rc);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004221 return rc;
4222 }
David Keitel0789fc62012-06-07 17:43:27 -07004223 }
4224 }
David Keitel38bdd4f2012-04-19 15:39:13 -07004225
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004226 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0xD9);
David Keitelb51995e2011-11-18 17:03:31 -08004227
David Keitela3c0d822011-11-03 14:18:52 -07004228 /* Disable EOC FSM processing */
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004229 pm_chg_write(chip, CHG_BUCK_CTRL_TEST3, 0x91);
David Keitela3c0d822011-11-03 14:18:52 -07004230
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004231 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4232 VREF_BATT_THERM_FORCE_ON);
4233 if (rc)
4234 pr_err("Failed to Force Vref therm rc=%d\n", rc);
4235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004236 rc = pm_chg_charge_dis(chip, charging_disabled);
4237 if (rc) {
4238 pr_err("Failed to disable CHG_CHARGE_DIS bit rc=%d\n", rc);
4239 return rc;
4240 }
4241
4242 rc = pm_chg_auto_enable(chip, !charging_disabled);
4243 if (rc) {
4244 pr_err("Failed to enable charging rc=%d\n", rc);
4245 return rc;
4246 }
4247
4248 return 0;
4249}
4250
4251static int get_rt_status(void *data, u64 * val)
4252{
4253 int i = (int)data;
4254 int ret;
4255
4256 /* global irq number is passed in via data */
4257 ret = pm_chg_get_rt_status(the_chip, i);
4258 *val = ret;
4259 return 0;
4260}
4261DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
4262
4263static int get_fsm_status(void *data, u64 * val)
4264{
4265 u8 temp;
4266
4267 temp = pm_chg_get_fsm_state(the_chip);
4268 *val = temp;
4269 return 0;
4270}
4271DEFINE_SIMPLE_ATTRIBUTE(fsm_fops, get_fsm_status, NULL, "%llu\n");
4272
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004273static int get_reg_loop(void *data, u64 * val)
4274{
4275 u8 temp;
4276
4277 if (!the_chip) {
4278 pr_err("%s called before init\n", __func__);
4279 return -EINVAL;
4280 }
4281 temp = pm_chg_get_regulation_loop(the_chip);
4282 *val = temp;
4283 return 0;
4284}
4285DEFINE_SIMPLE_ATTRIBUTE(reg_loop_fops, get_reg_loop, NULL, "0x%02llx\n");
4286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004287static int get_reg(void *data, u64 * val)
4288{
4289 int addr = (int)data;
4290 int ret;
4291 u8 temp;
4292
4293 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
4294 if (ret) {
4295 pr_err("pm8xxx_readb to %x value =%d errored = %d\n",
4296 addr, temp, ret);
4297 return -EAGAIN;
4298 }
4299 *val = temp;
4300 return 0;
4301}
4302
4303static int set_reg(void *data, u64 val)
4304{
4305 int addr = (int)data;
4306 int ret;
4307 u8 temp;
4308
4309 temp = (u8) val;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004310 ret = pm_chg_write(the_chip, addr, temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004311 if (ret) {
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004312 pr_err("pm_chg_write to %x value =%d errored = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313 addr, temp, ret);
4314 return -EAGAIN;
4315 }
4316 return 0;
4317}
4318DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
4319
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004320static int reg_loop;
4321#define MAX_REG_LOOP_CHAR 10
4322static int get_reg_loop_param(char *buf, struct kernel_param *kp)
4323{
4324 u8 temp;
4325
4326 if (!the_chip) {
4327 pr_err("called before init\n");
4328 return -EINVAL;
4329 }
4330 temp = pm_chg_get_regulation_loop(the_chip);
4331 return snprintf(buf, MAX_REG_LOOP_CHAR, "%d", temp);
4332}
4333module_param_call(reg_loop, NULL, get_reg_loop_param,
4334 &reg_loop, 0644);
4335
4336static int max_chg_ma;
4337#define MAX_MA_CHAR 10
4338static int get_max_chg_ma_param(char *buf, struct kernel_param *kp)
4339{
4340 if (!the_chip) {
4341 pr_err("called before init\n");
4342 return -EINVAL;
4343 }
4344 return snprintf(buf, MAX_MA_CHAR, "%d", the_chip->max_bat_chg_current);
4345}
4346module_param_call(max_chg_ma, NULL, get_max_chg_ma_param,
4347 &max_chg_ma, 0644);
4348static int ibatmax_ma;
4349static int set_ibat_max(const char *val, struct kernel_param *kp)
4350{
4351 int rc;
4352
4353 if (!the_chip) {
4354 pr_err("called before init\n");
4355 return -EINVAL;
4356 }
4357
4358 rc = param_set_int(val, kp);
4359 if (rc) {
4360 pr_err("error setting value %d\n", rc);
4361 return rc;
4362 }
4363
4364 if (abs(ibatmax_ma - the_chip->max_bat_chg_current)
4365 <= the_chip->ibatmax_max_adj_ma) {
4366 rc = pm_chg_ibatmax_set(the_chip, ibatmax_ma);
4367 if (rc) {
4368 pr_err("Failed to set ibatmax rc = %d\n", rc);
4369 return rc;
4370 }
4371 }
4372
4373 return 0;
4374}
4375static int get_ibat_max(char *buf, struct kernel_param *kp)
4376{
4377 int ibat_ma;
4378 int rc;
4379
4380 if (!the_chip) {
4381 pr_err("called before init\n");
4382 return -EINVAL;
4383 }
4384
4385 rc = pm_chg_ibatmax_get(the_chip, &ibat_ma);
4386 if (rc) {
4387 pr_err("ibatmax_get error = %d\n", rc);
4388 return rc;
4389 }
4390
4391 return snprintf(buf, MAX_MA_CHAR, "%d", ibat_ma);
4392}
4393module_param_call(ibatmax_ma, set_ibat_max, get_ibat_max,
4394 &ibatmax_ma, 0644);
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004395enum {
4396 BAT_WARM_ZONE,
4397 BAT_COOL_ZONE,
4398};
4399static int get_warm_cool(void *data, u64 * val)
4400{
4401 if (!the_chip) {
4402 pr_err("%s called before init\n", __func__);
4403 return -EINVAL;
4404 }
4405 if ((int)data == BAT_WARM_ZONE)
4406 *val = the_chip->is_bat_warm;
4407 if ((int)data == BAT_COOL_ZONE)
4408 *val = the_chip->is_bat_cool;
4409 return 0;
4410}
4411DEFINE_SIMPLE_ATTRIBUTE(warm_cool_fops, get_warm_cool, NULL, "0x%lld\n");
4412
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004413static void create_debugfs_entries(struct pm8921_chg_chip *chip)
4414{
4415 int i;
4416
4417 chip->dent = debugfs_create_dir("pm8921_chg", NULL);
4418
4419 if (IS_ERR(chip->dent)) {
4420 pr_err("pmic charger couldnt create debugfs dir\n");
4421 return;
4422 }
4423
4424 debugfs_create_file("CHG_CNTRL", 0644, chip->dent,
4425 (void *)CHG_CNTRL, &reg_fops);
4426 debugfs_create_file("CHG_CNTRL_2", 0644, chip->dent,
4427 (void *)CHG_CNTRL_2, &reg_fops);
4428 debugfs_create_file("CHG_CNTRL_3", 0644, chip->dent,
4429 (void *)CHG_CNTRL_3, &reg_fops);
4430 debugfs_create_file("PBL_ACCESS1", 0644, chip->dent,
4431 (void *)PBL_ACCESS1, &reg_fops);
4432 debugfs_create_file("PBL_ACCESS2", 0644, chip->dent,
4433 (void *)PBL_ACCESS2, &reg_fops);
4434 debugfs_create_file("SYS_CONFIG_1", 0644, chip->dent,
4435 (void *)SYS_CONFIG_1, &reg_fops);
4436 debugfs_create_file("SYS_CONFIG_2", 0644, chip->dent,
4437 (void *)SYS_CONFIG_2, &reg_fops);
4438 debugfs_create_file("CHG_VDD_MAX", 0644, chip->dent,
4439 (void *)CHG_VDD_MAX, &reg_fops);
4440 debugfs_create_file("CHG_VDD_SAFE", 0644, chip->dent,
4441 (void *)CHG_VDD_SAFE, &reg_fops);
4442 debugfs_create_file("CHG_VBAT_DET", 0644, chip->dent,
4443 (void *)CHG_VBAT_DET, &reg_fops);
4444 debugfs_create_file("CHG_IBAT_MAX", 0644, chip->dent,
4445 (void *)CHG_IBAT_MAX, &reg_fops);
4446 debugfs_create_file("CHG_IBAT_SAFE", 0644, chip->dent,
4447 (void *)CHG_IBAT_SAFE, &reg_fops);
4448 debugfs_create_file("CHG_VIN_MIN", 0644, chip->dent,
4449 (void *)CHG_VIN_MIN, &reg_fops);
4450 debugfs_create_file("CHG_VTRICKLE", 0644, chip->dent,
4451 (void *)CHG_VTRICKLE, &reg_fops);
4452 debugfs_create_file("CHG_ITRICKLE", 0644, chip->dent,
4453 (void *)CHG_ITRICKLE, &reg_fops);
4454 debugfs_create_file("CHG_ITERM", 0644, chip->dent,
4455 (void *)CHG_ITERM, &reg_fops);
4456 debugfs_create_file("CHG_TCHG_MAX", 0644, chip->dent,
4457 (void *)CHG_TCHG_MAX, &reg_fops);
4458 debugfs_create_file("CHG_TWDOG", 0644, chip->dent,
4459 (void *)CHG_TWDOG, &reg_fops);
4460 debugfs_create_file("CHG_TEMP_THRESH", 0644, chip->dent,
4461 (void *)CHG_TEMP_THRESH, &reg_fops);
4462 debugfs_create_file("CHG_COMP_OVR", 0644, chip->dent,
4463 (void *)CHG_COMP_OVR, &reg_fops);
4464 debugfs_create_file("CHG_BUCK_CTRL_TEST1", 0644, chip->dent,
4465 (void *)CHG_BUCK_CTRL_TEST1, &reg_fops);
4466 debugfs_create_file("CHG_BUCK_CTRL_TEST2", 0644, chip->dent,
4467 (void *)CHG_BUCK_CTRL_TEST2, &reg_fops);
4468 debugfs_create_file("CHG_BUCK_CTRL_TEST3", 0644, chip->dent,
4469 (void *)CHG_BUCK_CTRL_TEST3, &reg_fops);
4470 debugfs_create_file("CHG_TEST", 0644, chip->dent,
4471 (void *)CHG_TEST, &reg_fops);
4472
4473 debugfs_create_file("FSM_STATE", 0644, chip->dent, NULL,
4474 &fsm_fops);
4475
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004476 debugfs_create_file("REGULATION_LOOP_CONTROL", 0644, chip->dent, NULL,
4477 &reg_loop_fops);
4478
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004479 debugfs_create_file("BAT_WARM_ZONE", 0644, chip->dent,
4480 (void *)BAT_WARM_ZONE, &warm_cool_fops);
4481 debugfs_create_file("BAT_COOL_ZONE", 0644, chip->dent,
4482 (void *)BAT_COOL_ZONE, &warm_cool_fops);
4483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004484 for (i = 0; i < ARRAY_SIZE(chg_irq_data); i++) {
4485 if (chip->pmic_chg_irq[chg_irq_data[i].irq_id])
4486 debugfs_create_file(chg_irq_data[i].name, 0444,
4487 chip->dent,
4488 (void *)chg_irq_data[i].irq_id,
4489 &rt_fops);
4490 }
4491}
4492
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004493static int pm8921_charger_suspend_noirq(struct device *dev)
4494{
4495 int rc;
4496 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4497
4498 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
4499 if (rc)
4500 pr_err("Failed to Force Vref therm off rc=%d\n", rc);
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004501
4502 rc = pm8921_chg_set_lpm(chip, 1);
4503 if (rc)
4504 pr_err("Failed to set lpm rc=%d\n", rc);
4505
4506 pm8921_chg_set_hw_clk_switching(chip);
4507
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004508 return 0;
4509}
4510
4511static int pm8921_charger_resume_noirq(struct device *dev)
4512{
4513 int rc;
4514 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4515
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004516 pm8921_chg_force_19p2mhz_clk(chip);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004517
Abhijeet Dharmapurikar68f44372013-03-01 18:25:05 -08004518 rc = pm8921_chg_set_lpm(chip, 0);
4519 if (rc)
4520 pr_err("Failed to set lpm rc=%d\n", rc);
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004521
4522 rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
4523 VREF_BATT_THERM_FORCE_ON);
4524 if (rc)
4525 pr_err("Failed to Force Vref therm on rc=%d\n", rc);
4526 return 0;
4527}
4528
David Keitelf2226022011-12-13 15:55:50 -08004529static int pm8921_charger_resume(struct device *dev)
4530{
David Keitelf2226022011-12-13 15:55:50 -08004531 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4532
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004533 if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
4534 disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4535 pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
4536 }
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004537
4538 if (chip->btc_override && (is_dc_chg_plugged_in(the_chip) ||
4539 is_usb_chg_plugged_in(the_chip)))
4540 schedule_delayed_work(&chip->btc_override_work, 0);
4541
David Keitelf2226022011-12-13 15:55:50 -08004542 return 0;
4543}
4544
4545static int pm8921_charger_suspend(struct device *dev)
4546{
David Keitelf2226022011-12-13 15:55:50 -08004547 struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
4548
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004549 if (chip->btc_override)
4550 cancel_delayed_work_sync(&chip->btc_override_work);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004551
4552 if (is_usb_chg_plugged_in(chip)) {
4553 pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
4554 enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
4555 }
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004556
David Keitelf2226022011-12-13 15:55:50 -08004557 return 0;
4558}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004559static int __devinit pm8921_charger_probe(struct platform_device *pdev)
4560{
4561 int rc = 0;
4562 struct pm8921_chg_chip *chip;
4563 const struct pm8921_charger_platform_data *pdata
4564 = pdev->dev.platform_data;
4565
4566 if (!pdata) {
4567 pr_err("missing platform data\n");
4568 return -EINVAL;
4569 }
4570
4571 chip = kzalloc(sizeof(struct pm8921_chg_chip),
4572 GFP_KERNEL);
4573 if (!chip) {
4574 pr_err("Cannot allocate pm_chg_chip\n");
4575 return -ENOMEM;
4576 }
4577
4578 chip->dev = &pdev->dev;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004579 chip->ttrkl_time = pdata->ttrkl_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 chip->update_time = pdata->update_time;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004581 chip->max_voltage_mv = pdata->max_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004582 chip->alarm_low_mv = pdata->alarm_low_mv;
4583 chip->alarm_high_mv = pdata->alarm_high_mv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -08004584 chip->min_voltage_mv = pdata->min_voltage;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004585 chip->safe_current_ma = pdata->safe_current_ma;
David Keitel0789fc62012-06-07 17:43:27 -07004586 chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
Abhijeet Dharmapurikard55878e2011-10-27 10:22:24 -07004587 chip->resume_voltage_delta = pdata->resume_voltage_delta;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004588 chip->resume_charge_percent = pdata->resume_charge_percent;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004589 chip->term_current = pdata->term_current;
4590 chip->vbat_channel = pdata->charger_cdata.vbat_channel;
Abhijeet Dharmapurikarb24e2c32011-08-17 17:13:09 -07004591 chip->batt_temp_channel = pdata->charger_cdata.batt_temp_channel;
Abhijeet Dharmapurikarbe6bd8c2011-08-19 12:15:06 -07004592 chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
4593 chip->batt_id_min = pdata->batt_id_min;
4594 chip->batt_id_max = pdata->batt_id_max;
Abhijeet Dharmapurikarbc38f632012-01-10 09:30:11 -08004595 if (pdata->cool_temp != INT_MIN)
4596 chip->cool_temp_dc = pdata->cool_temp * 10;
4597 else
4598 chip->cool_temp_dc = INT_MIN;
4599
4600 if (pdata->warm_temp != INT_MIN)
4601 chip->warm_temp_dc = pdata->warm_temp * 10;
4602 else
4603 chip->warm_temp_dc = INT_MIN;
4604
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004605 chip->temp_check_period = pdata->temp_check_period;
4606 chip->max_bat_chg_current = pdata->max_bat_chg_current;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004607 /* Assign to corresponding module parameter */
4608 usb_max_current = pdata->usb_max_current;
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004609 chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
4610 chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
4611 chip->cool_bat_voltage = pdata->cool_bat_voltage;
4612 chip->warm_bat_voltage = pdata->warm_bat_voltage;
Abhijeet Dharmapurikar26cef9c2011-08-25 19:16:42 -07004613 chip->trkl_voltage = pdata->trkl_voltage;
4614 chip->weak_voltage = pdata->weak_voltage;
4615 chip->trkl_current = pdata->trkl_current;
4616 chip->weak_current = pdata->weak_current;
Abhijeet Dharmapurikar6fe50a82011-08-25 21:33:14 -07004617 chip->vin_min = pdata->vin_min;
Abhijeet Dharmapurikarad742362011-08-29 19:50:02 -07004618 chip->thermal_mitigation = pdata->thermal_mitigation;
4619 chip->thermal_levels = pdata->thermal_levels;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004620
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004621 chip->cold_thr = pdata->cold_thr;
4622 chip->hot_thr = pdata->hot_thr;
Abhijeet Dharmapurikar40491ce2011-11-07 11:38:54 -08004623 chip->rconn_mohm = pdata->rconn_mohm;
Jay Chokshid674a512012-03-15 14:06:04 -07004624 chip->led_src_config = pdata->led_src_config;
Xiaozhe Shi7c229e52013-01-22 09:46:45 -08004625 chip->has_dc_supply = pdata->has_dc_supply;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004626 chip->battery_less_hardware = pdata->battery_less_hardware;
4627 chip->btc_override = pdata->btc_override;
4628 if (chip->btc_override) {
4629 chip->btc_delay_ms = pdata->btc_delay_ms;
4630 chip->btc_override_cold_decidegc
4631 = pdata->btc_override_cold_degc * 10;
4632 chip->btc_override_hot_decidegc
4633 = pdata->btc_override_hot_degc * 10;
4634 chip->btc_panic_if_cant_stop_chg
4635 = pdata->btc_panic_if_cant_stop_chg;
4636 }
4637
4638 if (chip->battery_less_hardware)
4639 charging_disabled = 1;
4640
4641 chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
4642 chip->max_bat_chg_current);
Abhijeet Dharmapurikar0f024232011-10-03 12:00:15 -07004643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004644 rc = pm8921_chg_hw_init(chip);
4645 if (rc) {
4646 pr_err("couldn't init hardware rc=%d\n", rc);
4647 goto free_chip;
4648 }
4649
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004650 if (chip->btc_override)
4651 pm8921_chg_btc_override_init(chip);
4652
4653 chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
Anirudh Ghayal8ecf5ad2013-02-20 09:48:42 +05304654 chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004655
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004656 chip->usb_psy.name = "usb";
4657 chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
4658 chip->usb_psy.supplied_to = pm_power_supplied_to;
4659 chip->usb_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4660 chip->usb_psy.properties = pm_power_props_usb;
4661 chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props_usb);
4662 chip->usb_psy.get_property = pm_power_get_property_usb;
4663 chip->usb_psy.set_property = pm_power_set_property_usb;
4664 chip->usb_psy.property_is_writeable = usb_property_is_writeable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004666 chip->dc_psy.name = "pm8921-dc";
4667 chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
4668 chip->dc_psy.supplied_to = pm_power_supplied_to;
4669 chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
4670 chip->dc_psy.properties = pm_power_props_mains;
4671 chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
4672 chip->dc_psy.get_property = pm_power_get_property_mains;
David Keitel6ed71a52012-01-30 12:42:18 -08004673
Abhijeet Dharmapurikard97d54f2013-01-14 20:48:25 -08004674 chip->batt_psy.name = "battery";
4675 chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
4676 chip->batt_psy.properties = msm_batt_power_props;
4677 chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
4678 chip->batt_psy.get_property = pm_batt_power_get_property;
4679 chip->batt_psy.external_power_changed = pm_batt_external_power_changed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004680 rc = power_supply_register(chip->dev, &chip->usb_psy);
4681 if (rc < 0) {
4682 pr_err("power_supply_register usb failed rc = %d\n", rc);
Abhijeet Dharmapurikar86eea302011-08-15 13:55:18 -07004683 goto free_chip;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004684 }
4685
David Keitel6ed71a52012-01-30 12:42:18 -08004686 rc = power_supply_register(chip->dev, &chip->dc_psy);
4687 if (rc < 0) {
4688 pr_err("power_supply_register usb failed rc = %d\n", rc);
4689 goto unregister_usb;
4690 }
4691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004692 rc = power_supply_register(chip->dev, &chip->batt_psy);
4693 if (rc < 0) {
4694 pr_err("power_supply_register batt failed rc = %d\n", rc);
David Keitel6ed71a52012-01-30 12:42:18 -08004695 goto unregister_dc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004696 }
4697
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004698 platform_set_drvdata(pdev, chip);
4699 the_chip = chip;
4700
4701 wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
Amir Samuelovd31ef502011-10-26 14:41:36 +02004702 INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
David Keitelacf57c82012-03-07 18:48:50 -08004703 INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
4704 vin_collapse_check_worker);
Abhijeet Dharmapurikarc4599552011-12-22 17:27:56 -08004705 INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
Abhijeet Dharmapurikar98738c52011-09-20 17:04:48 -07004706
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004707 INIT_WORK(&chip->bms_notify.work, bms_notify);
4708 INIT_WORK(&chip->battery_id_valid_work, battery_id_valid);
4709
4710 INIT_DELAYED_WORK(&chip->update_heartbeat_work, update_heartbeat);
4711 INIT_DELAYED_WORK(&chip->btc_override_work, btc_override_worker);
4712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713 rc = request_irqs(chip, pdev);
4714 if (rc) {
4715 pr_err("couldn't register interrupts rc=%d\n", rc);
4716 goto unregister_batt;
4717 }
4718
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004719 enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004720 enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
David Keitel64dd3f52011-11-10 14:19:38 -08004721 enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
Abhijeet Dharmapurikar28fd0c62012-01-27 13:28:29 -08004722 enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
Abhijeet Dharmapurikare27d8092011-08-12 17:16:29 -07004723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004724 create_debugfs_entries(chip);
4725
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004726 /* determine what state the charger is in */
4727 determine_initial_state(chip);
4728
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004729 if (chip->update_time)
Abhijeet Dharmapurikar33fe6fb2011-09-14 16:03:11 -07004730 schedule_delayed_work(&chip->update_heartbeat_work,
4731 round_jiffies_relative(msecs_to_jiffies
4732 (chip->update_time)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 return 0;
4734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004735unregister_batt:
Abhijeet Dharmapurikar999ee572012-08-28 19:33:49 -07004736 wake_lock_destroy(&chip->eoc_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737 power_supply_unregister(&chip->batt_psy);
David Keitel6ed71a52012-01-30 12:42:18 -08004738unregister_dc:
4739 power_supply_unregister(&chip->dc_psy);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004740unregister_usb:
4741 power_supply_unregister(&chip->usb_psy);
4742free_chip:
4743 kfree(chip);
4744 return rc;
4745}
4746
4747static int __devexit pm8921_charger_remove(struct platform_device *pdev)
4748{
4749 struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
4750
4751 free_irqs(chip);
4752 platform_set_drvdata(pdev, NULL);
4753 the_chip = NULL;
4754 kfree(chip);
4755 return 0;
4756}
David Keitelf2226022011-12-13 15:55:50 -08004757static const struct dev_pm_ops pm8921_pm_ops = {
4758 .suspend = pm8921_charger_suspend,
Abhijeet Dharmapurikarccac6952012-01-18 16:35:34 -08004759 .suspend_noirq = pm8921_charger_suspend_noirq,
4760 .resume_noirq = pm8921_charger_resume_noirq,
David Keitelf2226022011-12-13 15:55:50 -08004761 .resume = pm8921_charger_resume,
4762};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004763static struct platform_driver pm8921_charger_driver = {
David Keitelf2226022011-12-13 15:55:50 -08004764 .probe = pm8921_charger_probe,
4765 .remove = __devexit_p(pm8921_charger_remove),
4766 .driver = {
4767 .name = PM8921_CHARGER_DEV_NAME,
4768 .owner = THIS_MODULE,
4769 .pm = &pm8921_pm_ops,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004770 },
4771};
4772
4773static int __init pm8921_charger_init(void)
4774{
4775 return platform_driver_register(&pm8921_charger_driver);
4776}
4777
4778static void __exit pm8921_charger_exit(void)
4779{
4780 platform_driver_unregister(&pm8921_charger_driver);
4781}
4782
4783late_initcall(pm8921_charger_init);
4784module_exit(pm8921_charger_exit);
4785
4786MODULE_LICENSE("GPL v2");
4787MODULE_DESCRIPTION("PMIC8921 charger/battery driver");
4788MODULE_VERSION("1.0");
4789MODULE_ALIAS("platform:" PM8921_CHARGER_DEV_NAME);