linux-pm.vger.kernel.org archive mirror
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).