Generic GPIO connected chargers support
cover Generic GPIO connected chargers support
Hi,
this patchset tries to implement an idea mentioned here:
https://marc.info/?l=linux-pm&m=149849407023228&w=2
(with comments taken into account).
First two patches could be possibly merged as these are cleanups only.
I'm sending the rest as a basis for a discussion which will hopefuly bring some bright ideas :)
Thank you,
ladis
Ladislav Michl (5):
power: supply: gpio-charger: Drop driver remove function
power: supply: gpio-charger: use helper variable to access device info
power: supply: gpio-charger: generic gpio algo
power: supply: gpio-charger: LTC3651 support
power: supply: gpio-charger: LM3658 support
drivers/power/supply/gpio-charger.c | 486 ++++++++++++++++++++++++++---------- 1 file changed, 348 insertions(+), 138 deletions(-)
Signature · 1 line
2.15.1
PATCH 1/5 power: supply: gpio-charger: Drop driver remove function
Simplify error unwinding using devm_* allocators. This also makes driver remove function empty, so remove it.
--- drivers/power/supply/gpio-charger.c | 49 ++++++++----------------------------- 1 file changed, 10 insertions(+), 39 deletions(-)
drivers/power/supply/gpio-charger.c +10 -39
@@ -35,7 +35,6 @@ struct gpio_charger {struct power_supply *charger;struct power_supply_desc charger_desc;struct gpio_desc *gpiod; -bool legacy_gpio_requested; };static irqreturn_t gpio_charger_irq (int irq,void *devid)
@@ -159,18 +158,12 @@ static int gpio_charger_probe(struct platform_device *pdev)dev_err (&pdev->dev,"Invalid gpio pin in pdata\n" );return -EINVAL ; } - ret =gpio_request (pdata->gpio,dev_name (&pdev->dev)); -if (ret) { + err =devm_gpio_request_one (&pdev->dev, pdata->gpio,GPIOF_IN , +dev_name (&pdev->dev)); +if (err) {dev_err (&pdev->dev,"Failed to request gpio pin: %d\n" , - ret); -return ret; - } - gpio_charger->legacy_gpio_requested = true; - ret =gpio_direction_input (pdata->gpio); -if (ret) { -dev_err (&pdev->dev,"Failed to set gpio to input: %d\n" , - ret); - goto err_gpio_free; + err); +return err; }/* Then convert this to gpiod for now */ gpio_charger->gpiod =gpio_to_desc (pdata->gpio);
@@ -195,20 +188,19 @@ static int gpio_charger_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = gpio_charger; - gpio_charger->pdata = pdata; - - gpio_charger->charger =power_supply_register (&pdev->dev, - charger_desc, &psy_cfg); + gpio_charger->charger =devm_power_supply_register (&pdev->dev, + charger_desc, &psy_cfg);if (IS_ERR (gpio_charger->charger)) { ret =PTR_ERR (gpio_charger->charger);dev_err (&pdev->dev,"Failed to register power supply: %d\n" , ret); - goto err_gpio_free; +return ret; } irq =gpiod_to_irq (gpio_charger->gpiod);if (irq >0 ) { - ret =request_any_context_irq (irq, gpio_charger_irq, + ret =devm_request_any_context_irq (&pdev->dev, irq, + gpio_charger_irq,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING ,dev_name (&pdev->dev), gpio_charger->charger);if (ret <0 )
@@ -222,26 +214,6 @@ static int gpio_charger_probe(struct platform_device *pdev)device_init_wakeup (&pdev->dev,1 );return 0 ; - -err_gpio_free: -if (gpio_charger->legacy_gpio_requested) -gpio_free (pdata->gpio); -return ret; -} - -static int gpio_charger_remove (struct platform_device *pdev) -{ -struct gpio_charger *gpio_charger =platform_get_drvdata (pdev); - -if (gpio_charger->irq) -free_irq (gpio_charger->irq, gpio_charger->charger); - -power_supply_unregister (gpio_charger->charger); - -if (gpio_charger->legacy_gpio_requested) -gpio_free (gpio_charger->pdata->gpio); - -return 0 ; }#ifdef CONFIG_PM_SLEEP
@@ -280,7 +252,6 @@ MODULE_DEVICE_TABLE(of, gpio_charger_match);static struct platform_driver gpio_charger_driver = { .probe = gpio_charger_probe, - .remove = gpio_charger_remove, .driver = { .name ="gpio-charger" , .pm = &gpio_charger_pm_ops,
Signature · 1 line
2.15.1
PATCH 2/5 power: supply: gpio-charger: use helper variable to access device info
In reply to Ladislav MichlUsing explicit struct device variable makes code a bit more readable.
--- drivers/power/supply/gpio-charger.c | 42 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
drivers/power/supply/gpio-charger.c +20 -22
@@ -118,7 +118,8 @@ struct gpio_charger_platform_data *gpio_charger_parse_dt(struct device *dev)static int gpio_charger_probe (struct platform_device *pdev) { -const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; +struct device *dev = &pdev->dev; +const struct gpio_charger_platform_data *pdata = dev->platform_data;struct power_supply_config psy_cfg = {};struct gpio_charger *gpio_charger;struct power_supply_desc *charger_desc;
@@ -126,19 +127,18 @@ static int gpio_charger_probe(struct platform_device *pdev)int irq;if (!pdata) { - pdata =gpio_charger_parse_dt (&pdev->dev); + pdata =gpio_charger_parse_dt (dev);if (IS_ERR (pdata)) { ret =PTR_ERR (pdata);if (ret != -EPROBE_DEFER ) -dev_err (&pdev->dev,"No platform data\n" ); +dev_err (dev,"No platform data\n" );return ret; } } - gpio_charger =devm_kzalloc (&pdev->dev,sizeof (*gpio_charger), -GFP_KERNEL ); + gpio_charger =devm_kzalloc (dev,sizeof (*gpio_charger),GFP_KERNEL );if (!gpio_charger) { -dev_err (&pdev->dev,"Failed to alloc driver structure\n" ); +dev_err (dev,"Failed to alloc driver structure\n" );return -ENOMEM ; }
@@ -146,20 +146,20 @@ static int gpio_charger_probe(struct platform_device *pdev)* This will fetch a GPIO descriptor from device tree, ACPI or * boardfile descriptor tables. It's good to try this first. */ - gpio_charger->gpiod =devm_gpiod_get (&pdev->dev,NULL ,GPIOD_IN ); + gpio_charger->gpiod =devm_gpiod_get (dev,NULL ,GPIOD_IN );/* * If this fails and we're not using device tree, try the * legacy platform data method. */ -if (IS_ERR (gpio_charger->gpiod) && !pdev->dev.of_node) { +if (IS_ERR (gpio_charger->gpiod) && !dev->of_node) {/* Non-DT: use legacy GPIO numbers */ if (!gpio_is_valid (pdata->gpio)) { -dev_err (&pdev->dev,"Invalid gpio pin in pdata\n" ); +dev_err (dev,"Invalid gpio pin in pdata\n" );return -EINVAL ; } - err =devm_gpio_request_one (&pdev->dev, pdata->gpio,GPIOF_IN , -dev_name (&pdev->dev)); + err =devm_gpio_request_one (dev, pdata->gpio,GPIOF_IN , +dev_name (dev));if (err) {dev_err (&pdev->dev,"Failed to request gpio pin: %d\n" , err);
@@ -171,7 +171,7 @@ static int gpio_charger_probe(struct platform_device *pdev)/* Just try again if this happens */ if (PTR_ERR (gpio_charger->gpiod) == -EPROBE_DEFER )return -EPROBE_DEFER ; -dev_err (&pdev->dev,"error getting GPIO descriptor\n" ); +dev_err (dev,"error getting GPIO descriptor\n" );return PTR_ERR (gpio_charger->gpiod); }
@@ -185,33 +185,31 @@ static int gpio_charger_probe(struct platform_device *pdev) psy_cfg.supplied_to = pdata->supplied_to; psy_cfg.num_supplicants = pdata->num_supplicants; - psy_cfg.of_node = pdev->dev.of_node; + psy_cfg.of_node = dev->of_node; psy_cfg.drv_data = gpio_charger; - gpio_charger->charger =devm_power_supply_register (&pdev->dev, - charger_desc, &psy_cfg); + gpio_charger->charger =devm_power_supply_register (dev, charger_desc, + &psy_cfg);if (IS_ERR (gpio_charger->charger)) { ret =PTR_ERR (gpio_charger->charger); -dev_err (&pdev->dev,"Failed to register power supply: %d\n" , - ret); +dev_err (dev,"Failed to register power supply: %d\n" , ret);return ret; } irq =gpiod_to_irq (gpio_charger->gpiod);if (irq >0 ) { - ret =devm_request_any_context_irq (&pdev->dev, irq, - gpio_charger_irq, + ret =devm_request_any_context_irq (dev, irq, gpio_charger_irq,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING , -dev_name (&pdev->dev), gpio_charger->charger); +dev_name (dev), gpio_charger->charger);if (ret <0 ) -dev_warn (&pdev->dev,"Failed to request irq: %d\n" , ret); +dev_warn (dev,"Failed to request irq: %d\n" , ret);else gpio_charger->irq = irq; }platform_set_drvdata (pdev, gpio_charger); -device_init_wakeup (&pdev->dev,1 ); +device_init_wakeup (dev,1 );return 0 ; }
Signature · 1 line
2.15.1
PATCH 3/5 power: supply: gpio-charger: generic gpio algo
In reply to Ladislav MichlJust a proof of concept...
--- drivers/power/supply/gpio-charger.c | 323 ++++++++++++++++++++++++++---------- 1 file changed, 231 insertions(+), 92 deletions(-)
drivers/power/supply/gpio-charger.c +231 -92
@@ -23,20 +23,62 @@#include <linux/power_supply.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/gpio/consumer.h> #include <linux/power/gpio-charger.h> -struct gpio_charger { -const struct gpio_charger_platform_data *pdata; -unsigned int irq; +struct gpio_charger_pin_map { +int val; +int res; +}; + +#define _VA_NARGS (_1, _2, _3, _4, _5, _6, _7, _8,N , ...) N +#define VA_NARGS (...) _VA_NARGS(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1) / 2 +#define MAP (mask, ...) mask, VA_NARGS(__VA_ARGS__), \ + (struct gpio_charger_pin_map[VA_NARGS(__VA_ARGS__)]) \ + {__VA_ARGS__} + +struct gpio_charger_mapping { +enum power_supply_property psp; +int defres; +int mask; +int nmaps; +struct gpio_charger_pin_map *map; +}; + +#define FLAG_PIN_OPTIONAL 0x01 +#define MAPPING (map) ARRAY_SIZE(map), map + +struct gpio_charger_config { +int nmaps; +struct gpio_charger_mapping *mapping; +struct { +char *label; +int flags; + } gpios[]; +}; + +struct gpio_charger_pin { +struct gpio_desc *gpiod; +int irq;bool wakeup_enabled; +}; + +struct gpio_charger { +int gpio_active_low;struct power_supply *charger;struct power_supply_desc charger_desc; -struct gpio_desc *gpiod; + +int nmaps; +struct gpio_charger_mapping *mapping; + +int npins; +struct gpio_charger_pin pin[]; }; +static irqreturn_t gpio_charger_irq (int irq,void *devid) {struct power_supply *charger = devid;
@@ -51,108 +93,124 @@ static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)return power_supply_get_drvdata (psy); } +static inline int gpio_charger_pins_available (struct gpio_charger *charger, +struct gpio_charger_mapping *mapping) +{ +int i; + +for (i =0 ; i < charger->npins; i++) +if (!charger->pin[i].gpiod && ((1 << i) & mapping->mask)) +return 0 ; +return 1 ; +} +static int gpio_charger_get_property (struct power_supply *psy,enum power_supply_property psp,union power_supply_propval *val) { +int i, v, res; +struct gpio_charger_pin *pin; +struct gpio_charger_mapping *mapping =NULL ;struct gpio_charger *gpio_charger =psy_to_gpio_charger (psy); -const struct gpio_charger_platform_data *pdata = gpio_charger->pdata; - -switch (psp) { -case POWER_SUPPLY_PROP_ONLINE : - val->intval =gpiod_get_value_cansleep (gpio_charger->gpiod); -/* This xor is only ever used with legacy pdata GPIO */ - val->intval ^= pdata->gpio_active_low; -break ; -default : + +for (i =0 ; i < gpio_charger->nmaps; i++) { +if (gpio_charger->mapping[i].psp == psp) { + mapping = &gpio_charger->mapping[i]; +break ; + } + } + +if (!mapping)return -EINVAL ; + +if (gpio_charger_pins_available (gpio_charger, mapping)) { + res =0 ; +for (i =0 ; i < gpio_charger->npins; i++) { + pin = &gpio_charger->pin[i]; +if (((1 << i) & mapping->mask) ==0 ) +continue ; + v =gpiod_get_value_cansleep (pin->gpiod); +if (v <0 ) +return v; + res |= v << i; + } + + val->intval = mapping->defres; +for (i =0 ; i < mapping->nmaps; i++) { +if (mapping->map[i].val == res) { + val->intval = mapping->map[i].res; +break ; + } + } + }else { + val->intval = mapping->defres; } +/* Special hack for legacy pdata GPIO */ +if (psp ==POWER_SUPPLY_PROP_ONLINE && gpio_charger->gpio_active_low) + val->intval ^=1 ; +return 0 ; } -static enum power_supply_property gpio_charger_properties[] = { -POWER_SUPPLY_PROP_ONLINE , -}; - -static -struct gpio_charger_platform_data *gpio_charger_parse_dt (struct device *dev) +static enum power_supply_type gpio_charger_get_type (struct device *dev) { -struct device_node *np = dev->of_node; -struct gpio_charger_platform_data *pdata; -const char *chargetype;int ret; +const char *chargetype; +enum power_supply_type type =POWER_SUPPLY_TYPE_UNKNOWN ; -if (!np) -return ERR_PTR (-ENOENT ); - - pdata =devm_kzalloc (dev,sizeof (*pdata),GFP_KERNEL ); -if (!pdata) -return ERR_PTR (-ENOMEM ); - - pdata->name = np->name; - pdata->type =POWER_SUPPLY_TYPE_UNKNOWN ; - ret =of_property_read_string (np,"charger-type" , &chargetype); + ret =of_property_read_string (dev->of_node,"charger-type" , &chargetype);if (ret >=0 ) {if (!strncmp ("unknown" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_UNKNOWN ; + type =POWER_SUPPLY_TYPE_UNKNOWN ;else if (!strncmp ("battery" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_BATTERY ; + type =POWER_SUPPLY_TYPE_BATTERY ;else if (!strncmp ("ups" , chargetype,3 )) - pdata->type =POWER_SUPPLY_TYPE_UPS ; + type =POWER_SUPPLY_TYPE_UPS ;else if (!strncmp ("mains" , chargetype,5 )) - pdata->type =POWER_SUPPLY_TYPE_MAINS ; + type =POWER_SUPPLY_TYPE_MAINS ;else if (!strncmp ("usb-sdp" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_USB ; + type =POWER_SUPPLY_TYPE_USB ;else if (!strncmp ("usb-dcp" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_USB_DCP ; + type =POWER_SUPPLY_TYPE_USB_DCP ;else if (!strncmp ("usb-cdp" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_USB_CDP ; + type =POWER_SUPPLY_TYPE_USB_CDP ;else if (!strncmp ("usb-aca" , chargetype,7 )) - pdata->type =POWER_SUPPLY_TYPE_USB_ACA ; + type =POWER_SUPPLY_TYPE_USB_ACA ;else dev_warn (dev,"unknown charger type %s\n" , chargetype); } -return pdata; +return type; } -static int gpio_charger_probe (struct platform_device *pdev) +static struct gpio_charger_mapping simple_mapping = { +POWER_SUPPLY_PROP_ONLINE , +0 , + MAP(0x01, { 0x01, 1 }), +}; + +static int gpio_charger_simple_init (struct device *dev, +struct gpio_charger *gpio_charger, +const struct gpio_charger_platform_data *pdata) { -struct device *dev = &pdev->dev; -const struct gpio_charger_platform_data *pdata = dev->platform_data; -struct power_supply_config psy_cfg = {}; -struct gpio_charger *gpio_charger; +int err; +struct gpio_desc *gpiod;struct power_supply_desc *charger_desc; -int ret; -int irq; - -if (!pdata) { - pdata =gpio_charger_parse_dt (dev); -if (IS_ERR (pdata)) { - ret =PTR_ERR (pdata); -if (ret != -EPROBE_DEFER ) -dev_err (dev,"No platform data\n" ); -return ret; - } - } - - gpio_charger =devm_kzalloc (dev,sizeof (*gpio_charger),GFP_KERNEL ); -if (!gpio_charger) { -dev_err (dev,"Failed to alloc driver structure\n" ); -return -ENOMEM ; - } +static enum power_supply_property properties[] = { +POWER_SUPPLY_PROP_ONLINE , + };/* * This will fetch a GPIO descriptor from device tree, ACPI or * boardfile descriptor tables. It's good to try this first. */ - gpio_charger->gpiod =devm_gpiod_get (dev,NULL ,GPIOD_IN ); + gpiod =devm_gpiod_get (dev,NULL ,GPIOD_IN );/* * If this fails and we're not using device tree, try the * legacy platform data method. */ -if (IS_ERR (gpio_charger->gpiod) && !dev->of_node) { +if (IS_ERR (gpiod) && !dev->of_node && pdata) {/* Non-DT: use legacy GPIO numbers */ if (!gpio_is_valid (pdata->gpio)) {dev_err (dev,"Invalid gpio pin in pdata\n" );
@@ -161,32 +219,97 @@ static int gpio_charger_probe(struct platform_device *pdev) err =devm_gpio_request_one (dev, pdata->gpio,GPIOF_IN ,dev_name (dev));if (err) { -dev_err (&pdev->dev,"Failed to request gpio pin: %d\n" , - err); +dev_err (dev,"Failed to request gpio pin: %d\n" , err);return err; }/* Then convert this to gpiod for now */ - gpio_charger->gpiod =gpio_to_desc (pdata->gpio); - }else if (IS_ERR (gpio_charger->gpiod)) { + gpiod =gpio_to_desc (pdata->gpio); + }else if (IS_ERR (gpiod)) {/* Just try again if this happens */ -if (PTR_ERR (gpio_charger->gpiod) == -EPROBE_DEFER ) -return -EPROBE_DEFER ; -dev_err (dev,"error getting GPIO descriptor\n" ); -return PTR_ERR (gpio_charger->gpiod); +if (PTR_ERR (gpiod) != -EPROBE_DEFER ) +dev_err (dev,"error getting GPIO descriptor\n" ); +return PTR_ERR (gpiod); } + gpio_charger->nmaps =1 ; + gpio_charger->mapping = &simple_mapping; + gpio_charger->npins =1 ; + gpio_charger->pin[0 ].gpiod = gpiod; + charger_desc = &gpio_charger->charger_desc; + charger_desc->type =POWER_SUPPLY_TYPE_UNKNOWN ; + charger_desc->properties = properties; + charger_desc->num_properties =ARRAY_SIZE (properties); + +if (pdata) { + charger_desc->name = pdata->name; + charger_desc->type = pdata->type; + gpio_charger->gpio_active_low = pdata->gpio_active_low; + } + +return 0 ; +} + +static int gpio_charger_cfg_init (struct device *dev, +struct gpio_charger *gpio_charger, +struct gpio_charger_config *cfg) +{ +return -EINVAL ; +} + +static int gpio_charger_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +const struct gpio_charger_platform_data *pdata = dev->platform_data; +struct power_supply_config psy_cfg = {}; +struct gpio_charger_pin *pin; +struct gpio_charger *gpio_charger; +struct power_supply_desc *charger_desc; +struct gpio_charger_config *cfg; +int i, ret; + +if (!pdata && !dev->of_node) { +dev_err (dev,"No platform data\n" ); +return -ENOENT ; + } + + i =1 ; + cfg = (struct gpio_charger_config *)of_device_get_match_data (dev); +if (cfg) +while (cfg->gpios[i].label) + i++; + + gpio_charger =devm_kzalloc (dev,sizeof (struct gpio_charger ) + + i *sizeof (struct gpio_charger_pin ), +GFP_KERNEL ); +if (!gpio_charger) { +dev_err (dev,"Failed to alloc driver structure\n" ); +return -ENOMEM ; + } + +if (cfg) + ret =gpio_charger_cfg_init (dev, gpio_charger, cfg); +else + ret =gpio_charger_simple_init (dev, gpio_charger, pdata); - charger_desc->name = pdata->name ? pdata->name :"gpio-charger" ; - charger_desc->type = pdata->type; - charger_desc->properties = gpio_charger_properties; - charger_desc->num_properties =ARRAY_SIZE (gpio_charger_properties); +if (ret) +return ret; + + charger_desc = &gpio_charger->charger_desc; charger_desc->get_property = gpio_charger_get_property; +if (charger_desc->type ==POWER_SUPPLY_TYPE_UNKNOWN ) + charger_desc->type =gpio_charger_get_type (&pdev->dev); +if (!charger_desc->name && pdev->dev.of_node) + charger_desc->name = pdev->dev.of_node->name; +if (!charger_desc->name) + charger_desc->name ="gpio-charger" ; - psy_cfg.supplied_to = pdata->supplied_to; - psy_cfg.num_supplicants = pdata->num_supplicants; psy_cfg.of_node = dev->of_node; psy_cfg.drv_data = gpio_charger; +if (pdata) { + psy_cfg.supplied_to = pdata->supplied_to; + psy_cfg.num_supplicants = pdata->num_supplicants; + } gpio_charger->charger =devm_power_supply_register (dev, charger_desc, &psy_cfg);
@@ -196,15 +319,17 @@ static int gpio_charger_probe(struct platform_device *pdev)return ret; } - irq =gpiod_to_irq (gpio_charger->gpiod); -if (irq >0 ) { - ret =devm_request_any_context_irq (dev, irq, gpio_charger_irq, +for (i =0 ; i < gpio_charger->npins; i++) { + pin = &gpio_charger->pin[i]; + pin->irq =gpiod_to_irq (pin->gpiod); +if (pin->irq <0 ) +continue ; + ret =devm_request_any_context_irq (dev, pin->irq, + gpio_charger_irq,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING ,dev_name (dev), gpio_charger->charger);if (ret <0 )dev_warn (dev,"Failed to request irq: %d\n" , ret); -else - gpio_charger->irq = irq; }platform_set_drvdata (pdev, gpio_charger);
@@ -217,22 +342,36 @@ static int gpio_charger_probe(struct platform_device *pdev)#ifdef CONFIG_PM_SLEEP static int gpio_charger_suspend (struct device *dev) { +int i; +struct gpio_charger_pin *pin;struct gpio_charger *gpio_charger =dev_get_drvdata (dev); -if (device_may_wakeup (dev)) - gpio_charger->wakeup_enabled = - !enable_irq_wake (gpio_charger->irq); +if (device_may_wakeup (dev)) { +for (i =0 ; i < gpio_charger->npins; i++) { + pin = &gpio_charger->pin[i]; +if (pin->irq <0 ) +continue ; + pin->wakeup_enabled = !enable_irq_wake (pin->irq); + } + }return 0 ; }static int gpio_charger_resume (struct device *dev) { -struct platform_device *pdev =to_platform_device (dev); -struct gpio_charger *gpio_charger =platform_get_drvdata (pdev); +int i; +struct gpio_charger_pin *pin; +struct gpio_charger *gpio_charger =dev_get_drvdata (dev); + +if (device_may_wakeup (dev)) { +for (i =0 ; i < gpio_charger->npins; i++) { + pin = &gpio_charger->pin[i]; +if (pin->wakeup_enabled) +disable_irq_wake (pin->irq); + } + } -if (device_may_wakeup (dev) && gpio_charger->wakeup_enabled) -disable_irq_wake (gpio_charger->irq);power_supply_changed (gpio_charger->charger);return 0 ;
Signature · 1 line
2.15.1
PATCH 4/5 power: supply: gpio-charger: LTC3651 support
In reply to Ladislav MichlJust a proof of concept...
--- drivers/power/supply/gpio-charger.c | 78 ++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-)
drivers/power/supply/gpio-charger.c +76 -2
@@ -254,7 +254,45 @@ static int gpio_charger_cfg_init(struct device *dev,struct gpio_charger *gpio_charger, struct gpio_charger_config *cfg) { - return -EINVAL; + struct gpio_desc *gpiod; +struct power_supply_desc *charger_desc; +int ret, i =0 ; + +while (cfg->gpios[i].label) { + gpiod = (cfg->gpios[i].flags &FLAG_PIN_OPTIONAL ) ? +devm_gpiod_get_optional (dev, cfg->gpios[i].label, +GPIOD_IN ) : +devm_gpiod_get (dev, cfg->gpios[i].label,GPIOD_IN ); + +if (IS_ERR (gpiod)) { + ret =PTR_ERR (gpiod); +if (ret !=EPROBE_DEFER ) +dev_err (dev, +"Failed to acquire '%s' GPIO: %d\n" , + cfg->gpios[i].label, ret); +return ret; + } + gpio_charger->pin[i].gpiod = gpiod; + i++; + } + + gpio_charger->nmaps = cfg->nmaps; + gpio_charger->mapping = cfg->mapping; + gpio_charger->npins = i; + + charger_desc = &gpio_charger->charger_desc; + charger_desc->type =POWER_SUPPLY_TYPE_MAINS ; + charger_desc->num_properties = cfg->nmaps; + charger_desc->properties =devm_kzalloc (dev, + cfg->nmaps *sizeof (enum power_supply_property ), +GFP_KERNEL ); +if (!charger_desc->properties) +return -ENOMEM ; + +for (i =0 ; i < cfg->nmaps; i++) + charger_desc->properties[i] = cfg->mapping[i].psp; + +return 0 ; }static int gpio_charger_probe (struct platform_device *pdev)
@@ -381,8 +419,44 @@ static int gpio_charger_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, gpio_charger_suspend, gpio_charger_resume); +struct gpio_charger_mapping chrg_fault_mapping[] = { + { +POWER_SUPPLY_PROP_ONLINE , +0 , +MAP (0x01 , + { 0x01, 1 }), + }, { +POWER_SUPPLY_PROP_STATUS , +POWER_SUPPLY_STATUS_UNKNOWN , +MAP (0x02 , + { 0x02, POWER_SUPPLY_STATUS_CHARGING }, + { 0x00, POWER_SUPPLY_STATUS_NOT_CHARGING }), + }, { +POWER_SUPPLY_PROP_HEALTH , +POWER_SUPPLY_HEALTH_UNKNOWN , +MAP (0x06 , + { 0x00, POWER_SUPPLY_HEALTH_GOOD }, + { 0x02, POWER_SUPPLY_HEALTH_OVERHEAT }, + { 0x06, POWER_SUPPLY_HEALTH_DEAD }), + }, +}; + +static const struct gpio_charger_config ltc3651_cfg = { +MAPPING (chrg_fault_mapping), + { + {"lltc,acpr" ,0 }, + {"lltc,chrg" ,FLAG_PIN_OPTIONAL }, + {"lltc,fault" ,FLAG_PIN_OPTIONAL }, + {NULL ,0 }, + }, +}; +static const struct of_device_id gpio_charger_match[] = { - { .compatible ="gpio-charger" }, + { .compatible ="gpio-charger" }, + { + .compatible ="lltc,ltc3651-charger" , + .data = (void *) <c3651_cfg, + }, { } };MODULE_DEVICE_TABLE (of, gpio_charger_match);
Signature · 1 line
2.15.1
PATCH 5/5 power: supply: gpio-charger: LM3658 support
In reply to Ladislav MichlJust a proof of concept...
--- drivers/power/supply/gpio-charger.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
drivers/power/supply/gpio-charger.c +28 -0
@@ -441,6 +441,21 @@ struct gpio_charger_mapping chrg_fault_mapping[] = { }, }; +struct gpio_charger_mapping stat12_mapping[] = { + { +POWER_SUPPLY_PROP_STATUS , +POWER_SUPPLY_STATUS_NOT_CHARGING , +MAP (0x03 , + { 0x01, POWER_SUPPLY_STATUS_CHARGING }, + { 0x02, POWER_SUPPLY_STATUS_FULL }), + }, { +POWER_SUPPLY_PROP_HEALTH , +POWER_SUPPLY_HEALTH_GOOD , +MAP (0x03 , + { 0x03, POWER_SUPPLY_HEALTH_DEAD }), + }, +}; +static const struct gpio_charger_config ltc3651_cfg = {MAPPING (chrg_fault_mapping), {
@@ -451,12 +466,25 @@ static const struct gpio_charger_config ltc3651_cfg = { }, }; +static const struct gpio_charger_config lm3658_cfg = { +MAPPING (stat12_mapping), + { + {"ti,stat1" ,0 }, + {"ti,stat2" ,0 }, + {NULL ,0 }, + }, +}; +static const struct of_device_id gpio_charger_match[] = { { .compatible ="gpio-charger" }, { .compatible ="lltc,ltc3651-charger" , .data = (void *) <c3651_cfg, }, + { + .compatible ="ti,lm3658" , + .data = (void *) &lm3658_cfg, + }, { } };MODULE_DEVICE_TABLE (of, gpio_charger_match);
Signature · 1 line
2.15.1