]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gpio: gpio-by-pinctrl: add pinctrl based generic GPIO driver
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Mon, 23 Mar 2026 19:01:47 +0000 (22:01 +0300)
committerLinus Walleij <linusw@kernel.org>
Tue, 24 Mar 2026 12:50:31 +0000 (13:50 +0100)
The ARM SCMI pinctrl protocol allows GPIO access.  Instead of creating
a new SCMI GPIO driver, this driver is a generic GPIO driver that uses
standard pinctrl interfaces.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-by-pinctrl.c [new file with mode: 0644]

index b45fb799e36c19794e56bbac7539250c09beaeb7..c631ecb01e070ef568b974341daba8dfaa790c12 100644 (file)
@@ -246,6 +246,19 @@ config GPIO_BRCMSTB
        help
          Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
 
+config GPIO_BY_PINCTRL
+       tristate "GPIO support based on a pure pin control backend"
+       depends on GPIOLIB
+       help
+         Support for generic GPIO handling based on top of pin control.
+         Traditionally, firmware creates a GPIO interface or a pin
+         controller interface and we have a driver to support it.  But
+         in SCMI, the pin control interface is generic and we can
+         create a simple GPIO device based on the pin control interface
+         without doing anything custom.
+
+         This driver used to do GPIO over the ARM SCMI protocol.
+
 config GPIO_CADENCE
        tristate "Cadence GPIO support"
        depends on OF_GPIO
index c05f7d795c434cd002b3d6b58a98718429f51cc7..20d4a57afdaa6db0d01cd7e107a2e22004641ecb 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_GPIO_BD9571MWV)          += gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BLZP1600)            += gpio-blzp1600.o
 obj-$(CONFIG_GPIO_BRCMSTB)             += gpio-brcmstb.o
 obj-$(CONFIG_GPIO_BT8XX)               += gpio-bt8xx.o
+obj-$(CONFIG_GPIO_BY_PINCTRL)          += gpio-by-pinctrl.o
 obj-$(CONFIG_GPIO_CADENCE)             += gpio-cadence.o
 obj-$(CONFIG_GPIO_CGBC)                        += gpio-cgbc.o
 obj-$(CONFIG_GPIO_CLPS711X)            += gpio-clps711x.o
diff --git a/drivers/gpio/gpio-by-pinctrl.c b/drivers/gpio/gpio-by-pinctrl.c
new file mode 100644 (file)
index 0000000..ddfdc47
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2026 Linaro Inc.
+//   Author: AKASHI takahiro <takahiro.akashi@linaro.org>
+
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include "gpiolib.h"
+
+static int pin_control_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       unsigned long config;
+       int ret;
+
+       config = PIN_CONFIG_OUTPUT_ENABLE;
+       ret = pinctrl_gpio_get_config(gc, offset, &config);
+       if (ret)
+               return ret;
+       if (config)
+               return GPIO_LINE_DIRECTION_OUT;
+
+       return GPIO_LINE_DIRECTION_IN;
+}
+
+static int pin_control_gpio_direction_output(struct gpio_chip *chip,
+                                            unsigned int offset, int val)
+{
+       return pinctrl_gpio_direction_output(chip, offset);
+}
+
+static int pin_control_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       unsigned long config;
+       int ret;
+
+       config = PIN_CONFIG_LEVEL;
+       ret = pinctrl_gpio_get_config(chip, offset, &config);
+       if (ret)
+               return ret;
+
+       return !!config;
+}
+
+static int pin_control_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                               int val)
+{
+       unsigned long config;
+
+       config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val);
+       return pinctrl_gpio_set_config(chip, offset, config);
+}
+
+static int pin_control_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct gpio_chip *chip;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->label = dev_name(dev);
+       chip->parent = dev;
+       chip->base = -1;
+
+       chip->request = gpiochip_generic_request;
+       chip->free = gpiochip_generic_free;
+       chip->get_direction = pin_control_gpio_get_direction;
+       chip->direction_input = pinctrl_gpio_direction_input;
+       chip->direction_output = pin_control_gpio_direction_output;
+       chip->get = pin_control_gpio_get;
+       chip->set = pin_control_gpio_set;
+       chip->set_config = gpiochip_generic_config;
+
+       return devm_gpiochip_add_data(dev, chip, NULL);
+}
+
+static const struct of_device_id pin_control_gpio_match[] = {
+       { .compatible = "scmi-pinctrl-gpio" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pin_control_gpio_match);
+
+static struct platform_driver pin_control_gpio_driver = {
+       .probe = pin_control_gpio_probe,
+       .driver = {
+               .name = "pin-control-gpio",
+               .of_match_table = pin_control_gpio_match,
+       },
+};
+module_platform_driver(pin_control_gpio_driver);
+
+MODULE_AUTHOR("AKASHI Takahiro <takahiro.akashi@linaro.org>");
+MODULE_DESCRIPTION("Pinctrl based GPIO driver");
+MODULE_LICENSE("GPL");