root/drivers/power/supply/gpio-charger.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gpio_charger_irq
  2. psy_to_gpio_charger
  3. gpio_charger_get_property
  4. gpio_charger_get_type
  5. gpio_charger_get_irq
  6. gpio_charger_probe
  7. gpio_charger_suspend
  8. gpio_charger_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
   4  *  Driver for chargers which report their online status through a GPIO pin
   5  */
   6 
   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>
  16 #include <linux/of.h>
  17 #include <linux/gpio/consumer.h>
  18 
  19 #include <linux/power/gpio-charger.h>
  20 
  21 struct gpio_charger {
  22         unsigned int irq;
  23         unsigned int charge_status_irq;
  24         bool wakeup_enabled;
  25 
  26         struct power_supply *charger;
  27         struct power_supply_desc charger_desc;
  28         struct gpio_desc *gpiod;
  29         struct gpio_desc *charge_status;
  30 };
  31 
  32 static irqreturn_t gpio_charger_irq(int irq, void *devid)
  33 {
  34         struct power_supply *charger = devid;
  35 
  36         power_supply_changed(charger);
  37 
  38         return IRQ_HANDLED;
  39 }
  40 
  41 static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
  42 {
  43         return power_supply_get_drvdata(psy);
  44 }
  45 
  46 static int gpio_charger_get_property(struct power_supply *psy,
  47                 enum power_supply_property psp, union power_supply_propval *val)
  48 {
  49         struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
  50 
  51         switch (psp) {
  52         case POWER_SUPPLY_PROP_ONLINE:
  53                 val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod);
  54                 break;
  55         case POWER_SUPPLY_PROP_STATUS:
  56                 if (gpiod_get_value_cansleep(gpio_charger->charge_status))
  57                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
  58                 else
  59                         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  60                 break;
  61         default:
  62                 return -EINVAL;
  63         }
  64 
  65         return 0;
  66 }
  67 
  68 static enum power_supply_type gpio_charger_get_type(struct device *dev)
  69 {
  70         const char *chargetype;
  71 
  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;
  89         }
  90         dev_warn(dev, "unknown charger type %s\n", chargetype);
  91 
  92         return POWER_SUPPLY_TYPE_UNKNOWN;
  93 }
  94 
  95 static int gpio_charger_get_irq(struct device *dev, void *dev_id,
  96                                 struct gpio_desc *gpio)
  97 {
  98         int ret, irq = gpiod_to_irq(gpio);
  99 
 100         if (irq > 0) {
 101                 ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq,
 102                                                    IRQF_TRIGGER_RISING |
 103                                                    IRQF_TRIGGER_FALLING,
 104                                                    dev_name(dev),
 105                                                    dev_id);
 106                 if (ret < 0) {
 107                         dev_warn(dev, "Failed to request irq: %d\n", ret);
 108                         irq = 0;
 109                 }
 110         }
 111 
 112         return irq;
 113 }
 114 
 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. */
 118 };
 119 
 120 static int gpio_charger_probe(struct platform_device *pdev)
 121 {
 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;
 129         unsigned long flags;
 130         int ret;
 131 
 132         if (!pdata && !dev->of_node) {
 133                 dev_err(dev, "No platform data\n");
 134                 return -ENOENT;
 135         }
 136 
 137         gpio_charger = devm_kzalloc(dev, sizeof(*gpio_charger), GFP_KERNEL);
 138         if (!gpio_charger)
 139                 return -ENOMEM;
 140 
 141         /*
 142          * This will fetch a GPIO descriptor from device tree, ACPI or
 143          * boardfile descriptor tables. It's good to try this first.
 144          */
 145         gpio_charger->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN);
 146 
 147         /*
 148          * If this fails and we're not using device tree, try the
 149          * legacy platform data method.
 150          */
 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");
 155                         return -EINVAL;
 156                 }
 157                 flags = GPIOF_IN;
 158                 if (pdata->gpio_active_low)
 159                         flags |= GPIOF_ACTIVE_LOW;
 160                 ret = devm_gpio_request_one(dev, pdata->gpio, flags,
 161                                             dev_name(dev));
 162                 if (ret) {
 163                         dev_err(dev, "Failed to request gpio pin: %d\n", ret);
 164                         return ret;
 165                 }
 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);
 174         }
 175 
 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);
 180 
 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;
 188 
 189         psy_cfg.of_node = dev->of_node;
 190         psy_cfg.drv_data = gpio_charger;
 191 
 192         if (pdata) {
 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;
 197         } else {
 198                 charger_desc->name = dev->of_node->name;
 199                 charger_desc->type = gpio_charger_get_type(dev);
 200         }
 201 
 202         if (!charger_desc->name)
 203                 charger_desc->name = pdev->name;
 204 
 205         gpio_charger->charger = devm_power_supply_register(dev, charger_desc,
 206                                                            &psy_cfg);
 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);
 210                 return ret;
 211         }
 212 
 213         gpio_charger->irq = gpio_charger_get_irq(dev, gpio_charger->charger,
 214                                                  gpio_charger->gpiod);
 215 
 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;
 219 
 220         platform_set_drvdata(pdev, gpio_charger);
 221 
 222         device_init_wakeup(dev, 1);
 223 
 224         return 0;
 225 }
 226 
 227 #ifdef CONFIG_PM_SLEEP
 228 static int gpio_charger_suspend(struct device *dev)
 229 {
 230         struct gpio_charger *gpio_charger = dev_get_drvdata(dev);
 231 
 232         if (device_may_wakeup(dev))
 233                 gpio_charger->wakeup_enabled =
 234                         !enable_irq_wake(gpio_charger->irq);
 235 
 236         return 0;
 237 }
 238 
 239 static int gpio_charger_resume(struct device *dev)
 240 {
 241         struct gpio_charger *gpio_charger = dev_get_drvdata(dev);
 242 
 243         if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled)
 244                 disable_irq_wake(gpio_charger->irq);
 245         power_supply_changed(gpio_charger->charger);
 246 
 247         return 0;
 248 }
 249 #endif
 250 
 251 static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops,
 252                 gpio_charger_suspend, gpio_charger_resume);
 253 
 254 static const struct of_device_id gpio_charger_match[] = {
 255         { .compatible = "gpio-charger" },
 256         { }
 257 };
 258 MODULE_DEVICE_TABLE(of, gpio_charger_match);
 259 
 260 static struct platform_driver gpio_charger_driver = {
 261         .probe = gpio_charger_probe,
 262         .driver = {
 263                 .name = "gpio-charger",
 264                 .pm = &gpio_charger_pm_ops,
 265                 .of_match_table = gpio_charger_match,
 266         },
 267 };
 268 
 269 module_platform_driver(gpio_charger_driver);
 270 
 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");

/* [<][>][^][v][top][bottom][index][help] */