diff options
| -rw-r--r-- | drivers/power/supply/gpio-charger.c | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c index 7e4f11d5a230..f99e8f1eef23 100644 --- a/drivers/power/supply/gpio-charger.c +++ b/drivers/power/supply/gpio-charger.c | |||
| @@ -29,11 +29,13 @@ | |||
| 29 | 29 | ||
| 30 | struct gpio_charger { | 30 | struct gpio_charger { |
| 31 | unsigned int irq; | 31 | unsigned int irq; |
| 32 | unsigned int charge_status_irq; | ||
| 32 | bool wakeup_enabled; | 33 | bool wakeup_enabled; |
| 33 | 34 | ||
| 34 | struct power_supply *charger; | 35 | struct power_supply *charger; |
| 35 | struct power_supply_desc charger_desc; | 36 | struct power_supply_desc charger_desc; |
| 36 | struct gpio_desc *gpiod; | 37 | struct gpio_desc *gpiod; |
| 38 | struct gpio_desc *charge_status; | ||
| 37 | }; | 39 | }; |
| 38 | 40 | ||
| 39 | static irqreturn_t gpio_charger_irq(int irq, void *devid) | 41 | static irqreturn_t gpio_charger_irq(int irq, void *devid) |
| @@ -59,6 +61,12 @@ static int gpio_charger_get_property(struct power_supply *psy, | |||
| 59 | case POWER_SUPPLY_PROP_ONLINE: | 61 | case POWER_SUPPLY_PROP_ONLINE: |
| 60 | val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); | 62 | val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); |
| 61 | break; | 63 | break; |
| 64 | case POWER_SUPPLY_PROP_STATUS: | ||
| 65 | if (gpiod_get_value_cansleep(gpio_charger->charge_status)) | ||
| 66 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 67 | else | ||
| 68 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 69 | break; | ||
| 62 | default: | 70 | default: |
| 63 | return -EINVAL; | 71 | return -EINVAL; |
| 64 | } | 72 | } |
| @@ -93,8 +101,29 @@ static enum power_supply_type gpio_charger_get_type(struct device *dev) | |||
| 93 | return POWER_SUPPLY_TYPE_UNKNOWN; | 101 | return POWER_SUPPLY_TYPE_UNKNOWN; |
| 94 | } | 102 | } |
| 95 | 103 | ||
| 104 | static int gpio_charger_get_irq(struct device *dev, void *dev_id, | ||
| 105 | struct gpio_desc *gpio) | ||
| 106 | { | ||
| 107 | int ret, irq = gpiod_to_irq(gpio); | ||
| 108 | |||
| 109 | if (irq > 0) { | ||
| 110 | ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq, | ||
| 111 | IRQF_TRIGGER_RISING | | ||
| 112 | IRQF_TRIGGER_FALLING, | ||
| 113 | dev_name(dev), | ||
| 114 | dev_id); | ||
| 115 | if (ret < 0) { | ||
| 116 | dev_warn(dev, "Failed to request irq: %d\n", ret); | ||
| 117 | irq = 0; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | return irq; | ||
| 122 | } | ||
| 123 | |||
| 96 | static enum power_supply_property gpio_charger_properties[] = { | 124 | static enum power_supply_property gpio_charger_properties[] = { |
| 97 | POWER_SUPPLY_PROP_ONLINE, | 125 | POWER_SUPPLY_PROP_ONLINE, |
| 126 | POWER_SUPPLY_PROP_STATUS /* Must always be last in the array. */ | ||
| 98 | }; | 127 | }; |
| 99 | 128 | ||
| 100 | static int gpio_charger_probe(struct platform_device *pdev) | 129 | static int gpio_charger_probe(struct platform_device *pdev) |
| @@ -104,8 +133,10 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
| 104 | struct power_supply_config psy_cfg = {}; | 133 | struct power_supply_config psy_cfg = {}; |
| 105 | struct gpio_charger *gpio_charger; | 134 | struct gpio_charger *gpio_charger; |
| 106 | struct power_supply_desc *charger_desc; | 135 | struct power_supply_desc *charger_desc; |
| 136 | struct gpio_desc *charge_status; | ||
| 137 | int charge_status_irq; | ||
| 107 | unsigned long flags; | 138 | unsigned long flags; |
| 108 | int irq, ret; | 139 | int ret; |
| 109 | 140 | ||
| 110 | if (!pdata && !dev->of_node) { | 141 | if (!pdata && !dev->of_node) { |
| 111 | dev_err(dev, "No platform data\n"); | 142 | dev_err(dev, "No platform data\n"); |
| @@ -151,9 +182,17 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
| 151 | return PTR_ERR(gpio_charger->gpiod); | 182 | return PTR_ERR(gpio_charger->gpiod); |
| 152 | } | 183 | } |
| 153 | 184 | ||
| 185 | charge_status = devm_gpiod_get_optional(dev, "charge-status", GPIOD_IN); | ||
| 186 | gpio_charger->charge_status = charge_status; | ||
| 187 | if (IS_ERR(gpio_charger->charge_status)) | ||
| 188 | return PTR_ERR(gpio_charger->charge_status); | ||
| 189 | |||
| 154 | charger_desc = &gpio_charger->charger_desc; | 190 | charger_desc = &gpio_charger->charger_desc; |
| 155 | charger_desc->properties = gpio_charger_properties; | 191 | charger_desc->properties = gpio_charger_properties; |
| 156 | charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties); | 192 | charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties); |
| 193 | /* Remove POWER_SUPPLY_PROP_STATUS from the supported properties. */ | ||
| 194 | if (!gpio_charger->charge_status) | ||
| 195 | charger_desc->num_properties -= 1; | ||
| 157 | charger_desc->get_property = gpio_charger_get_property; | 196 | charger_desc->get_property = gpio_charger_get_property; |
| 158 | 197 | ||
| 159 | psy_cfg.of_node = dev->of_node; | 198 | psy_cfg.of_node = dev->of_node; |
| @@ -180,16 +219,12 @@ static int gpio_charger_probe(struct platform_device *pdev) | |||
| 180 | return ret; | 219 | return ret; |
| 181 | } | 220 | } |
| 182 | 221 | ||
| 183 | irq = gpiod_to_irq(gpio_charger->gpiod); | 222 | gpio_charger->irq = gpio_charger_get_irq(dev, gpio_charger->charger, |
| 184 | if (irq > 0) { | 223 | gpio_charger->gpiod); |
| 185 | ret = devm_request_any_context_irq(dev, irq, gpio_charger_irq, | 224 | |
| 186 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | 225 | charge_status_irq = gpio_charger_get_irq(dev, gpio_charger->charger, |
| 187 | dev_name(dev), gpio_charger->charger); | 226 | gpio_charger->charge_status); |
| 188 | if (ret < 0) | 227 | gpio_charger->charge_status_irq = charge_status_irq; |
| 189 | dev_warn(dev, "Failed to request irq: %d\n", ret); | ||
| 190 | else | ||
| 191 | gpio_charger->irq = irq; | ||
| 192 | } | ||
| 193 | 228 | ||
| 194 | platform_set_drvdata(pdev, gpio_charger); | 229 | platform_set_drvdata(pdev, gpio_charger); |
| 195 | 230 | ||
