2 * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver
4 * Copyright (C) 2011 Samsung Electronics
5 * MyungJoo Ham <myungjoo.ham@samsung.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/gpio.h>
24 #include <linux/interrupt.h>
25 #include <linux/slab.h>
26 #include <linux/power_supply.h>
27 #include <linux/platform_device.h>
28 #include <linux/power/max8903_charger.h>
31 struct max8903_pdata
*pdata
;
33 struct power_supply psy
;
39 static enum power_supply_property max8903_charger_props
[] = {
40 POWER_SUPPLY_PROP_STATUS
, /* Charger status output */
41 POWER_SUPPLY_PROP_ONLINE
, /* External power source */
42 POWER_SUPPLY_PROP_HEALTH
, /* Fault or OK */
45 static int max8903_get_property(struct power_supply
*psy
,
46 enum power_supply_property psp
,
47 union power_supply_propval
*val
)
49 struct max8903_data
*data
= container_of(psy
,
50 struct max8903_data
, psy
);
53 case POWER_SUPPLY_PROP_STATUS
:
54 val
->intval
= POWER_SUPPLY_STATUS_UNKNOWN
;
55 if (data
->pdata
->chg
) {
56 if (gpio_get_value(data
->pdata
->chg
) == 0)
57 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
58 else if (data
->usb_in
|| data
->ta_in
)
59 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
61 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
64 case POWER_SUPPLY_PROP_ONLINE
:
66 if (data
->usb_in
|| data
->ta_in
)
69 case POWER_SUPPLY_PROP_HEALTH
:
70 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
72 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
80 static irqreturn_t
max8903_dcin(int irq
, void *_data
)
82 struct max8903_data
*data
= _data
;
83 struct max8903_pdata
*pdata
= data
->pdata
;
85 enum power_supply_type old_type
;
87 ta_in
= gpio_get_value(pdata
->dok
) ? false : true;
89 if (ta_in
== data
->ta_in
)
94 /* Set Current-Limit-Mode 1:DC 0:USB */
96 gpio_set_value(pdata
->dcm
, ta_in
? 1 : 0);
98 /* Charger Enable / Disable (cen is negated) */
100 gpio_set_value(pdata
->cen
, ta_in
? 0 :
101 (data
->usb_in
? 0 : 1));
103 dev_dbg(data
->dev
, "TA(DC-IN) Charger %s.\n", ta_in
?
104 "Connected" : "Disconnected");
106 old_type
= data
->psy
.type
;
109 data
->psy
.type
= POWER_SUPPLY_TYPE_MAINS
;
110 else if (data
->usb_in
)
111 data
->psy
.type
= POWER_SUPPLY_TYPE_USB
;
113 data
->psy
.type
= POWER_SUPPLY_TYPE_BATTERY
;
115 if (old_type
!= data
->psy
.type
)
116 power_supply_changed(&data
->psy
);
121 static irqreturn_t
max8903_usbin(int irq
, void *_data
)
123 struct max8903_data
*data
= _data
;
124 struct max8903_pdata
*pdata
= data
->pdata
;
126 enum power_supply_type old_type
;
128 usb_in
= gpio_get_value(pdata
->uok
) ? false : true;
130 if (usb_in
== data
->usb_in
)
133 data
->usb_in
= usb_in
;
135 /* Do not touch Current-Limit-Mode */
137 /* Charger Enable / Disable (cen is negated) */
139 gpio_set_value(pdata
->cen
, usb_in
? 0 :
140 (data
->ta_in
? 0 : 1));
142 dev_dbg(data
->dev
, "USB Charger %s.\n", usb_in
?
143 "Connected" : "Disconnected");
145 old_type
= data
->psy
.type
;
148 data
->psy
.type
= POWER_SUPPLY_TYPE_MAINS
;
149 else if (data
->usb_in
)
150 data
->psy
.type
= POWER_SUPPLY_TYPE_USB
;
152 data
->psy
.type
= POWER_SUPPLY_TYPE_BATTERY
;
154 if (old_type
!= data
->psy
.type
)
155 power_supply_changed(&data
->psy
);
160 static irqreturn_t
max8903_fault(int irq
, void *_data
)
162 struct max8903_data
*data
= _data
;
163 struct max8903_pdata
*pdata
= data
->pdata
;
166 fault
= gpio_get_value(pdata
->flt
) ? false : true;
168 if (fault
== data
->fault
)
174 dev_err(data
->dev
, "Charger suffers a fault and stops.\n");
176 dev_err(data
->dev
, "Charger recovered from a fault.\n");
181 static __devinit
int max8903_probe(struct platform_device
*pdev
)
183 struct max8903_data
*data
;
184 struct device
*dev
= &pdev
->dev
;
185 struct max8903_pdata
*pdata
= pdev
->dev
.platform_data
;
191 data
= kzalloc(sizeof(struct max8903_data
), GFP_KERNEL
);
193 dev_err(dev
, "Cannot allocate memory.\n");
198 platform_set_drvdata(pdev
, data
);
200 if (pdata
->dc_valid
== false && pdata
->usb_valid
== false) {
201 dev_err(dev
, "No valid power sources.\n");
206 if (pdata
->dc_valid
) {
207 if (pdata
->dok
&& gpio_is_valid(pdata
->dok
) &&
208 pdata
->dcm
&& gpio_is_valid(pdata
->dcm
)) {
209 gpio
= pdata
->dok
; /* PULL_UPed Interrupt */
210 ta_in
= gpio_get_value(gpio
) ? 0 : 1;
212 gpio
= pdata
->dcm
; /* Output */
213 gpio_set_value(gpio
, ta_in
);
215 dev_err(dev
, "When DC is wired, DOK and DCM should"
216 " be wired as well.\n");
222 if (gpio_is_valid(pdata
->dcm
))
223 gpio_set_value(pdata
->dcm
, 0);
225 dev_err(dev
, "Invalid pin: dcm.\n");
232 if (pdata
->usb_valid
) {
233 if (pdata
->uok
&& gpio_is_valid(pdata
->uok
)) {
235 usb_in
= gpio_get_value(gpio
) ? 0 : 1;
237 dev_err(dev
, "When USB is wired, UOK should be wired."
245 if (gpio_is_valid(pdata
->cen
)) {
246 gpio_set_value(pdata
->cen
, (ta_in
|| usb_in
) ? 0 : 1);
248 dev_err(dev
, "Invalid pin: cen.\n");
255 if (!gpio_is_valid(pdata
->chg
)) {
256 dev_err(dev
, "Invalid pin: chg.\n");
263 if (!gpio_is_valid(pdata
->flt
)) {
264 dev_err(dev
, "Invalid pin: flt.\n");
271 if (!gpio_is_valid(pdata
->usus
)) {
272 dev_err(dev
, "Invalid pin: usus.\n");
280 data
->usb_in
= usb_in
;
282 data
->psy
.name
= "max8903_charger";
283 data
->psy
.type
= (ta_in
) ? POWER_SUPPLY_TYPE_MAINS
:
284 ((usb_in
) ? POWER_SUPPLY_TYPE_USB
:
285 POWER_SUPPLY_TYPE_BATTERY
);
286 data
->psy
.get_property
= max8903_get_property
;
287 data
->psy
.properties
= max8903_charger_props
;
288 data
->psy
.num_properties
= ARRAY_SIZE(max8903_charger_props
);
290 ret
= power_supply_register(dev
, &data
->psy
);
292 dev_err(dev
, "failed: power supply register.\n");
296 if (pdata
->dc_valid
) {
297 ret
= request_threaded_irq(gpio_to_irq(pdata
->dok
),
299 IRQF_TRIGGER_FALLING
| IRQF_TRIGGER_RISING
,
300 "MAX8903 DC IN", data
);
302 dev_err(dev
, "Cannot request irq %d for DC (%d)\n",
303 gpio_to_irq(pdata
->dok
), ret
);
308 if (pdata
->usb_valid
) {
309 ret
= request_threaded_irq(gpio_to_irq(pdata
->uok
),
311 IRQF_TRIGGER_FALLING
| IRQF_TRIGGER_RISING
,
312 "MAX8903 USB IN", data
);
314 dev_err(dev
, "Cannot request irq %d for USB (%d)\n",
315 gpio_to_irq(pdata
->uok
), ret
);
321 ret
= request_threaded_irq(gpio_to_irq(pdata
->flt
),
323 IRQF_TRIGGER_FALLING
| IRQF_TRIGGER_RISING
,
324 "MAX8903 Fault", data
);
326 dev_err(dev
, "Cannot request irq %d for Fault (%d)\n",
327 gpio_to_irq(pdata
->flt
), ret
);
335 if (pdata
->usb_valid
)
336 free_irq(gpio_to_irq(pdata
->uok
), data
);
339 free_irq(gpio_to_irq(pdata
->dok
), data
);
341 power_supply_unregister(&data
->psy
);
347 static __devexit
int max8903_remove(struct platform_device
*pdev
)
349 struct max8903_data
*data
= platform_get_drvdata(pdev
);
352 struct max8903_pdata
*pdata
= data
->pdata
;
355 free_irq(gpio_to_irq(pdata
->flt
), data
);
356 if (pdata
->usb_valid
)
357 free_irq(gpio_to_irq(pdata
->uok
), data
);
359 free_irq(gpio_to_irq(pdata
->dok
), data
);
360 power_supply_unregister(&data
->psy
);
367 static struct platform_driver max8903_driver
= {
368 .probe
= max8903_probe
,
369 .remove
= __devexit_p(max8903_remove
),
371 .name
= "max8903-charger",
372 .owner
= THIS_MODULE
,
376 static int __init
max8903_init(void)
378 return platform_driver_register(&max8903_driver
);
380 module_init(max8903_init
);
382 static void __exit
max8903_exit(void)
384 platform_driver_unregister(&max8903_driver
);
386 module_exit(max8903_exit
);
388 MODULE_LICENSE("GPL");
389 MODULE_DESCRIPTION("MAX8903 Charger Driver");
390 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
391 MODULE_ALIAS("max8903-charger");