All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Generic GPIO connected chargers support
@ 2018-01-17 20:27 Ladislav Michl
  2018-01-17 20:31 ` [PATCH 1/5] power: supply: gpio-charger: Drop driver remove function Ladislav Michl
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:27 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

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(-)

-- 
2.15.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] power: supply: gpio-charger: Drop driver remove function
  2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
@ 2018-01-17 20:31 ` Ladislav Michl
  2018-01-17 20:31 ` [PATCH 2/5] power: supply: gpio-charger: use helper variable to access device info Ladislav Michl
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:31 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

Simplify error unwinding using devm_* allocators. This also
makes driver remove function empty, so remove it.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
 drivers/power/supply/gpio-charger.c | 49 ++++++++-----------------------------
 1 file changed, 10 insertions(+), 39 deletions(-)

diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 001731e88718..9c008ef8cf70 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -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,
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] power: supply: gpio-charger: use helper variable to access device info
  2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
  2018-01-17 20:31 ` [PATCH 1/5] power: supply: gpio-charger: Drop driver remove function Ladislav Michl
@ 2018-01-17 20:31 ` Ladislav Michl
  2018-01-17 20:32 ` [PATCH 3/5] power: supply: gpio-charger: generic gpio algo Ladislav Michl
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:31 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

Using explicit struct device variable makes code a bit more readable.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
 drivers/power/supply/gpio-charger.c | 42 ++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 9c008ef8cf70..8660a886162b 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -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;
 }
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] power: supply: gpio-charger: generic gpio algo
  2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
  2018-01-17 20:31 ` [PATCH 1/5] power: supply: gpio-charger: Drop driver remove function Ladislav Michl
  2018-01-17 20:31 ` [PATCH 2/5] power: supply: gpio-charger: use helper variable to access device info Ladislav Michl
@ 2018-01-17 20:32 ` Ladislav Michl
  2018-01-17 20:32 ` [PATCH 4/5] power: supply: gpio-charger: LTC3651 support Ladislav Michl
  2018-01-17 20:33 ` [PATCH 5/5] power: supply: gpio-charger: LM3658 support Ladislav Michl
  4 siblings, 0 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:32 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

Just a proof of concept...

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
 drivers/power/supply/gpio-charger.c | 323 ++++++++++++++++++++++++++----------
 1 file changed, 231 insertions(+), 92 deletions(-)

diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 8660a886162b..11ce5fab27d5 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -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;
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] power: supply: gpio-charger: LTC3651 support
  2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
                   ` (2 preceding siblings ...)
  2018-01-17 20:32 ` [PATCH 3/5] power: supply: gpio-charger: generic gpio algo Ladislav Michl
@ 2018-01-17 20:32 ` Ladislav Michl
  2018-01-17 20:33 ` [PATCH 5/5] power: supply: gpio-charger: LM3658 support Ladislav Michl
  4 siblings, 0 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:32 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

Just a proof of concept...

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
 drivers/power/supply/gpio-charger.c | 78 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 2 deletions(-)

diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 11ce5fab27d5..463e0abe975b 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -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 *) &ltc3651_cfg,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, gpio_charger_match);
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] power: supply: gpio-charger: LM3658 support
  2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
                   ` (3 preceding siblings ...)
  2018-01-17 20:32 ` [PATCH 4/5] power: supply: gpio-charger: LTC3651 support Ladislav Michl
@ 2018-01-17 20:33 ` Ladislav Michl
  4 siblings, 0 replies; 6+ messages in thread
From: Ladislav Michl @ 2018-01-17 20:33 UTC (permalink / raw)
  To: linux-pm; +Cc: Sebastian Reichel, Mike Looijmans

Just a proof of concept...

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
---
 drivers/power/supply/gpio-charger.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c
index 463e0abe975b..1628ac1e84d1 100644
--- a/drivers/power/supply/gpio-charger.c
+++ b/drivers/power/supply/gpio-charger.c
@@ -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 *) &ltc3651_cfg,
 	},
+	{
+		.compatible = "ti,lm3658",
+		.data = (void *) &lm3658_cfg,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, gpio_charger_match);
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-01-17 20:33 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-17 20:27 [PATCH 0/5] Generic GPIO connected chargers support Ladislav Michl
2018-01-17 20:31 ` [PATCH 1/5] power: supply: gpio-charger: Drop driver remove function Ladislav Michl
2018-01-17 20:31 ` [PATCH 2/5] power: supply: gpio-charger: use helper variable to access device info Ladislav Michl
2018-01-17 20:32 ` [PATCH 3/5] power: supply: gpio-charger: generic gpio algo Ladislav Michl
2018-01-17 20:32 ` [PATCH 4/5] power: supply: gpio-charger: LTC3651 support Ladislav Michl
2018-01-17 20:33 ` [PATCH 5/5] power: supply: gpio-charger: LM3658 support Ladislav Michl

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.