blob: b2f2d4188da9ffa055244e3619ff22464d3253e4 [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 Jones2fa5b0f42013-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 Jones2fa5b0f42013-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{
230 int ret = 0;
231
232 pm2->failure_input_ovv++;
233 if (pm2->failure_input_ovv < 4) {
234 ret = pm2xxx_charging_enable_mngt(pm2);
235 goto out;
236 } else {
237 pm2->failure_input_ovv = 0;
238 dev_err(pm2->dev, "Overvoltage detected\n");
239 pm2->flags.ovv = true;
240 power_supply_changed(&pm2->ac_chg.psy);
241 }
242
243out:
244 return ret;
245}
246
247static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
248{
249 dev_dbg(pm2->dev , "20 minutes watchdog occured\n");
250
251 pm2->ac.wd_expired = true;
252 power_supply_changed(&pm2->ac_chg.psy);
253
254 return 0;
255}
256
257static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
258{
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530259 int ret;
260
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200261 switch (val) {
262 case PM2XXX_INT1_ITVBATLOWR:
263 dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530264 /* Enable SW EOC ctrl */
265 ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
266 PM2XXX_SWCTRL_SW);
267 if (ret < 0) {
268 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
269 return ret;
270 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200271 break;
272
273 case PM2XXX_INT1_ITVBATLOWF:
274 dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530275 /* Disable SW EOC ctrl */
276 ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
277 PM2XXX_SWCTRL_HW);
278 if (ret < 0) {
279 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
280 return ret;
281 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200282 break;
283
284 default:
285 dev_err(pm2->dev, "Unknown VBAT level\n");
286 }
287
288 return 0;
289}
290
291static int pm2xxx_charger_bat_disc_mngt(struct pm2xxx_charger *pm2, int val)
292{
293 dev_dbg(pm2->dev, "battery disconnected\n");
294
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200295 return 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200296}
297
298static int pm2xxx_charger_detection(struct pm2xxx_charger *pm2, u8 *val)
299{
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530300 int ret;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200301
302 ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT2, val);
303
304 if (ret < 0) {
305 dev_err(pm2->dev, "Charger detection failed\n");
306 goto out;
307 }
308
309 *val &= (PM2XXX_INT2_S_ITVPWR1PLUG | PM2XXX_INT2_S_ITVPWR2PLUG);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530310
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200311out:
312 return ret;
313}
314
315static int pm2xxx_charger_itv_pwr_plug_mngt(struct pm2xxx_charger *pm2, int val)
316{
317
318 int ret;
319 u8 read_val;
320
321 /*
322 * Since we can't be sure that the events are received
323 * synchronously, we have the check if the main charger is
324 * connected by reading the interrupt source register.
325 */
326 ret = pm2xxx_charger_detection(pm2, &read_val);
327
328 if ((ret == 0) && read_val) {
329 pm2->ac.charger_connected = 1;
330 pm2->ac_conn = true;
331 queue_work(pm2->charger_wq, &pm2->ac_work);
332 }
333
334
335 return ret;
336}
337
338static int pm2xxx_charger_itv_pwr_unplug_mngt(struct pm2xxx_charger *pm2,
339 int val)
340{
341 pm2->ac.charger_connected = 0;
342 queue_work(pm2->charger_wq, &pm2->ac_work);
343
344 return 0;
345}
346
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200347static int pm2_int_reg0(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200348{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200349 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200350 int ret = 0;
351
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530352 if (val & PM2XXX_INT1_ITVBATLOWR) {
353 ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
354 PM2XXX_INT1_ITVBATLOWR);
355 if (ret < 0)
356 goto out;
357 }
358
359 if (val & PM2XXX_INT1_ITVBATLOWF) {
360 ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
361 PM2XXX_INT1_ITVBATLOWF);
362 if (ret < 0)
363 goto out;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200364 }
365
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200366 if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200367 ret = pm2xxx_charger_bat_disc_mngt(pm2,
368 PM2XXX_INT1_ITVBATDISCONNECT);
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530369 if (ret < 0)
370 goto out;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200371 }
Rajkumar Kasirajan584f9702012-06-05 12:31:25 +0530372out:
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200373 return ret;
374}
375
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200376static int pm2_int_reg1(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200377{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200378 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200379 int ret = 0;
380
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200381 if (val & (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200382 dev_dbg(pm2->dev , "Main charger plugged\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200383 ret = pm2xxx_charger_itv_pwr_plug_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200384 (PM2XXX_INT2_ITVPWR1PLUG | PM2XXX_INT2_ITVPWR2PLUG));
385 }
386
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200387 if (val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200388 (PM2XXX_INT2_ITVPWR1UNPLUG | PM2XXX_INT2_ITVPWR2UNPLUG)) {
389 dev_dbg(pm2->dev , "Main charger unplugged\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200390 ret = pm2xxx_charger_itv_pwr_unplug_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200391 (PM2XXX_INT2_ITVPWR1UNPLUG |
392 PM2XXX_INT2_ITVPWR2UNPLUG));
393 }
394
395 return ret;
396}
397
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200398static int pm2_int_reg2(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200399{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200400 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200401 int ret = 0;
402
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200403 if (val & PM2XXX_INT3_ITAUTOTIMEOUTWD)
404 ret = pm2xxx_charger_wd_exp_mngt(pm2, val);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200405
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200406 if (val & (PM2XXX_INT3_ITCHPRECHARGEWD |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200407 PM2XXX_INT3_ITCHCCWD | PM2XXX_INT3_ITCHCVWD)) {
408 dev_dbg(pm2->dev,
409 "Watchdog occured for precharge, CC and CV charge\n");
410 }
411
412 return ret;
413}
414
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200415static int pm2_int_reg3(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200416{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200417 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200418 int ret = 0;
419
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200420 if (val & (PM2XXX_INT4_ITCHARGINGON)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200421 dev_dbg(pm2->dev ,
422 "chargind operation has started\n");
423 }
424
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200425 if (val & (PM2XXX_INT4_ITVRESUME)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200426 dev_dbg(pm2->dev,
427 "battery discharged down to VResume threshold\n");
428 }
429
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200430 if (val & (PM2XXX_INT4_ITBATTFULL)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200431 dev_dbg(pm2->dev , "battery fully detected\n");
432 }
433
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200434 if (val & (PM2XXX_INT4_ITCVPHASE)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200435 dev_dbg(pm2->dev, "CV phase enter with 0.5C charging\n");
436 }
437
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200438 if (val & (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200439 pm2->failure_case = VPWR_OVV;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200440 ret = pm2xxx_charger_ovv_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200441 (PM2XXX_INT4_ITVPWR2OVV | PM2XXX_INT4_ITVPWR1OVV));
442 dev_dbg(pm2->dev, "VPWR/VSYSTEM overvoltage detected\n");
443 }
444
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200445 if (val & (PM2XXX_INT4_S_ITBATTEMPCOLD |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200446 PM2XXX_INT4_S_ITBATTEMPHOT)) {
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200447 ret = pm2xxx_charger_batt_therm_mngt(pm2, val &
448 (PM2XXX_INT4_S_ITBATTEMPCOLD |
449 PM2XXX_INT4_S_ITBATTEMPHOT));
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200450 dev_dbg(pm2->dev, "BTEMP is too Low/High\n");
451 }
452
453 return ret;
454}
455
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200456static int pm2_int_reg4(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200457{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200458 struct pm2xxx_charger *pm2 = pm2_data;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200459 int ret = 0;
460
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200461 if (val & PM2XXX_INT5_ITVSYSTEMOVV) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200462 pm2->failure_case = VSYSTEM_OVV;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200463 ret = pm2xxx_charger_ovv_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200464 PM2XXX_INT5_ITVSYSTEMOVV);
465 dev_dbg(pm2->dev, "VSYSTEM overvoltage detected\n");
466 }
467
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200468 if (val & (PM2XXX_INT5_ITTHERMALWARNINGFALL |
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200469 PM2XXX_INT5_ITTHERMALWARNINGRISE |
470 PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
471 PM2XXX_INT5_ITTHERMALSHUTDOWNRISE)) {
472 dev_dbg(pm2->dev, "BTEMP die temperature is too Low/High\n");
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200473 ret = pm2xxx_charger_die_therm_mngt(pm2, val &
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200474 (PM2XXX_INT5_ITTHERMALWARNINGFALL |
475 PM2XXX_INT5_ITTHERMALWARNINGRISE |
476 PM2XXX_INT5_ITTHERMALSHUTDOWNFALL |
477 PM2XXX_INT5_ITTHERMALSHUTDOWNRISE));
478 }
479
480 return ret;
481}
482
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200483static int pm2_int_reg5(void *pm2_data, int val)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200484{
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200485 struct pm2xxx_charger *pm2 = pm2_data;
486 int ret = 0;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200487
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200488
489 if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200490 dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
491 }
492
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200493 if (val & (PM2XXX_INT6_ITVPWR2VALIDRISE |
494 PM2XXX_INT6_ITVPWR1VALIDRISE |
495 PM2XXX_INT6_ITVPWR2VALIDFALL |
496 PM2XXX_INT6_ITVPWR1VALIDFALL)) {
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200497 dev_dbg(pm2->dev, "Falling/Rising edge on WPWR1/2\n");
498 }
499
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200500 return ret;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200501}
502
503static irqreturn_t pm2xxx_irq_int(int irq, void *data)
504{
505 struct pm2xxx_charger *pm2 = data;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200506 struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
507 int i;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200508
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200509 for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
510 pm2xxx_reg_read(pm2,
511 pm2xxx_interrupt_registers[i],
512 &(interrupt->reg[i]));
513
514 if (interrupt->reg[i] > 0)
515 interrupt->handler[i](pm2, interrupt->reg[i]);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200516 }
517
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200518 return IRQ_HANDLED;
519}
520
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200521static int pm2xxx_charger_get_ac_cv(struct pm2xxx_charger *pm2)
522{
523 int ret = 0;
524 u8 val;
525
526 if (pm2->ac.charger_connected && pm2->ac.charger_online) {
527
528 ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &val);
529 if (ret < 0) {
530 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
531 goto out;
532 }
533
534 if (val & PM2XXX_INT4_S_ITCVPHASE)
535 ret = PM2XXX_CONST_VOLT;
536 else
537 ret = PM2XXX_CONST_CURR;
538 }
539out:
540 return ret;
541}
542
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200543static int pm2xxx_current_to_regval(int curr)
544{
545 int i;
546
547 if (curr < pm2xxx_charger_current_map[0])
548 return 0;
549
550 for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_current_map); i++) {
551 if (curr < pm2xxx_charger_current_map[i])
552 return (i - 1);
553 }
554
555 i = ARRAY_SIZE(pm2xxx_charger_current_map) - 1;
556 if (curr == pm2xxx_charger_current_map[i])
557 return i;
558 else
559 return -EINVAL;
560}
561
562static int pm2xxx_voltage_to_regval(int curr)
563{
564 int i;
565
566 if (curr < pm2xxx_charger_voltage_map[0])
567 return 0;
568
569 for (i = 1; i < ARRAY_SIZE(pm2xxx_charger_voltage_map); i++) {
570 if (curr < pm2xxx_charger_voltage_map[i])
571 return i - 1;
572 }
573
574 i = ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1;
575 if (curr == pm2xxx_charger_voltage_map[i])
576 return i;
577 else
578 return -EINVAL;
579}
580
581static int pm2xxx_charger_update_charger_current(struct ux500_charger *charger,
582 int ich_out)
583{
584 int ret;
585 int curr_index;
586 struct pm2xxx_charger *pm2;
587 u8 val;
588
589 if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
590 pm2 = to_pm2xxx_charger_ac_device_info(charger);
591 else
592 return -ENXIO;
593
594 curr_index = pm2xxx_current_to_regval(ich_out);
595 if (curr_index < 0) {
596 dev_err(pm2->dev,
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200597 "Charger current too high, charging not started\n");
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200598 return -ENXIO;
599 }
600
601 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
602 if (ret >= 0) {
603 val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
604 val |= curr_index;
605 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
606 if (ret < 0) {
607 dev_err(pm2->dev,
608 "%s write failed\n", __func__);
609 }
610 }
611 else
612 dev_err(pm2->dev, "%s read failed\n", __func__);
613
614 return ret;
615}
616
617static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
618 enum power_supply_property psp,
619 union power_supply_propval *val)
620{
621 struct pm2xxx_charger *pm2;
622
623 pm2 = to_pm2xxx_charger_ac_device_info(psy_to_ux500_charger(psy));
624
625 switch (psp) {
626 case POWER_SUPPLY_PROP_HEALTH:
627 if (pm2->flags.mainextchnotok)
628 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
629 else if (pm2->ac.wd_expired)
630 val->intval = POWER_SUPPLY_HEALTH_DEAD;
631 else if (pm2->flags.main_thermal_prot)
632 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
633 else
634 val->intval = POWER_SUPPLY_HEALTH_GOOD;
635 break;
636 case POWER_SUPPLY_PROP_ONLINE:
637 val->intval = pm2->ac.charger_online;
638 break;
639 case POWER_SUPPLY_PROP_PRESENT:
640 val->intval = pm2->ac.charger_connected;
641 break;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200642 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
643 pm2->ac.cv_active = pm2xxx_charger_get_ac_cv(pm2);
644 val->intval = pm2->ac.cv_active;
645 break;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200646 default:
647 return -EINVAL;
648 }
649 return 0;
650}
651
652static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
653{
654 int ret = 0;
655
656 /* enable CC and CV watchdog */
657 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG3,
658 (PM2XXX_CH_WD_CV_PHASE_60MIN | PM2XXX_CH_WD_CC_PHASE_60MIN));
659 if( ret < 0)
660 return ret;
661
662 /* enable precharge watchdog */
663 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG4,
664 PM2XXX_CH_WD_PRECH_PHASE_60MIN);
665
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200666 /* Disable auto timeout */
667 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG5,
668 PM2XXX_CH_WD_AUTO_TIMEOUT_20MIN);
669
670 /*
671 * EOC current level = 100mA
672 * Precharge current level = 100mA
673 * CC current level = 1000mA
674 */
675 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6,
676 (PM2XXX_DIR_CH_CC_CURRENT_1000MA |
677 PM2XXX_CH_PRECH_CURRENT_100MA |
678 PM2XXX_CH_EOC_CURRENT_100MA));
679
680 /*
681 * recharge threshold = 3.8V
682 * Precharge to CC threshold = 2.9V
683 */
684 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG7,
685 (PM2XXX_CH_PRECH_VOL_2_9 | PM2XXX_CH_VRESUME_VOL_3_8));
686
687 /* float voltage charger level = 4.2V */
688 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8,
689 PM2XXX_CH_VOLT_4_2);
690
691 /* Voltage drop between VBAT and VSYS in HW charging = 300mV */
692 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG9,
693 (PM2XXX_CH_150MV_DROP_300MV | PM2XXX_CHARCHING_INFO_DIS |
694 PM2XXX_CH_CC_REDUCED_CURRENT_IDENT |
695 PM2XXX_CH_CC_MODEDROP_DIS));
696
697 /* Input charger level of over voltage = 10V */
698 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR2,
699 PM2XXX_VPWR2_OVV_10);
700 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_VOLT_VPWR1,
701 PM2XXX_VPWR1_OVV_10);
702
703 /* Input charger drop */
704 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR2,
705 (PM2XXX_VPWR2_HW_OPT_DIS | PM2XXX_VPWR2_VALID_DIS |
706 PM2XXX_VPWR2_DROP_DIS));
707 ret = pm2xxx_reg_write(pm2, PM2XXX_INP_DROP_VPWR1,
708 (PM2XXX_VPWR1_HW_OPT_DIS | PM2XXX_VPWR1_VALID_DIS |
709 PM2XXX_VPWR1_DROP_DIS));
710
711 /* Disable battery low monitoring */
712 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530713 PM2XXX_VBAT_LOW_MONITORING_ENA);
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200714
715 /* Disable LED */
716 ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG,
717 PM2XXX_LED_SELECT_DIS);
718
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200719 return ret;
720}
721
722static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
723 int enable, int vset, int iset)
724{
725 int ret;
726 int volt_index;
727 int curr_index;
728 u8 val;
729
730 struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);
731
732 if (enable) {
733 if (!pm2->ac.charger_connected) {
734 dev_dbg(pm2->dev, "AC charger not connected\n");
735 return -ENXIO;
736 }
737
738 dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
739 if (!pm2->vddadc_en_ac) {
740 regulator_enable(pm2->regu);
741 pm2->vddadc_en_ac = true;
742 }
743
744 ret = pm2xxx_charging_init(pm2);
745 if (ret < 0) {
746 dev_err(pm2->dev, "%s charging init failed\n",
747 __func__);
748 goto error_occured;
749 }
750
751 volt_index = pm2xxx_voltage_to_regval(vset);
752 curr_index = pm2xxx_current_to_regval(iset);
753
754 if (volt_index < 0 || curr_index < 0) {
755 dev_err(pm2->dev,
756 "Charger voltage or current too high, "
757 "charging not started\n");
758 return -ENXIO;
759 }
760
761 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530762 if (ret < 0) {
763 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
764 goto error_occured;
765 }
766 val &= ~PM2XXX_CH_VOLT_MASK;
767 val |= volt_index;
768 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
769 if (ret < 0) {
770 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
771 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200772 }
773
774 ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530775 if (ret < 0) {
776 dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
777 goto error_occured;
778 }
779 val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
780 val |= curr_index;
781 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
782 if (ret < 0) {
783 dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
784 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200785 }
786
787 if (!pm2->bat->enable_overshoot) {
788 ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530789 if (ret < 0) {
790 dev_err(pm2->dev, "%s pm2xxx read failed\n",
791 __func__);
792 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200793 }
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530794 val |= PM2XXX_ANTI_OVERSHOOT_EN;
795 ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
796 if (ret < 0) {
797 dev_err(pm2->dev, "%s pm2xxx write failed\n",
798 __func__);
799 goto error_occured;
800 }
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200801 }
802
803 ret = pm2xxx_charging_enable_mngt(pm2);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530804 if (ret < 0) {
805 dev_err(pm2->dev, "Failed to enable"
806 "pm2xxx ac charger\n");
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200807 goto error_occured;
808 }
809
810 pm2->ac.charger_online = 1;
811 } else {
812 pm2->ac.charger_online = 0;
813 pm2->ac.wd_expired = false;
814
815 /* Disable regulator if enabled */
816 if (pm2->vddadc_en_ac) {
817 regulator_disable(pm2->regu);
818 pm2->vddadc_en_ac = false;
819 }
820
821 ret = pm2xxx_charging_disable_mngt(pm2);
Rajkumar Kasirajane41f39e2012-05-28 15:57:33 +0530822 if (ret < 0) {
823 dev_err(pm2->dev, "failed to disable"
824 "pm2xxx ac charger\n");
825 goto error_occured;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200826 }
827
828 dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
829 }
830 power_supply_changed(&pm2->ac_chg.psy);
831
832error_occured:
833 return ret;
834}
835
836static int pm2xxx_charger_watchdog_kick(struct ux500_charger *charger)
837{
838 int ret;
839 struct pm2xxx_charger *pm2;
840
841 if (charger->psy.type == POWER_SUPPLY_TYPE_MAINS)
842 pm2 = to_pm2xxx_charger_ac_device_info(charger);
843 else
844 return -ENXIO;
845
846 ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_WD_KICK, WD_TIMER);
847 if (ret)
848 dev_err(pm2->dev, "Failed to kick WD!\n");
849
850 return ret;
851}
852
853static void pm2xxx_charger_ac_work(struct work_struct *work)
854{
855 struct pm2xxx_charger *pm2 = container_of(work,
856 struct pm2xxx_charger, ac_work);
857
858
859 power_supply_changed(&pm2->ac_chg.psy);
860 sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
861};
862
863static void pm2xxx_charger_check_main_thermal_prot_work(
864 struct work_struct *work)
865{
866};
867
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200868static struct pm2xxx_interrupts pm2xxx_int = {
869 .handler[0] = pm2_int_reg0,
870 .handler[1] = pm2_int_reg1,
871 .handler[2] = pm2_int_reg2,
872 .handler[3] = pm2_int_reg3,
873 .handler[4] = pm2_int_reg4,
874 .handler[5] = pm2_int_reg5,
875};
876
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200877static struct pm2xxx_irq pm2xxx_charger_irq[] = {
878 {"PM2XXX_IRQ_INT", pm2xxx_irq_int},
879};
880
881static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client)
882{
883 return 0;
884}
885
886static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client,
887 pm_message_t state)
888{
889 return 0;
890}
891
Lee Jones116c3262013-02-25 14:26:52 +0000892static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200893 const struct i2c_device_id *id)
894{
895 struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
896 struct pm2xxx_charger *pm2;
897 int ret = 0;
898 u8 val;
899
900 pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
901 if (!pm2) {
902 dev_err(pm2->dev, "pm2xxx_charger allocation failed\n");
903 return -ENOMEM;
904 }
905
906 /* get parent data */
907 pm2->dev = &i2c_client->dev;
908 pm2->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
909
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200910 pm2->pm2_int = &pm2xxx_int;
911
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200912 /* get charger spcific platform data */
913 if (!pl_data->wall_charger) {
914 dev_err(pm2->dev, "no charger platform data supplied\n");
915 ret = -EINVAL;
916 goto free_device_info;
917 }
918
919 pm2->pdata = pl_data->wall_charger;
920
921 /* get battery specific platform data */
922 if (!pl_data->battery) {
923 dev_err(pm2->dev, "no battery platform data supplied\n");
924 ret = -EINVAL;
925 goto free_device_info;
926 }
927
928 pm2->bat = pl_data->battery;
929
Lee Jones39880432013-01-23 14:38:15 +0000930 /*get lpn GPIO from platform data*/
931 if (!pm2->pdata->lpn_gpio) {
932 dev_err(pm2->dev, "no lpn gpio data supplied\n");
933 ret = -EINVAL;
934 goto free_device_info;
935 }
936 pm2->lpn_pin = pm2->pdata->lpn_gpio;
937
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200938 if (!i2c_check_functionality(i2c_client->adapter,
939 I2C_FUNC_SMBUS_BYTE_DATA |
940 I2C_FUNC_SMBUS_READ_WORD_DATA)) {
941 ret = -ENODEV;
942 dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
943 goto free_device_info;
944 }
945
946 pm2->config.pm2xxx_i2c = i2c_client;
947 pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
948 i2c_set_clientdata(i2c_client, pm2);
949
950 /* AC supply */
951 /* power_supply base class */
952 pm2->ac_chg.psy.name = pm2->pdata->label;
953 pm2->ac_chg.psy.type = POWER_SUPPLY_TYPE_MAINS;
954 pm2->ac_chg.psy.properties = pm2xxx_charger_ac_props;
955 pm2->ac_chg.psy.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
956 pm2->ac_chg.psy.get_property = pm2xxx_charger_ac_get_property;
957 pm2->ac_chg.psy.supplied_to = pm2->pdata->supplied_to;
958 pm2->ac_chg.psy.num_supplicants = pm2->pdata->num_supplicants;
959 /* pm2xxx_charger sub-class */
960 pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
961 pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
962 pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
963 pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
964 ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
965 pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
966 ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
Loic Pallardye07a5642012-05-10 15:33:56 +0200967 pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
Olivier Clergeaud006f82d2012-05-14 16:50:29 +0200968 pm2->ac_chg.enabled = true;
Loic Pallardye07a5642012-05-10 15:33:56 +0200969 pm2->ac_chg.external = true;
Michel JAOUEN01ec8c52012-04-26 10:00:04 +0200970
971 /* Create a work queue for the charger */
972 pm2->charger_wq =
973 create_singlethread_workqueue("pm2xxx_charger_wq");
974 if (pm2->charger_wq == NULL) {
975 dev_err(pm2->dev, "failed to create work queue\n");
976 goto free_device_info;
977 }
978
979 /* Init work for charger detection */
980 INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);
981
982 /* Init work for checking HW status */
983 INIT_WORK(&pm2->check_main_thermal_prot_work,
984 pm2xxx_charger_check_main_thermal_prot_work);
985
986 /*
987 * VDD ADC supply needs to be enabled from this driver when there
988 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
989 * interrupts during charging
990 */
991 pm2->regu = regulator_get(pm2->dev, "vddadc");
992 if (IS_ERR(pm2->regu)) {
993 ret = PTR_ERR(pm2->regu);
994 dev_err(pm2->dev, "failed to get vddadc regulator\n");
995 goto free_charger_wq;
996 }
997
998 /* Register AC charger class */
999 ret = power_supply_register(pm2->dev, &pm2->ac_chg.psy);
1000 if (ret) {
1001 dev_err(pm2->dev, "failed to register AC charger\n");
1002 goto free_regulator;
1003 }
1004
1005 /* Register interrupts */
1006 ret = request_threaded_irq(pm2->pdata->irq_number, NULL,
1007 pm2xxx_charger_irq[0].isr,
1008 pm2->pdata->irq_type,
1009 pm2xxx_charger_irq[0].name, pm2);
1010
1011 if (ret != 0) {
1012 dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
1013 pm2xxx_charger_irq[0].name, pm2->pdata->irq_number, ret);
1014 goto unregister_pm2xxx_charger;
1015 }
1016
Lee Jones39880432013-01-23 14:38:15 +00001017 /*Initialize lock*/
1018 mutex_init(&pm2->lock);
1019
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001020 /*
Lee Jones39880432013-01-23 14:38:15 +00001021 * Charger detection mechanism requires pulling up the LPN pin
1022 * while i2c communication if Charger is not connected
1023 * LPN pin of PM2301 is GPIO60 of AB9540
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001024 */
Lee Jones39880432013-01-23 14:38:15 +00001025 ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
1026 if (ret < 0) {
1027 dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
1028 goto unregister_pm2xxx_charger;
1029 }
1030 ret = gpio_direction_output(pm2->lpn_pin, 0);
1031 if (ret < 0) {
1032 dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
1033 goto free_gpio;
1034 }
1035
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001036 ret = pm2xxx_charger_detection(pm2, &val);
1037
1038 if ((ret == 0) && val) {
1039 pm2->ac.charger_connected = 1;
1040 pm2->ac_conn = true;
1041 power_supply_changed(&pm2->ac_chg.psy);
1042 sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
1043 }
1044
1045 return 0;
1046
Lee Jones39880432013-01-23 14:38:15 +00001047free_gpio:
1048 gpio_free(pm2->lpn_pin);
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001049unregister_pm2xxx_charger:
1050 /* unregister power supply */
1051 power_supply_unregister(&pm2->ac_chg.psy);
1052free_regulator:
1053 /* disable the regulator */
1054 regulator_put(pm2->regu);
1055free_charger_wq:
1056 destroy_workqueue(pm2->charger_wq);
1057free_device_info:
1058 kfree(pm2);
1059 return ret;
1060}
1061
Lee Jones116c3262013-02-25 14:26:52 +00001062static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001063{
1064 struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
1065
1066 /* Disable AC charging */
1067 pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
1068
1069 /* Disable interrupts */
1070 free_irq(pm2->pdata->irq_number, pm2);
1071
1072 /* Delete the work queue */
1073 destroy_workqueue(pm2->charger_wq);
1074
1075 flush_scheduled_work();
1076
1077 /* disable the regulator */
1078 regulator_put(pm2->regu);
1079
1080 power_supply_unregister(&pm2->ac_chg.psy);
1081
Lee Jones39880432013-01-23 14:38:15 +00001082 /*Free GPIO60*/
1083 gpio_free(pm2->lpn_pin);
1084
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001085 kfree(pm2);
1086
1087 return 0;
1088}
1089
1090static const struct i2c_device_id pm2xxx_id[] = {
1091 { "pm2301", 0 },
1092 { }
1093};
1094
1095MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
1096
1097static struct i2c_driver pm2xxx_charger_driver = {
1098 .probe = pm2xxx_wall_charger_probe,
Lee Jones116c3262013-02-25 14:26:52 +00001099 .remove = pm2xxx_wall_charger_remove,
Michel JAOUEN01ec8c52012-04-26 10:00:04 +02001100 .suspend = pm2xxx_wall_charger_suspend,
1101 .resume = pm2xxx_wall_charger_resume,
1102 .driver = {
1103 .name = "pm2xxx-wall_charger",
1104 .owner = THIS_MODULE,
1105 },
1106 .id_table = pm2xxx_id,
1107};
1108
1109static int __init pm2xxx_charger_init(void)
1110{
1111 return i2c_add_driver(&pm2xxx_charger_driver);
1112}
1113
1114static void __exit pm2xxx_charger_exit(void)
1115{
1116 i2c_del_driver(&pm2xxx_charger_driver);
1117}
1118
1119subsys_initcall_sync(pm2xxx_charger_init);
1120module_exit(pm2xxx_charger_exit);
1121
1122MODULE_LICENSE("GPL v2");
1123MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
1124MODULE_ALIAS("platform:pm2xxx-charger");
1125MODULE_DESCRIPTION("PM2xxx charger management driver");
1126