Lines Matching +full:gpio +full:- +full:charger

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
16 #include <linux/gpio/consumer.h>
18 #include <linux/power/gpio-charger.h>
31 struct power_supply *charger; member
44 struct power_supply *charger = devid; in gpio_charger_irq() local
46 power_supply_changed(charger); in gpio_charger_irq()
59 int ndescs = gpio_charger->current_limit_gpios->ndescs; in set_charge_current_limit()
60 struct gpio_desc **gpios = gpio_charger->current_limit_gpios->desc; in set_charge_current_limit()
63 if (!gpio_charger->current_limit_map_size) in set_charge_current_limit()
64 return -EINVAL; in set_charge_current_limit()
66 for (i = 0; i < gpio_charger->current_limit_map_size; i++) { in set_charge_current_limit()
67 if (gpio_charger->current_limit_map[i].limit_ua <= val) in set_charge_current_limit()
70 mapping = gpio_charger->current_limit_map[i]; in set_charge_current_limit()
74 gpiod_set_value_cansleep(gpios[ndescs-i-1], val); in set_charge_current_limit()
77 gpio_charger->charge_current_limit = mapping.limit_ua; in set_charge_current_limit()
79 dev_dbg(gpio_charger->dev, "set charge current limit to %d (requested: %d)\n", in set_charge_current_limit()
80 gpio_charger->charge_current_limit, val); in set_charge_current_limit()
92 val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); in gpio_charger_get_property()
95 if (gpiod_get_value_cansleep(gpio_charger->charge_status)) in gpio_charger_get_property()
96 val->intval = POWER_SUPPLY_STATUS_CHARGING; in gpio_charger_get_property()
98 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; in gpio_charger_get_property()
101 val->intval = gpio_charger->charge_current_limit; in gpio_charger_get_property()
104 return -EINVAL; in gpio_charger_get_property()
117 return set_charge_current_limit(gpio_charger, val->intval); in gpio_charger_set_property()
119 return -EINVAL; in gpio_charger_set_property()
142 if (!device_property_read_string(dev, "charger-type", &chargetype)) { in gpio_charger_get_type()
151 if (!strcmp("usb-sdp", chargetype)) in gpio_charger_get_type()
153 if (!strcmp("usb-dcp", chargetype)) in gpio_charger_get_type()
155 if (!strcmp("usb-cdp", chargetype)) in gpio_charger_get_type()
157 if (!strcmp("usb-aca", chargetype)) in gpio_charger_get_type()
160 dev_warn(dev, "unknown charger type %s\n", chargetype); in gpio_charger_get_type()
166 struct gpio_desc *gpio) in gpio_charger_get_irq() argument
168 int ret, irq = gpiod_to_irq(gpio); in gpio_charger_get_irq()
191 gpio_charger->current_limit_gpios = devm_gpiod_get_array_optional(dev, in init_charge_current_limit()
192 "charge-current-limit", GPIOD_OUT_LOW); in init_charge_current_limit()
193 if (IS_ERR(gpio_charger->current_limit_gpios)) { in init_charge_current_limit()
194 dev_err(dev, "error getting current-limit GPIOs\n"); in init_charge_current_limit()
195 return PTR_ERR(gpio_charger->current_limit_gpios); in init_charge_current_limit()
198 if (!gpio_charger->current_limit_gpios) in init_charge_current_limit()
201 len = device_property_read_u32_array(dev, "charge-current-limit-mapping", in init_charge_current_limit()
207 dev_err(dev, "invalid charge-current-limit-mapping length\n"); in init_charge_current_limit()
208 return -EINVAL; in init_charge_current_limit()
211 gpio_charger->current_limit_map = devm_kmalloc_array(dev, in init_charge_current_limit()
212 len / 2, sizeof(*gpio_charger->current_limit_map), GFP_KERNEL); in init_charge_current_limit()
213 if (!gpio_charger->current_limit_map) in init_charge_current_limit()
214 return -ENOMEM; in init_charge_current_limit()
216 gpio_charger->current_limit_map_size = len / 2; in init_charge_current_limit()
218 len = device_property_read_u32_array(dev, "charge-current-limit-mapping", in init_charge_current_limit()
219 (u32*) gpio_charger->current_limit_map, len); in init_charge_current_limit()
223 for (i=0; i < gpio_charger->current_limit_map_size; i++) { in init_charge_current_limit()
224 if (gpio_charger->current_limit_map[i].limit_ua > cur_limit) { in init_charge_current_limit()
225 dev_err(dev, "charge-current-limit-mapping not sorted by current in descending order\n"); in init_charge_current_limit()
226 return -EINVAL; in init_charge_current_limit()
229 cur_limit = gpio_charger->current_limit_map[i].limit_ua; in init_charge_current_limit()
233 len = gpio_charger->current_limit_map_size - 1; in init_charge_current_limit()
235 gpio_charger->current_limit_map[len].limit_ua); in init_charge_current_limit()
253 struct device *dev = &pdev->dev; in gpio_charger_probe()
254 const struct gpio_charger_platform_data *pdata = dev->platform_data; in gpio_charger_probe()
263 if (!pdata && !dev->of_node) { in gpio_charger_probe()
265 return -ENOENT; in gpio_charger_probe()
270 return -ENOMEM; in gpio_charger_probe()
271 gpio_charger->dev = dev; in gpio_charger_probe()
274 * This will fetch a GPIO descriptor from device tree, ACPI or in gpio_charger_probe()
277 gpio_charger->gpiod = devm_gpiod_get_optional(dev, NULL, GPIOD_IN); in gpio_charger_probe()
278 if (IS_ERR(gpio_charger->gpiod)) { in gpio_charger_probe()
280 return dev_err_probe(dev, PTR_ERR(gpio_charger->gpiod), in gpio_charger_probe()
281 "error getting GPIO descriptor\n"); in gpio_charger_probe()
284 if (gpio_charger->gpiod) { in gpio_charger_probe()
289 charge_status = devm_gpiod_get_optional(dev, "charge-status", GPIOD_IN); in gpio_charger_probe()
293 gpio_charger->charge_status = charge_status; in gpio_charger_probe()
301 if (gpio_charger->current_limit_map) { in gpio_charger_probe()
307 charger_desc = &gpio_charger->charger_desc; in gpio_charger_probe()
308 charger_desc->properties = gpio_charger_properties; in gpio_charger_probe()
309 charger_desc->num_properties = num_props; in gpio_charger_probe()
310 charger_desc->get_property = gpio_charger_get_property; in gpio_charger_probe()
311 charger_desc->set_property = gpio_charger_set_property; in gpio_charger_probe()
312 charger_desc->property_is_writeable = in gpio_charger_probe()
315 psy_cfg.of_node = dev->of_node; in gpio_charger_probe()
319 charger_desc->name = pdata->name; in gpio_charger_probe()
320 charger_desc->type = pdata->type; in gpio_charger_probe()
321 psy_cfg.supplied_to = pdata->supplied_to; in gpio_charger_probe()
322 psy_cfg.num_supplicants = pdata->num_supplicants; in gpio_charger_probe()
324 charger_desc->name = dev->of_node->name; in gpio_charger_probe()
325 charger_desc->type = gpio_charger_get_type(dev); in gpio_charger_probe()
328 if (!charger_desc->name) in gpio_charger_probe()
329 charger_desc->name = pdev->name; in gpio_charger_probe()
331 gpio_charger->charger = devm_power_supply_register(dev, charger_desc, in gpio_charger_probe()
333 if (IS_ERR(gpio_charger->charger)) { in gpio_charger_probe()
334 ret = PTR_ERR(gpio_charger->charger); in gpio_charger_probe()
339 gpio_charger->irq = gpio_charger_get_irq(dev, gpio_charger->charger, in gpio_charger_probe()
340 gpio_charger->gpiod); in gpio_charger_probe()
342 charge_status_irq = gpio_charger_get_irq(dev, gpio_charger->charger, in gpio_charger_probe()
343 gpio_charger->charge_status); in gpio_charger_probe()
344 gpio_charger->charge_status_irq = charge_status_irq; in gpio_charger_probe()
359 gpio_charger->wakeup_enabled = in gpio_charger_suspend()
360 !enable_irq_wake(gpio_charger->irq); in gpio_charger_suspend()
369 if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled) in gpio_charger_resume()
370 disable_irq_wake(gpio_charger->irq); in gpio_charger_resume()
371 power_supply_changed(gpio_charger->charger); in gpio_charger_resume()
381 { .compatible = "gpio-charger" },
389 .name = "gpio-charger",
397 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
398 MODULE_DESCRIPTION("Driver for chargers only communicating via GPIO(s)");
400 MODULE_ALIAS("platform:gpio-charger");