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/module.h>
27 #include <linux/of_device.h>
28 #include <linux/of_gpio.h>
29 #include <linux/slab.h>
30 #include <linux/power_supply.h>
31 #include <linux/platform_device.h>
32 #include <linux/power/max8903_charger.h>
35 struct max8903_pdata
*pdata
;
37 struct power_supply
*psy
;
38 struct power_supply_desc psy_desc
;
44 static enum power_supply_property max8903_charger_props
[] = {
45 POWER_SUPPLY_PROP_STATUS
, /* Charger status output */
46 POWER_SUPPLY_PROP_ONLINE
, /* External power source */
47 POWER_SUPPLY_PROP_HEALTH
, /* Fault or OK */
50 static int max8903_get_property(struct power_supply
*psy
,
51 enum power_supply_property psp
,
52 union power_supply_propval
*val
)
54 struct max8903_data
*data
= power_supply_get_drvdata(psy
);
57 case POWER_SUPPLY_PROP_STATUS
:
58 val
->intval
= POWER_SUPPLY_STATUS_UNKNOWN
;
59 if (gpio_is_valid(data
->pdata
->chg
)) {
60 if (gpio_get_value(data
->pdata
->chg
) == 0)
61 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
62 else if (data
->usb_in
|| data
->ta_in
)
63 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
65 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
68 case POWER_SUPPLY_PROP_ONLINE
:
70 if (data
->usb_in
|| data
->ta_in
)
73 case POWER_SUPPLY_PROP_HEALTH
:
74 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
76 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
85 static irqreturn_t
max8903_dcin(int irq
, void *_data
)
87 struct max8903_data
*data
= _data
;
88 struct max8903_pdata
*pdata
= data
->pdata
;
90 enum power_supply_type old_type
;
92 ta_in
= gpio_get_value(pdata
->dok
) ? false : true;
94 if (ta_in
== data
->ta_in
)
99 /* Set Current-Limit-Mode 1:DC 0:USB */
100 if (gpio_is_valid(pdata
->dcm
))
101 gpio_set_value(pdata
->dcm
, ta_in
? 1 : 0);
103 /* Charger Enable / Disable (cen is negated) */
104 if (gpio_is_valid(pdata
->cen
))
105 gpio_set_value(pdata
->cen
, ta_in
? 0 :
106 (data
->usb_in
? 0 : 1));
108 dev_dbg(data
->dev
, "TA(DC-IN) Charger %s.\n", ta_in
?
109 "Connected" : "Disconnected");
111 old_type
= data
->psy_desc
.type
;
114 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_MAINS
;
115 else if (data
->usb_in
)
116 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_USB
;
118 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_BATTERY
;
120 if (old_type
!= data
->psy_desc
.type
)
121 power_supply_changed(data
->psy
);
126 static irqreturn_t
max8903_usbin(int irq
, void *_data
)
128 struct max8903_data
*data
= _data
;
129 struct max8903_pdata
*pdata
= data
->pdata
;
131 enum power_supply_type old_type
;
133 usb_in
= gpio_get_value(pdata
->uok
) ? false : true;
135 if (usb_in
== data
->usb_in
)
138 data
->usb_in
= usb_in
;
140 /* Do not touch Current-Limit-Mode */
142 /* Charger Enable / Disable (cen is negated) */
143 if (gpio_is_valid(pdata
->cen
))
144 gpio_set_value(pdata
->cen
, usb_in
? 0 :
145 (data
->ta_in
? 0 : 1));
147 dev_dbg(data
->dev
, "USB Charger %s.\n", usb_in
?
148 "Connected" : "Disconnected");
150 old_type
= data
->psy_desc
.type
;
153 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_MAINS
;
154 else if (data
->usb_in
)
155 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_USB
;
157 data
->psy_desc
.type
= POWER_SUPPLY_TYPE_BATTERY
;
159 if (old_type
!= data
->psy_desc
.type
)
160 power_supply_changed(data
->psy
);
165 static irqreturn_t
max8903_fault(int irq
, void *_data
)
167 struct max8903_data
*data
= _data
;
168 struct max8903_pdata
*pdata
= data
->pdata
;
171 fault
= gpio_get_value(pdata
->flt
) ? false : true;
173 if (fault
== data
->fault
)
179 dev_err(data
->dev
, "Charger suffers a fault and stops.\n");
181 dev_err(data
->dev
, "Charger recovered from a fault.\n");
186 static struct max8903_pdata
*max8903_parse_dt_data(struct device
*dev
)
188 struct device_node
*np
= dev
->of_node
;
189 struct max8903_pdata
*pdata
= NULL
;
194 pdata
= devm_kzalloc(dev
, sizeof(*pdata
), GFP_KERNEL
);
198 pdata
->dc_valid
= false;
199 pdata
->usb_valid
= false;
201 pdata
->cen
= of_get_named_gpio(np
, "cen-gpios", 0);
202 if (!gpio_is_valid(pdata
->cen
))
203 pdata
->cen
= -EINVAL
;
205 pdata
->chg
= of_get_named_gpio(np
, "chg-gpios", 0);
206 if (!gpio_is_valid(pdata
->chg
))
207 pdata
->chg
= -EINVAL
;
209 pdata
->flt
= of_get_named_gpio(np
, "flt-gpios", 0);
210 if (!gpio_is_valid(pdata
->flt
))
211 pdata
->flt
= -EINVAL
;
213 pdata
->usus
= of_get_named_gpio(np
, "usus-gpios", 0);
214 if (!gpio_is_valid(pdata
->usus
))
215 pdata
->usus
= -EINVAL
;
217 pdata
->dcm
= of_get_named_gpio(np
, "dcm-gpios", 0);
218 if (!gpio_is_valid(pdata
->dcm
))
219 pdata
->dcm
= -EINVAL
;
221 pdata
->dok
= of_get_named_gpio(np
, "dok-gpios", 0);
222 if (!gpio_is_valid(pdata
->dok
))
223 pdata
->dok
= -EINVAL
;
225 pdata
->dc_valid
= true;
227 pdata
->uok
= of_get_named_gpio(np
, "uok-gpios", 0);
228 if (!gpio_is_valid(pdata
->uok
))
229 pdata
->uok
= -EINVAL
;
231 pdata
->usb_valid
= true;
236 static int max8903_setup_gpios(struct platform_device
*pdev
)
238 struct max8903_data
*data
= platform_get_drvdata(pdev
);
239 struct device
*dev
= &pdev
->dev
;
240 struct max8903_pdata
*pdata
= pdev
->dev
.platform_data
;
246 if (pdata
->dc_valid
) {
247 if (gpio_is_valid(pdata
->dok
)) {
248 ret
= devm_gpio_request(dev
, pdata
->dok
,
249 data
->psy_desc
.name
);
252 "Failed GPIO request for dok: %d err %d\n",
257 gpio
= pdata
->dok
; /* PULL_UPed Interrupt */
258 ta_in
= gpio_get_value(gpio
) ? 0 : 1;
260 dev_err(dev
, "When DC is wired, DOK should be wired as well.\n");
265 if (gpio_is_valid(pdata
->dcm
)) {
266 ret
= devm_gpio_request(dev
, pdata
->dcm
, data
->psy_desc
.name
);
269 "Failed GPIO request for dcm: %d err %d\n",
274 gpio
= pdata
->dcm
; /* Output */
275 gpio_set_value(gpio
, ta_in
);
278 if (pdata
->usb_valid
) {
279 if (gpio_is_valid(pdata
->uok
)) {
280 ret
= devm_gpio_request(dev
, pdata
->uok
,
281 data
->psy_desc
.name
);
284 "Failed GPIO request for uok: %d err %d\n",
290 usb_in
= gpio_get_value(gpio
) ? 0 : 1;
292 dev_err(dev
, "When USB is wired, UOK should be wired."
298 if (gpio_is_valid(pdata
->cen
)) {
299 ret
= devm_gpio_request(dev
, pdata
->cen
, data
->psy_desc
.name
);
302 "Failed GPIO request for cen: %d err %d\n",
307 gpio_set_value(pdata
->cen
, (ta_in
|| usb_in
) ? 0 : 1);
310 if (gpio_is_valid(pdata
->chg
)) {
311 ret
= devm_gpio_request(dev
, pdata
->chg
, data
->psy_desc
.name
);
314 "Failed GPIO request for chg: %d err %d\n",
320 if (gpio_is_valid(pdata
->flt
)) {
321 ret
= devm_gpio_request(dev
, pdata
->flt
, data
->psy_desc
.name
);
324 "Failed GPIO request for flt: %d err %d\n",
330 if (gpio_is_valid(pdata
->usus
)) {
331 ret
= devm_gpio_request(dev
, pdata
->usus
, data
->psy_desc
.name
);
334 "Failed GPIO request for usus: %d err %d\n",
342 data
->usb_in
= usb_in
;
347 static int max8903_probe(struct platform_device
*pdev
)
349 struct max8903_data
*data
;
350 struct device
*dev
= &pdev
->dev
;
351 struct max8903_pdata
*pdata
= pdev
->dev
.platform_data
;
352 struct power_supply_config psy_cfg
= {};
355 data
= devm_kzalloc(dev
, sizeof(struct max8903_data
), GFP_KERNEL
);
359 if (IS_ENABLED(CONFIG_OF
) && !pdata
&& dev
->of_node
)
360 pdata
= max8903_parse_dt_data(dev
);
363 dev_err(dev
, "No platform data.\n");
367 pdev
->dev
.platform_data
= pdata
;
370 platform_set_drvdata(pdev
, data
);
372 if (pdata
->dc_valid
== false && pdata
->usb_valid
== false) {
373 dev_err(dev
, "No valid power sources.\n");
377 ret
= max8903_setup_gpios(pdev
);
381 data
->psy_desc
.name
= "max8903_charger";
382 data
->psy_desc
.type
= (data
->ta_in
) ? POWER_SUPPLY_TYPE_MAINS
:
383 ((data
->usb_in
) ? POWER_SUPPLY_TYPE_USB
:
384 POWER_SUPPLY_TYPE_BATTERY
);
385 data
->psy_desc
.get_property
= max8903_get_property
;
386 data
->psy_desc
.properties
= max8903_charger_props
;
387 data
->psy_desc
.num_properties
= ARRAY_SIZE(max8903_charger_props
);
389 psy_cfg
.of_node
= dev
->of_node
;
390 psy_cfg
.drv_data
= data
;
392 data
->psy
= devm_power_supply_register(dev
, &data
->psy_desc
, &psy_cfg
);
393 if (IS_ERR(data
->psy
)) {
394 dev_err(dev
, "failed: power supply register.\n");
395 return PTR_ERR(data
->psy
);
398 if (pdata
->dc_valid
) {
399 ret
= devm_request_threaded_irq(dev
, gpio_to_irq(pdata
->dok
),
401 IRQF_TRIGGER_FALLING
|
402 IRQF_TRIGGER_RISING
| IRQF_ONESHOT
,
403 "MAX8903 DC IN", data
);
405 dev_err(dev
, "Cannot request irq %d for DC (%d)\n",
406 gpio_to_irq(pdata
->dok
), ret
);
411 if (pdata
->usb_valid
) {
412 ret
= devm_request_threaded_irq(dev
, gpio_to_irq(pdata
->uok
),
414 IRQF_TRIGGER_FALLING
|
415 IRQF_TRIGGER_RISING
| IRQF_ONESHOT
,
416 "MAX8903 USB IN", data
);
418 dev_err(dev
, "Cannot request irq %d for USB (%d)\n",
419 gpio_to_irq(pdata
->uok
), ret
);
424 if (gpio_is_valid(pdata
->flt
)) {
425 ret
= devm_request_threaded_irq(dev
, gpio_to_irq(pdata
->flt
),
427 IRQF_TRIGGER_FALLING
|
428 IRQF_TRIGGER_RISING
| IRQF_ONESHOT
,
429 "MAX8903 Fault", data
);
431 dev_err(dev
, "Cannot request irq %d for Fault (%d)\n",
432 gpio_to_irq(pdata
->flt
), ret
);
440 static const struct of_device_id max8903_match_ids
[] = {
441 { .compatible
= "maxim,max8903", },
444 MODULE_DEVICE_TABLE(of
, max8903_match_ids
);
446 static struct platform_driver max8903_driver
= {
447 .probe
= max8903_probe
,
449 .name
= "max8903-charger",
450 .of_match_table
= max8903_match_ids
454 module_platform_driver(max8903_driver
);
456 MODULE_LICENSE("GPL");
457 MODULE_DESCRIPTION("MAX8903 Charger Driver");
458 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
459 MODULE_ALIAS("platform:max8903-charger");