[RFC PATCH] gpio-button-hotplug: gpio descriptor API update

Christian Lamparter chunkeey at gmail.com
Thu Aug 5 06:54:03 PDT 2021


This driver still uses the Legacy GPIO Subsystem gpio_ API.
While it does work fine, it won't supports the new GPIO
LOOKUP tables that have been popping up upstream since v5.0.

For APU2 users > linux 5.4:
Please test if this fixes your reset button.

(DT devices needs to be re-tested as well)

Reported-by: Chris Blake <chrisrblake93 at gmail.com>
Signed-off-by: Christian Lamparter <chunkeey at gmail.com>
---
 .../src/gpio-button-hotplug.c                 | 83 ++++++++-----------
 1 file changed, 35 insertions(+), 48 deletions(-)

diff --git a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
index 9575c6245b..bc151645e3 100644
--- a/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
+++ b/package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c
@@ -242,11 +242,11 @@ static int gpio_button_get_value(struct gpio_keys_button_data *bdata)
 	int val;
 
 	if (bdata->can_sleep)
-		val = !!gpio_get_value_cansleep(bdata->b->gpio);
+		val = !!gpiod_get_value_cansleep(bdata->gpiod);
 	else
-		val = !!gpio_get_value(bdata->b->gpio);
+		val = !!gpiod_get_value(bdata->gpiod);
 
-	return val ^ bdata->b->active_low;
+	return val;
 }
 
 static void gpio_keys_handle_button(struct gpio_keys_button_data *bdata)
@@ -391,35 +391,15 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 	of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
 
 	for_each_child_of_node(node, pp) {
-		enum of_gpio_flags flags;
-
-		if (!of_find_property(pp, "gpios", NULL)) {
-			pdata->nbuttons--;
-			dev_warn(dev, "Found button without gpios\n");
-			continue;
-		}
-
 		button = (struct gpio_keys_button *)(&pdata->buttons[i++]);
 
-		button->irq = irq_of_parse_and_map(pp, 0);
+		button->gpio = -ENOENT; /* gets filled in later */
 
-		button->gpio = of_get_gpio_flags(pp, 0, &flags);
-		if (button->gpio < 0) {
-			error = button->gpio;
-			if (error != -ENOENT) {
-				if (error != -EPROBE_DEFER)
-					dev_err(dev,
-						"Failed to get gpio flags, error: %d\n",
-						error);
-				return ERR_PTR(error);
-			}
-		} else {
-			button->active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
-		}
+		button->irq = irq_of_parse_and_map(pp, 0);
 
 		if (of_property_read_u32(pp, "linux,code", &button->code)) {
-			dev_err(dev, "Button without keycode: 0x%x\n",
-				button->gpio);
+			dev_err(dev, "Button node '%s' without keycode\n",
+				pp->full_name);
 			error = -EINVAL;
 			goto err_out;
 		}
@@ -514,7 +494,6 @@ static int gpio_keys_button_probe(struct platform_device *pdev,
 	for (i = 0; i < pdata->nbuttons; i++) {
 		struct gpio_keys_button *button = &buttons[i];
 		struct gpio_keys_button_data *bdata = &bdev->data[i];
-		unsigned int gpio = button->gpio;
 
 		if (button->wakeup) {
 			dev_err(dev, "does not support wakeup\n");
@@ -534,26 +513,37 @@ static int gpio_keys_button_probe(struct platform_device *pdev,
 			continue;
 		}
 
-		error = devm_gpio_request(dev, gpio,
+		bdata->gpiod = devm_gpiod_get_index(dev,
+			button->desc ? button->desc : DRV_NAME, i, GPIOD_IN);
+		if (IS_ERR(bdata->gpiod)) {
+			unsigned gpio;
+
+			error = PTR_ERR(bdata->gpiod);
+
+			/*
+			 * In case of -ENOENT, there still hope that we might
+			 * just be using legacy platform data, which has the
+			 * button->gpio filled in.
+			 */
+			if (error != -ENOENT || !gpio_is_valid(button->gpio))
+				return error;
+
+			gpio = button->gpio;
+			error = devm_gpio_request_one(dev, gpio, GPIOF_IN |
+				     (button->active_low ? GPIOF_ACTIVE_LOW : 0),
 				     button->desc ? button->desc : DRV_NAME);
-		if (error) {
-			dev_err(dev, "unable to claim gpio %u, err=%d\n",
-				gpio, error);
-			return error;
-		}
-		bdata->gpiod = gpio_to_desc(gpio);
-		if (!bdata->gpiod)
-			return -EINVAL;
+			if (error) {
+				dev_err(dev, "unable to claim gpio %u, err=%d\n",
+					gpio, error);
+				return error;
+			}
 
-		error = gpio_direction_input(gpio);
-		if (error) {
-			dev_err(dev,
-				"unable to set direction on gpio %u, err=%d\n",
-				gpio, error);
-			return error;
+			bdata->gpiod = gpio_to_desc(gpio);
+			if (!bdata->gpiod)
+				return -EINVAL;
 		}
 
-		bdata->can_sleep = gpio_cansleep(gpio);
+		bdata->can_sleep = gpiod_cansleep(bdata->gpiod);
 		bdata->last_state = -1; /* Unknown state on boot */
 
 		if (bdev->polled) {
@@ -608,11 +598,8 @@ static int gpio_keys_probe(struct platform_device *pdev)
 
 		INIT_DELAYED_WORK(&bdata->work, gpio_keys_irq_work_func);
 
-		if (!bdata->gpiod)
-			continue;
-
 		if (!button->irq) {
-			bdata->irq = gpio_to_irq(button->gpio);
+			bdata->irq = gpiod_to_irq(bdata->gpiod);
 
 			if (bdata->irq < 0) {
 				dev_err(&pdev->dev, "failed to get irq for gpio:%d\n",
-- 
2.32.0




More information about the openwrt-devel mailing list