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

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

DEFINITIONS

This source file includes following definitions.
  1. lt3651_charger_irq
  2. psy_to_lt3651_charger
  3. lt3651_charger_get_property
  4. lt3651_charger_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  *  Driver for Analog Devices (Linear Technology) LT3651 charger IC.
   4  *  Copyright (C) 2017, Topic Embedded Products
   5  */
   6 
   7 #include <linux/device.h>
   8 #include <linux/gpio/consumer.h>
   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 
  18 struct lt3651_charger {
  19         struct power_supply *charger;
  20         struct power_supply_desc charger_desc;
  21         struct gpio_desc *acpr_gpio;
  22         struct gpio_desc *fault_gpio;
  23         struct gpio_desc *chrg_gpio;
  24 };
  25 
  26 static irqreturn_t lt3651_charger_irq(int irq, void *devid)
  27 {
  28         struct power_supply *charger = devid;
  29 
  30         power_supply_changed(charger);
  31 
  32         return IRQ_HANDLED;
  33 }
  34 
  35 static inline struct lt3651_charger *psy_to_lt3651_charger(
  36         struct power_supply *psy)
  37 {
  38         return power_supply_get_drvdata(psy);
  39 }
  40 
  41 static int lt3651_charger_get_property(struct power_supply *psy,
  42                 enum power_supply_property psp, union power_supply_propval *val)
  43 {
  44         struct lt3651_charger *lt3651_charger = psy_to_lt3651_charger(psy);
  45 
  46         switch (psp) {
  47         case POWER_SUPPLY_PROP_STATUS:
  48                 if (!lt3651_charger->chrg_gpio) {
  49                         val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
  50                         break;
  51                 }
  52                 if (gpiod_get_value(lt3651_charger->chrg_gpio))
  53                         val->intval = POWER_SUPPLY_STATUS_CHARGING;
  54                 else
  55                         val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
  56                 break;
  57         case POWER_SUPPLY_PROP_ONLINE:
  58                 val->intval = gpiod_get_value(lt3651_charger->acpr_gpio);
  59                 break;
  60         case POWER_SUPPLY_PROP_HEALTH:
  61                 if (!lt3651_charger->fault_gpio) {
  62                         val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
  63                         break;
  64                 }
  65                 if (!gpiod_get_value(lt3651_charger->fault_gpio)) {
  66                         val->intval = POWER_SUPPLY_HEALTH_GOOD;
  67                         break;
  68                 }
  69                 /*
  70                  * If the fault pin is active, the chrg pin explains the type
  71                  * of failure.
  72                  */
  73                 if (!lt3651_charger->chrg_gpio) {
  74                         val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
  75                         break;
  76                 }
  77                 val->intval = gpiod_get_value(lt3651_charger->chrg_gpio) ?
  78                                 POWER_SUPPLY_HEALTH_OVERHEAT :
  79                                 POWER_SUPPLY_HEALTH_DEAD;
  80                 break;
  81         default:
  82                 return -EINVAL;
  83         }
  84 
  85         return 0;
  86 }
  87 
  88 static enum power_supply_property lt3651_charger_properties[] = {
  89         POWER_SUPPLY_PROP_STATUS,
  90         POWER_SUPPLY_PROP_ONLINE,
  91         POWER_SUPPLY_PROP_HEALTH,
  92 };
  93 
  94 static int lt3651_charger_probe(struct platform_device *pdev)
  95 {
  96         struct power_supply_config psy_cfg = {};
  97         struct lt3651_charger *lt3651_charger;
  98         struct power_supply_desc *charger_desc;
  99         int ret;
 100 
 101         lt3651_charger = devm_kzalloc(&pdev->dev, sizeof(*lt3651_charger),
 102                                         GFP_KERNEL);
 103         if (!lt3651_charger)
 104                 return -ENOMEM;
 105 
 106         lt3651_charger->acpr_gpio = devm_gpiod_get(&pdev->dev,
 107                                         "lltc,acpr", GPIOD_IN);
 108         if (IS_ERR(lt3651_charger->acpr_gpio)) {
 109                 ret = PTR_ERR(lt3651_charger->acpr_gpio);
 110                 dev_err(&pdev->dev, "Failed to acquire acpr GPIO: %d\n", ret);
 111                 return ret;
 112         }
 113         lt3651_charger->fault_gpio = devm_gpiod_get_optional(&pdev->dev,
 114                                         "lltc,fault", GPIOD_IN);
 115         if (IS_ERR(lt3651_charger->fault_gpio)) {
 116                 ret = PTR_ERR(lt3651_charger->fault_gpio);
 117                 dev_err(&pdev->dev, "Failed to acquire fault GPIO: %d\n", ret);
 118                 return ret;
 119         }
 120         lt3651_charger->chrg_gpio = devm_gpiod_get_optional(&pdev->dev,
 121                                         "lltc,chrg", GPIOD_IN);
 122         if (IS_ERR(lt3651_charger->chrg_gpio)) {
 123                 ret = PTR_ERR(lt3651_charger->chrg_gpio);
 124                 dev_err(&pdev->dev, "Failed to acquire chrg GPIO: %d\n", ret);
 125                 return ret;
 126         }
 127 
 128         charger_desc = &lt3651_charger->charger_desc;
 129         charger_desc->name = pdev->dev.of_node->name;
 130         charger_desc->type = POWER_SUPPLY_TYPE_MAINS;
 131         charger_desc->properties = lt3651_charger_properties;
 132         charger_desc->num_properties = ARRAY_SIZE(lt3651_charger_properties);
 133         charger_desc->get_property = lt3651_charger_get_property;
 134         psy_cfg.of_node = pdev->dev.of_node;
 135         psy_cfg.drv_data = lt3651_charger;
 136 
 137         lt3651_charger->charger = devm_power_supply_register(&pdev->dev,
 138                                                       charger_desc, &psy_cfg);
 139         if (IS_ERR(lt3651_charger->charger)) {
 140                 ret = PTR_ERR(lt3651_charger->charger);
 141                 dev_err(&pdev->dev, "Failed to register power supply: %d\n",
 142                         ret);
 143                 return ret;
 144         }
 145 
 146         /*
 147          * Acquire IRQs for the GPIO pins if possible. If the system does not
 148          * support IRQs on these pins, userspace will have to poll the sysfs
 149          * files manually.
 150          */
 151         if (lt3651_charger->acpr_gpio) {
 152                 ret = gpiod_to_irq(lt3651_charger->acpr_gpio);
 153                 if (ret >= 0)
 154                         ret = devm_request_any_context_irq(&pdev->dev, ret,
 155                                 lt3651_charger_irq,
 156                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 157                                 dev_name(&pdev->dev), lt3651_charger->charger);
 158                 if (ret < 0)
 159                         dev_warn(&pdev->dev, "Failed to request acpr irq\n");
 160         }
 161         if (lt3651_charger->fault_gpio) {
 162                 ret = gpiod_to_irq(lt3651_charger->fault_gpio);
 163                 if (ret >= 0)
 164                         ret = devm_request_any_context_irq(&pdev->dev, ret,
 165                                 lt3651_charger_irq,
 166                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 167                                 dev_name(&pdev->dev), lt3651_charger->charger);
 168                 if (ret < 0)
 169                         dev_warn(&pdev->dev, "Failed to request fault irq\n");
 170         }
 171         if (lt3651_charger->chrg_gpio) {
 172                 ret = gpiod_to_irq(lt3651_charger->chrg_gpio);
 173                 if (ret >= 0)
 174                         ret = devm_request_any_context_irq(&pdev->dev, ret,
 175                                 lt3651_charger_irq,
 176                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 177                                 dev_name(&pdev->dev), lt3651_charger->charger);
 178                 if (ret < 0)
 179                         dev_warn(&pdev->dev, "Failed to request chrg irq\n");
 180         }
 181 
 182         platform_set_drvdata(pdev, lt3651_charger);
 183 
 184         return 0;
 185 }
 186 
 187 static const struct of_device_id lt3651_charger_match[] = {
 188         { .compatible = "lltc,ltc3651-charger" }, /* DEPRECATED */
 189         { .compatible = "lltc,lt3651-charger" },
 190         { }
 191 };
 192 MODULE_DEVICE_TABLE(of, lt3651_charger_match);
 193 
 194 static struct platform_driver lt3651_charger_driver = {
 195         .probe = lt3651_charger_probe,
 196         .driver = {
 197                 .name = "lt3651-charger",
 198                 .of_match_table = lt3651_charger_match,
 199         },
 200 };
 201 
 202 module_platform_driver(lt3651_charger_driver);
 203 
 204 MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
 205 MODULE_DESCRIPTION("Driver for LT3651 charger");
 206 MODULE_LICENSE("GPL");
 207 MODULE_ALIAS("platform:lt3651-charger");

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