blob: b560fa5ac4e79417f8b07a3c08916b77334365ad [file] [log] [blame]
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001/*
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02002 * Copyright 2012 ST Ericsson.
3 *
Lee Jones2fa5b0f2013-01-23 14:33:47 +00004 * Power supply driver for ST Ericsson pm2xxx_charger charger
5 *
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/module.h>
13#include <linux/device.h>
14#include <linux/interrupt.h>
15#include <linux/delay.h>
16#include <linux/slab.h>
17#include <linux/platform_device.h>
18#include <linux/power_supply.h>
19#include <linux/completion.h>
20#include <linux/regulator/consumer.h>
21#include <linux/err.h>
22#include <linux/i2c.h>
23#include <linux/workqueue.h>
24#include <linux/kobject.h>
25#include <linux/mfd/abx500.h>
26#include <linux/mfd/abx500/ab8500.h>
27#include <linux/mfd/abx500/ab8500-bm.h>
28#include <linux/mfd/abx500/ab8500-gpadc.h>
29#include <linux/mfd/abx500/ux500_chargalg.h>
30#include <linux/pm2301_charger.h>
Lee Jones39880432013-01-23 14:38:15 +000031#include <linux/gpio.h>
Michel JAOUEN01ec8c52012-04-26 10:00:04 +020032
Lee Jones2fa5b0f2013-01-23 14:33:47 +000033#include "pm2301_charger.h"
Michel JAOUEN01ec8c52012-04-26 10:00:04 +020034
35#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
36 struct pm2xxx_charger, ac_chg)
37
38static int pm2xxx_interrupt_registers[] = {
39 PM2XXX_REG_INT1,
40 PM2XXX_REG_INT2,
41 PM2XXX_REG_INT3,
42 PM2XXX_REG_INT4,
43 PM2XXX_REG_INT5,
44 PM2XXX_REG_INT6,
45};
46
Michel JAOUEN01ec8c52012-04-26 10:00:04 +020047static enum power_supply_property pm2xxx_charger_ac_props[] = {
48 POWER_SUPPLY_PROP_HEALTH,
49 POWER_SUPPLY_PROP_PRESENT,
50 POWER_SUPPLY_PROP_ONLINE,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +020051 POWER_SUPPLY_PROP_VOLTAGE_AVG,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +020052};
53
54static int pm2xxx_charger_voltage_map[] = {
55 3500,
56 3525,
57 3550,
58 3575,
59 3600,
60 3625,
61 3650,
62 3675,
63 3700,
64 3725,
65 3750,
66 3775,
67 3800,
68 3825,
69 3850,
70 3875,
71 3900,
72 3925,
73 3950,
74 3975,
75 4000,
76 4025,
77 4050,
78 4075,
79 4100,
80 4125,
81 4150,
82 4175,
83 4200,
84 4225,
85 4250,
86 4275,
87 4300,
88};
89
90static int pm2xxx_charger_current_map[] = {
91 200,
92 200,
93 400,
94 600,
95 800,
96 1000,
97 1200,
98 1400,
99 1600,
100 1800,
101 2000,
102 2200,
103 2400,
104 2600,
105 2800,
106 3000,
107};
108
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200109static const struct i2c_device_id pm2xxx_ident[] = {
110 { "pm2301", 0 },
111 { }
112};
113
Lee Jones39880432013-01-23 14:38:15 +0000114static void set_lpn_pin(struct pm2xxx_charger *pm2)
115{
116 if (pm2->ac.charger_connected)
117 return;
118 gpio_set_value(pm2->lpn_pin, 1);
119
120 return;
121}
122
123static void clear_lpn_pin(struct pm2xxx_charger *pm2)
124{
125 if (pm2->ac.charger_connected)
126 return;
127 gpio_set_value(pm2->lpn_pin, 0);
128
129 return;
130}
131
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200132static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
133{
134 int ret;
Lee Jones39880432013-01-23 14:38:15 +0000135 /*
136 * When AC adaptor is unplugged, the host
137 * must put LPN high to be able to
138 * communicate by I2C with PM2301
139 * and receive I2C "acknowledge" from PM2301.
140 */
141 mutex_lock(&pm2->lock);
142 set_lpn_pin(pm2);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200143
144 ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
145 1, val);
146 if (ret < 0)
147 dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530148 else
149 ret = 0;
Lee Jones39880432013-01-23 14:38:15 +0000150 clear_lpn_pin(pm2);
151 mutex_unlock(&pm2->lock);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200152
153 return ret;
154}
155
156static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
157{
158 int ret;
Lee Jones39880432013-01-23 14:38:15 +0000159 /*
160 * When AC adaptor is unplugged, the host
161 * must put LPN high to be able to
162 * communicate by I2C with PM2301
163 * and receive I2C "acknowledge" from PM2301.
164 */
165 mutex_lock(&pm2->lock);
166 set_lpn_pin(pm2);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200167
168 ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
169 1, &val);
170 if (ret < 0)
171 dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530172 else
173 ret = 0;
Lee Jones39880432013-01-23 14:38:15 +0000174 clear_lpn_pin(pm2);
175 mutex_unlock(&pm2->lock);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200176
177 return ret;
178}
179
180static int pm2xxx_charging_enable_mngt(struct pm2xxx_charger *pm2)
181{
182 int ret;
183
184 /* Enable charging */
185 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
186 (PM2XXX_CH_AUTO_RESUME_EN | PM2XXX_CHARGER_ENA));
187
188 return ret;
189}
190
191static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
192{
193 int ret;
194
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530195 /* Disable SW EOC ctrl */
196 ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, PM2XXX_SWCTRL_HW);
197 if (ret < 0) {
198 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
199 return ret;
200 }
201
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200202 /* Disable charging */
203 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
204 (PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530205 if (ret < 0) {
206 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
207 return ret;
208 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200209
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530210 return 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200211}
212
213static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
214{
215 queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
216
217 return 0;
218}
219
220
221int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
222{
223 queue_work(pm2->charger_wq, &pm2->check_main_thermal_prot_work);
224
225 return 0;
226}
227
228static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
229{
Rupesh Kumar789ca7b2012-06-19 10:21:24 +0530230 dev_err(pm2->dev, "Overvoltage detected\n");
231 pm2->flags.ovv = true;
232 power_supply_changed(&pm2->ac_chg.psy);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200233
Rupesh Kumar789ca7b2012-06-19 10:21:24 +0530234 /* Schedule a new HW failure check */
235 queue_delayed_work(pm2->charger_wq, &pm2->check_hw_failure_work, 0);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200236
Rupesh Kumar789ca7b2012-06-19 10:21:24 +0530237 return 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200238}
239
240static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
241{
242 dev_dbg(pm2->dev , "20 minutes watchdog occured\n");
243
244 pm2->ac.wd_expired = true;
245 power_supply_changed(&pm2->ac_chg.psy);
246
247 return 0;
248}
249
250static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
251{
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530252 int ret;
253
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200254 switch (val) {
255 case PM2XXX_INT1_ITVBATLOWR:
256 dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530257 /* Enable SW EOC ctrl */
258 ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
259 PM2XXX_SWCTRL_SW);
260 if (ret < 0) {
261 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
262 return ret;
263 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200264 break;
265
266 case PM2XXX_INT1_ITVBATLOWF:
267 dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530268 /* Disable SW EOC ctrl */
269 ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
270 PM2XXX_SWCTRL_HW);
271 if (ret < 0) {
272 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
273 return ret;
274 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200275 break;
276
277 default:
278 dev_err(pm2->dev, "Unknown VBAT level\n");
279 }
280
281 return 0;
282}
283
284static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
285{
286 dev_dbg(pm2->dev, "battery disconnected\n");
287
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200288 return 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200289}
290
291static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
292{
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530293 int ret;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200294
295 ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
296
297 if (ret < 0) {
298 dev_err(pm2->dev, "Charger detection failed\n");
299 goto out;
300 }
301
302 *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530303
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200304out:
305 return ret;
306}
307
308static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
309{
310
311 int ret;
312 u8 read_val;
313
314 /*
315 * Since we can't be sure that the events are received
316 * synchronously, we have the check if the main charger is
317 * connected by reading the interrupt source register.
318 */
319 ret = pm2xxx_charger_detection(pm2, &read_val);
320
321 if ((ret == 0) && read_val) {
322 pm2->ac.charger_connected = 1;
323 pm2->ac_conn = true;
324 queue_work(pm2->charger_wq, &pm2->ac_work);
325 }
326
327
328 return ret;
329}
330
331static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
332 int val)
333{
334 pm2->ac.charger_connected = 0;
335 queue_work(pm2->charger_wq, &pm2->ac_work);
336
337 return 0;
338}
339
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200340static int pm2_int_reg0(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200341{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200342 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200343 int ret = 0;
344
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530345 if (val & PM2XXX_INT1_ITVBATLOWR) {
346 ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
347 PM2XXX_INT1_ITVBATLOWR);
348 if (ret < 0)
349 goto out;
350 }
351
352 if (val & PM2XXX_INT1_ITVBATLOWF) {
353 ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
354 PM2XXX_INT1_ITVBATLOWF);
355 if (ret < 0)
356 goto out;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200357 }
358
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200359 if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200360 ret = pm2xxx_charger_bat_disc_mngt(pm2,
361 PM2XXX_INT1_ITVBATDISCONNECT);
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530362 if (ret < 0)
363 goto out;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200364 }
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530365out:
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200366 return ret;
367}
368
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200369static int pm2_int_reg1(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200370{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200371 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200372 int ret = 0;
373
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200374 if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200375 dev_dbg(pm2->dev , "Main charger plugged\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200376 ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200377 (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
378 }
379
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200380 if (val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200381 (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
382 dev_dbg(pm2->dev , "Main charger unplugged\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200383 ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200384 (PM2XXX_INT2_ITVPWR1UNPLUG |
385 PM2XXX_INT2_ITVPWR2UNPLUG));
386 }
387
388 return ret;
389}
390
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200391static int pm2_int_reg2(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200392{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200393 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200394 int ret = 0;
395
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200396 if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
397 ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200398
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200399 if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200400 PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
401 dev_dbg(pm2->dev,
402 "Watchdog occured for precharge, CC and CV charge\n");
403 }
404
405 return ret;
406}
407
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200408static int pm2_int_reg3(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200409{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200410 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200411 int ret = 0;
412
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200413 if (val & (PM2XXX_INT4_ITCHARGINGON)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200414 dev_dbg(pm2->dev ,
415 "chargind operation has started\n");
416 }
417
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200418 if (val & (PM2XXX_INT4_ITVRESUME)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200419 dev_dbg(pm2->dev,
420 "battery discharged down to VResume threshold\n");
421 }
422
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200423 if (val & (PM2XXX_INT4_ITBATTFULL)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200424 dev_dbg(pm2->dev , "battery fully detected\n");
425 }
426
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200427 if (val & (PM2XXX_INT4_ITCVPHASE)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200428 dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
429 }
430
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200431 if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200432 pm2->failure_case = VPWR_OVV;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200433 ret = pm2xxx_charger_ovv_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200434 (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
435 dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
436 }
437
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200438 if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200439 PM2XXX_INT4_S_ITBATTEMPHOT)) {
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200440 ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
441 (PM2XXX_INT4_S_ITBATTEMPCOLD |
442 PM2XXX_INT4_S_ITBATTEMPHOT));
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200443 dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
444 }
445
446 return ret;
447}
448
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200449static int pm2_int_reg4(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200450{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200451 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200452 int ret = 0;
453
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200454 if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200455 pm2->failure_case = VSYSTEM_OVV;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200456 ret = pm2xxx_charger_ovv_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200457 PM2XXX_INT5_ITVSYSTEMOVV);
458 dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
459 }
460
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200461 if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200462 PM2XXX_INT5_ITTHERMALWARNINGRISE |
463 PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
464 PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
465 dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200466 ret = pm2xxx_charger_die_therm_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200467 (PM2XXX_INT5_ITTHERMALWARNINGFALL |
468 PM2XXX_INT5_ITTHERMALWARNINGRISE |
469 PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
470 PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
471 }
472
473 return ret;
474}
475
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200476static int pm2_int_reg5(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200477{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200478 struct pm2xxx_charger *pm2 = pm2_data;
479 int ret = 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200480
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200481
482 if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200483 dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
484 }
485
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200486 if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
487 PM2XXX_INT6_ITVPWR1VALIDRISE |
488 PM2XXX_INT6_ITVPWR2VALIDFALL |
489 PM2XXX_INT6_ITVPWR1VALIDFALL)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200490 dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
491 }
492
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200493 return ret;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200494}
495
496static irqreturn_t pm2xxx_irq_int(int irq, void *data)
497{
498 struct pm2xxx_charger *pm2 = data;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200499 struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
500 int i;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200501
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200502 for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
503 pm2xxx_reg_read(pm2,
504 pm2xxx_interrupt_registers[i],
505 &(interrupt->reg[i]));
506
507 if (interrupt->reg[i] > 0)
508 interrupt->handler[i](pm2, interrupt->reg[i]);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200509 }
510
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200511 return IRQ_HANDLED;
512}
513
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200514static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
515{
516 int ret = 0;
517 u8 val;
518
519 if (pm2->ac.charger_connected && pm2->ac.charger_online) {
520
521 ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
522 if (ret < 0) {
523 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
524 goto out;
525 }
526
527 if (val & PM2XXX_INT4_S_ITCVPHASE)
528 ret = PM2XXX_CONST_VOLT;
529 else
530 ret = PM2XXX_CONST_CURR;
531 }
532out:
533 return ret;
534}
535
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200536static int pm2xxx_current_to_regval(int curr)
537{
538 int i;
539
540 if (curr < pm2xxx_charger_current_map[0])
541 return 0;
542
543 for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
544 if (curr < pm2xxx_charger_current_map[i])
545 return (i - 1);
546 }
547
548 i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
549 if (curr == pm2xxx_charger_current_map[i])
550 return i;
551 else
552 return -EINVAL;
553}
554
555static int pm2xxx_voltage_to_regval(int curr)
556{
557 int i;
558
559 if (curr < pm2xxx_charger_voltage_map[0])
560 return 0;
561
562 for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
563 if (curr < pm2xxx_charger_voltage_map[i])
564 return i - 1;
565 }
566
567 i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
568 if (curr == pm2xxx_charger_voltage_map[i])
569 return i;
570 else
571 return -EINVAL;
572}
573
574static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
575 int ich_out)
576{
577 int ret;
578 int curr_index;
579 struct pm2xxx_charger *pm2;
580 u8 val;
581
582 if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
583 pm2 = to_pm2xxx_charger_ac_device_info(charger);
584 else
585 return -ENXIO;
586
587 curr_index = pm2xxx_current_to_regval(ich_out);
588 if (curr_index < 0) {
589 dev_err(pm2->dev,
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200590 "Charger current too high, charging not started\n");
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200591 return -ENXIO;
592 }
593
594 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
595 if (ret >= 0) {
596 val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
597 val |= curr_index;
598 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
599 if (ret < 0) {
600 dev_err(pm2->dev,
601 "%s write failed\n", __func__);
602 }
603 }
604 else
605 dev_err(pm2->dev, "%s read failed\n", __func__);
606
607 return ret;
608}
609
610static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
611 enum power_supply_property psp,
612 union power_supply_propval *val)
613{
614 struct pm2xxx_charger *pm2;
615
616 pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
617
618 switch (psp) {
619 case POWER_SUPPLY_PROP_HEALTH:
620 if (pm2->flags.mainextchnotok)
621 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
622 else if (pm2->ac.wd_expired)
623 val->intval = POWER_SUPPLY_HEALTH_DEAD;
624 else if (pm2->flags.main_thermal_prot)
625 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
Rupesh Kumar789ca7b2012-06-19 10:21:24 +0530626 else if (pm2->flags.ovv)
627 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200628 else
629 val->intval = POWER_SUPPLY_HEALTH_GOOD;
630 break;
631 case POWER_SUPPLY_PROP_ONLINE:
632 val->intval = pm2->ac.charger_online;
633 break;
634 case POWER_SUPPLY_PROP_PRESENT:
635 val->intval = pm2->ac.charger_connected;
636 break;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200637 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
638 pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
639 val->intval = pm2->ac.cv_active;
640 break;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200641 default:
642 return -EINVAL;
643 }
644 return 0;
645}
646
647static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
648{
649 int ret = 0;
650
651 /* enable CC and CV watchdog */
652 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
653 (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
654 if( ret < 0)
655 return ret;
656
657 /* enable precharge watchdog */
658 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
659 PM2XXX_CH_WD_PRECH_PHASE_60MIN);
660
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200661 /* Disable auto timeout */
662 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
663 PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
664
665 /*
666 * EOC current level = 100mA
667 * Precharge current level = 100mA
668 * CC current level = 1000mA
669 */
670 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
671 (PM2XXX_DIR_CH_CC_CURRENT_1000MA |
672 PM2XXX_CH_PRECH_CURRENT_100MA |
673 PM2XXX_CH_EOC_CURRENT_100MA));
674
675 /*
676 * recharge threshold = 3.8V
677 * Precharge to CC threshold = 2.9V
678 */
679 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
680 (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
681
682 /* float voltage charger level = 4.2V */
683 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
684 PM2XXX_CH_VOLT_4_2);
685
686 /* Voltage drop between VBAT and VSYS in HW charging = 300mV */
687 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
688 (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
689 PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
690 PM2XXX_CH_CC_MODEDROP_DIS));
691
692 /* Input charger level of over voltage = 10V */
693 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
694 PM2XXX_VPWR2_OVV_10);
695 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
696 PM2XXX_VPWR1_OVV_10);
697
698 /* Input charger drop */
699 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
700 (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
701 PM2XXX_VPWR2_DROP_DIS));
702 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
703 (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
704 PM2XXX_VPWR1_DROP_DIS));
705
706 /* Disable battery low monitoring */
707 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530708 PM2XXX_VBAT_LOW_MONITORING_ENA);
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200709
710 /* Disable LED */
711 ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG,
712 PM2XXX_LED_SELECT_DIS);
713
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200714 return ret;
715}
716
717static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
718 int enable, int vset, int iset)
719{
720 int ret;
721 int volt_index;
722 int curr_index;
723 u8 val;
724
725 struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
726
727 if (enable) {
728 if (!pm2->ac.charger_connected) {
729 dev_dbg(pm2->dev, "AC charger not connected\n");
730 return -ENXIO;
731 }
732
733 dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
734 if (!pm2->vddadc_en_ac) {
735 regulator_enable(pm2->regu);
736 pm2->vddadc_en_ac = true;
737 }
738
739 ret = pm2xxx_charging_init(pm2);
740 if (ret < 0) {
741 dev_err(pm2->dev, "%s charging init failed\n",
742 __func__);
743 goto error_occured;
744 }
745
746 volt_index = pm2xxx_voltage_to_regval(vset);
747 curr_index = pm2xxx_current_to_regval(iset);
748
749 if (volt_index < 0 || curr_index < 0) {
750 dev_err(pm2->dev,
751 "Charger voltage or current too high, "
752 "charging not started\n");
753 return -ENXIO;
754 }
755
756 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530757 if (ret < 0) {
758 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
759 goto error_occured;
760 }
761 val &= ~PM2XXX_CH_VOLT_MASK;
762 val |= volt_index;
763 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
764 if (ret < 0) {
765 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
766 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200767 }
768
769 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530770 if (ret < 0) {
771 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
772 goto error_occured;
773 }
774 val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
775 val |= curr_index;
776 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
777 if (ret < 0) {
778 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
779 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200780 }
781
782 if (!pm2->bat->enable_overshoot) {
783 ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530784 if (ret < 0) {
785 dev_err(pm2->dev, "%s pm2xxx read failed\n",
786 __func__);
787 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200788 }
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530789 val |= PM2XXX_ANTI_OVERSHOOT_EN;
790 ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
791 if (ret < 0) {
792 dev_err(pm2->dev, "%s pm2xxx write failed\n",
793 __func__);
794 goto error_occured;
795 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200796 }
797
798 ret = pm2xxx_charging_enable_mngt(pm2);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530799 if (ret < 0) {
800 dev_err(pm2->dev, "Failed to enable"
801 "pm2xxx ac charger\n");
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200802 goto error_occured;
803 }
804
805 pm2->ac.charger_online = 1;
806 } else {
807 pm2->ac.charger_online = 0;
808 pm2->ac.wd_expired = false;
809
810 /* Disable regulator if enabled */
811 if (pm2->vddadc_en_ac) {
812 regulator_disable(pm2->regu);
813 pm2->vddadc_en_ac = false;
814 }
815
816 ret = pm2xxx_charging_disable_mngt(pm2);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530817 if (ret < 0) {
818 dev_err(pm2->dev, "failed to disable"
819 "pm2xxx ac charger\n");
820 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200821 }
822
823 dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
824 }
825 power_supply_changed(&pm2->ac_chg.psy);
826
827error_occured:
828 return ret;
829}
830
831static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
832{
833 int ret;
834 struct pm2xxx_charger *pm2;
835
836 if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
837 pm2 = to_pm2xxx_charger_ac_device_info(charger);
838 else
839 return -ENXIO;
840
841 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
842 if (ret)
843 dev_err(pm2->dev, "Failed to kick WD!\n");
844
845 return ret;
846}
847
848static void pm2xxx_charger_ac_work(struct work_struct *work)
849{
850 struct pm2xxx_charger *pm2 = container_of(work,
851 struct pm2xxx_charger, ac_work);
852
853
854 power_supply_changed(&pm2->ac_chg.psy);
855 sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
856};
857
Rupesh Kumar789ca7b2012-06-19 10:21:24 +0530858static void pm2xxx_charger_check_hw_failure_work(struct work_struct *work)
859{
860 u8 reg_value;
861
862 struct pm2xxx_charger *pm2 = container_of(work,
863 struct pm2xxx_charger, check_hw_failure_work.work);
864
865 if (pm2->flags.ovv) {
866 pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &reg_value);
867
868 if (!(reg_value & (PM2XXX_INT4_S_ITVPWR1OVV |
869 PM2XXX_INT4_S_ITVPWR2OVV))) {
870 pm2->flags.ovv = false;
871 power_supply_changed(&pm2->ac_chg.psy);
872 }
873 }
874
875 /* If we still have a failure, schedule a new check */
876 if (pm2->flags.ovv) {
877 queue_delayed_work(pm2->charger_wq,
878 &pm2->check_hw_failure_work, round_jiffies(HZ));
879 }
880}
881
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200882static void pm2xxx_charger_check_main_thermal_prot_work(
883 struct work_struct *work)
884{
885};
886
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200887static struct pm2xxx_interrupts pm2xxx_int = {
888 .handler[0] = pm2_int_reg0,
889 .handler[1] = pm2_int_reg1,
890 .handler[2] = pm2_int_reg2,
891 .handler[3] = pm2_int_reg3,
892 .handler[4] = pm2_int_reg4,
893 .handler[5] = pm2_int_reg5,
894};
895
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200896static struct pm2xxx_irq pm2xxx_charger_irq[] = {
897 {"PM2XXX_IRQ_INT", pm2xxx_irq_int},
898};
899
900static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client)
901{
902 return 0;
903}
904
905static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client,
906 pm_message_t state)
907{
908 return 0;
909}
910
Lee Jones116c3262013-02-25 14:26:52 +0000911static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200912 const struct i2c_device_id *id)
913{
914 struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
915 struct pm2xxx_charger *pm2;
916 int ret = 0;
917 u8 val;
918
919 pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
920 if (!pm2) {
921 dev_err(pm2->dev, "pm2xxx_charger allocation failed\n");
922 return -ENOMEM;
923 }
924
925 /* get parent data */
926 pm2->dev = &i2c_client->dev;
927 pm2->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
928
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200929 pm2->pm2_int = &pm2xxx_int;
930
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200931 /* get charger spcific platform data */
932 if (!pl_data->wall_charger) {
933 dev_err(pm2->dev, "no charger platform data supplied\n");
934 ret = -EINVAL;
935 goto free_device_info;
936 }
937
938 pm2->pdata = pl_data->wall_charger;
939
940 /* get battery specific platform data */
941 if (!pl_data->battery) {
942 dev_err(pm2->dev, "no battery platform data supplied\n");
943 ret = -EINVAL;
944 goto free_device_info;
945 }
946
947 pm2->bat = pl_data->battery;
948
Lee Jones39880432013-01-23 14:38:15 +0000949 /*get lpn GPIO from platform data*/
950 if (!pm2->pdata->lpn_gpio) {
951 dev_err(pm2->dev, "no lpn gpio data supplied\n");
952 ret = -EINVAL;
953 goto free_device_info;
954 }
955 pm2->lpn_pin = pm2->pdata->lpn_gpio;
956
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200957 if (!i2c_check_functionality(i2c_client->adapter,
958 I2C_FUNC_SMBUS_BYTE_DATA |
959 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
960 ret = -ENODEV;
961 dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
962 goto free_device_info;
963 }
964
965 pm2->config.pm2xxx_i2c = i2c_client;
966 pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
967 i2c_set_clientdata(i2c_client, pm2);
968
969 /* AC supply */
970 /* power_supply base class */
971 pm2->ac_chg.psy.name = pm2->pdata->label;
972 pm2->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
973 pm2->ac_chg.psy.properties = pm2xxx_charger_ac_props;
974 pm2->ac_chg.psy.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
975 pm2->ac_chg.psy.get_property = pm2xxx_charger_ac_get_property;
976 pm2->ac_chg.psy.supplied_to = pm2->pdata->supplied_to;
977 pm2->ac_chg.psy.num_supplicants = pm2->pdata->num_supplicants;
978 /* pm2xxx_charger sub-class */
979 pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
980 pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
981 pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
982 pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
983 ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
984 pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
985 ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
Loic Pallardye07a5642012-05-10 15:33:56 +0200986 pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200987 pm2->ac_chg.enabled = true;
Loic Pallardye07a5642012-05-10 15:33:56 +0200988 pm2->ac_chg.external = true;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200989
990 /* Create a work queue for the charger */
991 pm2->charger_wq =
992 create_singlethread_workqueue("pm2xxx_charger_wq");
993 if (pm2->charger_wq == NULL) {
994 dev_err(pm2->dev, "failed to create work queue\n");
995 goto free_device_info;
996 }
997
998 /* Init work for charger detection */
999 INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
1000
1001 /* Init work for checking HW status */
1002 INIT_WORK(&pm2->check_main_thermal_prot_work,
1003 pm2xxx_charger_check_main_thermal_prot_work);
1004
Rupesh Kumar789ca7b2012-06-19 10:21:24 +05301005 /* Init work for HW failure check */
1006 INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work,
1007 pm2xxx_charger_check_hw_failure_work);
1008
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001009 /*
1010 * VDD ADC supply needs to be enabled from this driver when there
1011 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
1012 * interrupts during charging
1013 */
1014 pm2->regu = regulator_get(pm2->dev, "vddadc");
1015 if (IS_ERR(pm2->regu)) {
1016 ret = PTR_ERR(pm2->regu);
1017 dev_err(pm2->dev, "failed to get vddadc regulator\n");
1018 goto free_charger_wq;
1019 }
1020
1021 /* Register AC charger class */
1022 ret = power_supply_register(pm2->dev, &pm2->ac_chg.psy);
1023 if (ret) {
1024 dev_err(pm2->dev, "failed to register AC charger\n");
1025 goto free_regulator;
1026 }
1027
1028 /* Register interrupts */
1029 ret = request_threaded_irq(pm2->pdata->irq_number, NULL,
1030 pm2xxx_charger_irq[0].isr,
1031 pm2->pdata->irq_type,
1032 pm2xxx_charger_irq[0].name, pm2);
1033
1034 if (ret != 0) {
1035 dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
1036 pm2xxx_charger_irq[0].name, pm2->pdata->irq_number, ret);
1037 goto unregister_pm2xxx_charger;
1038 }
1039
Lee Jones39880432013-01-23 14:38:15 +00001040 /*Initialize lock*/
1041 mutex_init(&pm2->lock);
1042
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001043 /*
Lee Jones39880432013-01-23 14:38:15 +00001044 * Charger detection mechanism requires pulling up the LPN pin
1045 * while i2c communication if Charger is not connected
1046 * LPN pin of PM2301 is GPIO60 of AB9540
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001047 */
Lee Jones39880432013-01-23 14:38:15 +00001048 ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
1049 if (ret < 0) {
1050 dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
1051 goto unregister_pm2xxx_charger;
1052 }
1053 ret = gpio_direction_output(pm2->lpn_pin, 0);
1054 if (ret < 0) {
1055 dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
1056 goto free_gpio;
1057 }
1058
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001059 ret = pm2xxx_charger_detection(pm2, &val);
1060
1061 if ((ret == 0) && val) {
1062 pm2->ac.charger_connected = 1;
1063 pm2->ac_conn = true;
1064 power_supply_changed(&pm2->ac_chg.psy);
1065 sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
1066 }
1067
1068 return 0;
1069
Lee Jones39880432013-01-23 14:38:15 +00001070free_gpio:
1071 gpio_free(pm2->lpn_pin);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001072unregister_pm2xxx_charger:
1073 /* unregister power supply */
1074 power_supply_unregister(&pm2->ac_chg.psy);
1075free_regulator:
1076 /* disable the regulator */
1077 regulator_put(pm2->regu);
1078free_charger_wq:
1079 destroy_workqueue(pm2->charger_wq);
1080free_device_info:
1081 kfree(pm2);
1082 return ret;
1083}
1084
Lee Jones116c3262013-02-25 14:26:52 +00001085static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001086{
1087 struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
1088
1089 /* Disable AC charging */
1090 pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
1091
1092 /* Disable interrupts */
1093 free_irq(pm2->pdata->irq_number, pm2);
1094
1095 /* Delete the work queue */
1096 destroy_workqueue(pm2->charger_wq);
1097
1098 flush_scheduled_work();
1099
1100 /* disable the regulator */
1101 regulator_put(pm2->regu);
1102
1103 power_supply_unregister(&pm2->ac_chg.psy);
1104
Lee Jones39880432013-01-23 14:38:15 +00001105 /*Free GPIO60*/
1106 gpio_free(pm2->lpn_pin);
1107
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001108 kfree(pm2);
1109
1110 return 0;
1111}
1112
1113static const struct i2c_device_id pm2xxx_id[] = {
1114 { "pm2301", 0 },
1115 { }
1116};
1117
1118MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
1119
1120static struct i2c_driver pm2xxx_charger_driver = {
1121 .probe = pm2xxx_wall_charger_probe,
Lee Jones116c3262013-02-25 14:26:52 +00001122 .remove = pm2xxx_wall_charger_remove,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001123 .suspend = pm2xxx_wall_charger_suspend,
1124 .resume = pm2xxx_wall_charger_resume,
1125 .driver = {
1126 .name = "pm2xxx-wall_charger",
1127 .owner = THIS_MODULE,
1128 },
1129 .id_table = pm2xxx_id,
1130};
1131
1132static int __init pm2xxx_charger_init(void)
1133{
1134 return i2c_add_driver(&pm2xxx_charger_driver);
1135}
1136
1137static void __exit pm2xxx_charger_exit(void)
1138{
1139 i2c_del_driver(&pm2xxx_charger_driver);
1140}
1141
1142subsys_initcall_sync(pm2xxx_charger_init);
1143module_exit(pm2xxx_charger_exit);
1144
1145MODULE_LICENSE("GPL v2");
1146MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
1147MODULE_ALIAS("platform:pm2xxx-charger");
1148MODULE_DESCRIPTION("PM2xxx charger management driver");