1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
4 * Driver for chargers which report their online status through a GPIO pin
7 #include <linux/device.h>
8 #include <linux/gpio.h> /* For legacy platform data */
9 #include <linux/init.h>
10 #include <linux/interrupt.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h>
15 #include <linux/slab.h>
17 #include <linux/gpio/consumer.h>
19 #include <linux/power/gpio-charger.h>
23 unsigned int charge_status_irq
;
26 struct power_supply
*charger
;
27 struct power_supply_desc charger_desc
;
28 struct gpio_desc
*gpiod
;
29 struct gpio_desc
*charge_status
;
32 static irqreturn_t
gpio_charger_irq(int irq
, void *devid
)
34 struct power_supply
*charger
= devid
;
36 power_supply_changed(charger
);
41 static inline struct gpio_charger
*psy_to_gpio_charger(struct power_supply
*psy
)
43 return power_supply_get_drvdata(psy
);
46 static int gpio_charger_get_property(struct power_supply
*psy
,
47 enum power_supply_property psp
, union power_supply_propval
*val
)
49 struct gpio_charger
*gpio_charger
= psy_to_gpio_charger(psy
);
52 case POWER_SUPPLY_PROP_ONLINE
:
53 val
->intval
= gpiod_get_value_cansleep(gpio_charger
->gpiod
);
55 case POWER_SUPPLY_PROP_STATUS
:
56 if (gpiod_get_value_cansleep(gpio_charger
->charge_status
))
57 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
59 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
68 static enum power_supply_type
gpio_charger_get_type(struct device
*dev
)
70 const char *chargetype
;
72 if (!device_property_read_string(dev
, "charger-type", &chargetype
)) {
73 if (!strcmp("unknown", chargetype
))
74 return POWER_SUPPLY_TYPE_UNKNOWN
;
75 if (!strcmp("battery", chargetype
))
76 return POWER_SUPPLY_TYPE_BATTERY
;
77 if (!strcmp("ups", chargetype
))
78 return POWER_SUPPLY_TYPE_UPS
;
79 if (!strcmp("mains", chargetype
))
80 return POWER_SUPPLY_TYPE_MAINS
;
81 if (!strcmp("usb-sdp", chargetype
))
82 return POWER_SUPPLY_TYPE_USB
;
83 if (!strcmp("usb-dcp", chargetype
))
84 return POWER_SUPPLY_TYPE_USB
;
85 if (!strcmp("usb-cdp", chargetype
))
86 return POWER_SUPPLY_TYPE_USB
;
87 if (!strcmp("usb-aca", chargetype
))
88 return POWER_SUPPLY_TYPE_USB
;
90 dev_warn(dev
, "unknown charger type %s\n", chargetype
);
92 return POWER_SUPPLY_TYPE_UNKNOWN
;
95 static int gpio_charger_get_irq(struct device
*dev
, void *dev_id
,
96 struct gpio_desc
*gpio
)
98 int ret
, irq
= gpiod_to_irq(gpio
);
101 ret
= devm_request_any_context_irq(dev
, irq
, gpio_charger_irq
,
102 IRQF_TRIGGER_RISING
|
103 IRQF_TRIGGER_FALLING
,
107 dev_warn(dev
, "Failed to request irq: %d\n", ret
);
115 static enum power_supply_property gpio_charger_properties
[] = {
116 POWER_SUPPLY_PROP_ONLINE
,
117 POWER_SUPPLY_PROP_STATUS
/* Must always be last in the array. */
120 static int gpio_charger_probe(struct platform_device
*pdev
)
122 struct device
*dev
= &pdev
->dev
;
123 const struct gpio_charger_platform_data
*pdata
= dev
->platform_data
;
124 struct power_supply_config psy_cfg
= {};
125 struct gpio_charger
*gpio_charger
;
126 struct power_supply_desc
*charger_desc
;
127 struct gpio_desc
*charge_status
;
128 int charge_status_irq
;
132 if (!pdata
&& !dev
->of_node
) {
133 dev_err(dev
, "No platform data\n");
137 gpio_charger
= devm_kzalloc(dev
, sizeof(*gpio_charger
), GFP_KERNEL
);
142 * This will fetch a GPIO descriptor from device tree, ACPI or
143 * boardfile descriptor tables. It's good to try this first.
145 gpio_charger
->gpiod
= devm_gpiod_get(dev
, NULL
, GPIOD_IN
);
148 * If this fails and we're not using device tree, try the
149 * legacy platform data method.
151 if (IS_ERR(gpio_charger
->gpiod
) && !dev
->of_node
) {
152 /* Non-DT: use legacy GPIO numbers */
153 if (!gpio_is_valid(pdata
->gpio
)) {
154 dev_err(dev
, "Invalid gpio pin in pdata\n");
158 if (pdata
->gpio_active_low
)
159 flags
|= GPIOF_ACTIVE_LOW
;
160 ret
= devm_gpio_request_one(dev
, pdata
->gpio
, flags
,
163 dev_err(dev
, "Failed to request gpio pin: %d\n", ret
);
166 /* Then convert this to gpiod for now */
167 gpio_charger
->gpiod
= gpio_to_desc(pdata
->gpio
);
168 } else if (IS_ERR(gpio_charger
->gpiod
)) {
169 /* Just try again if this happens */
170 if (PTR_ERR(gpio_charger
->gpiod
) == -EPROBE_DEFER
)
171 return -EPROBE_DEFER
;
172 dev_err(dev
, "error getting GPIO descriptor\n");
173 return PTR_ERR(gpio_charger
->gpiod
);
176 charge_status
= devm_gpiod_get_optional(dev
, "charge-status", GPIOD_IN
);
177 gpio_charger
->charge_status
= charge_status
;
178 if (IS_ERR(gpio_charger
->charge_status
))
179 return PTR_ERR(gpio_charger
->charge_status
);
181 charger_desc
= &gpio_charger
->charger_desc
;
182 charger_desc
->properties
= gpio_charger_properties
;
183 charger_desc
->num_properties
= ARRAY_SIZE(gpio_charger_properties
);
184 /* Remove POWER_SUPPLY_PROP_STATUS from the supported properties. */
185 if (!gpio_charger
->charge_status
)
186 charger_desc
->num_properties
-= 1;
187 charger_desc
->get_property
= gpio_charger_get_property
;
189 psy_cfg
.of_node
= dev
->of_node
;
190 psy_cfg
.drv_data
= gpio_charger
;
193 charger_desc
->name
= pdata
->name
;
194 charger_desc
->type
= pdata
->type
;
195 psy_cfg
.supplied_to
= pdata
->supplied_to
;
196 psy_cfg
.num_supplicants
= pdata
->num_supplicants
;
198 charger_desc
->name
= dev
->of_node
->name
;
199 charger_desc
->type
= gpio_charger_get_type(dev
);
202 if (!charger_desc
->name
)
203 charger_desc
->name
= pdev
->name
;
205 gpio_charger
->charger
= devm_power_supply_register(dev
, charger_desc
,
207 if (IS_ERR(gpio_charger
->charger
)) {
208 ret
= PTR_ERR(gpio_charger
->charger
);
209 dev_err(dev
, "Failed to register power supply: %d\n", ret
);
213 gpio_charger
->irq
= gpio_charger_get_irq(dev
, gpio_charger
->charger
,
214 gpio_charger
->gpiod
);
216 charge_status_irq
= gpio_charger_get_irq(dev
, gpio_charger
->charger
,
217 gpio_charger
->charge_status
);
218 gpio_charger
->charge_status_irq
= charge_status_irq
;
220 platform_set_drvdata(pdev
, gpio_charger
);
222 device_init_wakeup(dev
, 1);
227 #ifdef CONFIG_PM_SLEEP
228 static int gpio_charger_suspend(struct device
*dev
)
230 struct gpio_charger
*gpio_charger
= dev_get_drvdata(dev
);
232 if (device_may_wakeup(dev
))
233 gpio_charger
->wakeup_enabled
=
234 !enable_irq_wake(gpio_charger
->irq
);
239 static int gpio_charger_resume(struct device
*dev
)
241 struct gpio_charger
*gpio_charger
= dev_get_drvdata(dev
);
243 if (device_may_wakeup(dev
) && gpio_charger
->wakeup_enabled
)
244 disable_irq_wake(gpio_charger
->irq
);
245 power_supply_changed(gpio_charger
->charger
);
251 static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops
,
252 gpio_charger_suspend
, gpio_charger_resume
);
254 static const struct of_device_id gpio_charger_match
[] = {
255 { .compatible
= "gpio-charger" },
258 MODULE_DEVICE_TABLE(of
, gpio_charger_match
);
260 static struct platform_driver gpio_charger_driver
= {
261 .probe
= gpio_charger_probe
,
263 .name
= "gpio-charger",
264 .pm
= &gpio_charger_pm_ops
,
265 .of_match_table
= gpio_charger_match
,
269 module_platform_driver(gpio_charger_driver
);
271 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
272 MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
273 MODULE_LICENSE("GPL");
274 MODULE_ALIAS("platform:gpio-charger");