[PATCH 4/4] gpio: scmi: Add gpio_scmi driver

Michal Simek michal.simek at amd.com
Tue Feb 24 17:10:26 CET 2026



On 2/23/26 15:33, Dan Carpenter wrote:
> This provides gpio support over SCMI.  The device tree entry would look
> like this:
> 
>                  scmi_gpio1: gpio1 {
>                          compatible = "scmi,gpio";
>                          scmi,pinctrl = <&scmi_pinctrl 0 2>;
>                          pinctrl-names = "default";
>                          pinctrl-0 = <&pinmux1>;
>                          gpio-controller;
>                  };
> 
> The scmi,pinctrl phandle points to the function and the index within that
> function.  The pinctrl-0 phandle points to the initial pin configuration
> if necessary.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter at linaro.org>
> ---
>   drivers/gpio/Kconfig     |   6 ++
>   drivers/gpio/Makefile    |   1 +
>   drivers/gpio/gpio_scmi.c | 221 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 228 insertions(+)
>   create mode 100644 drivers/gpio/gpio_scmi.c
> 
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 60c5c54688e6..7d22c1f792d1 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -723,6 +723,12 @@ config SLG7XL45106_I2C_GPO
>   	   8-bit gpo expander, all gpo lines are controlled by writing
>   	   value into data register.
>   
> +config GPIO_SCMI
> +	bool "SCMI GPIO pinctrl driver"
> +	depends on DM_GPIO && PINCTRL_SCMI
> +	help
> +	   Support pinctrl GPIO over the SCMI interface.
> +
>   config ADP5585_GPIO
>   	bool "ADP5585 GPIO driver"
>   	depends on DM_GPIO && DM_I2C
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 910478c0c7a9..0003ed74be67 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -77,6 +77,7 @@ obj-$(CONFIG_SL28CPLD_GPIO)	+= sl28cpld-gpio.o
>   obj-$(CONFIG_ADP5588_GPIO)	+= adp5588_gpio.o
>   obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN)	+= zynqmp_gpio_modepin.o
>   obj-$(CONFIG_SLG7XL45106_I2C_GPO)	+= gpio_slg7xl45106.o
> +obj-$(CONFIG_GPIO_SCMI)		+= gpio_scmi.o
>   obj-$(CONFIG_$(PHASE_)ADP5585_GPIO)	+= adp5585_gpio.o
>   obj-$(CONFIG_RZG2L_GPIO)	+= rzg2l-gpio.o
>   obj-$(CONFIG_MPFS_GPIO)	+= mpfs_gpio.o
> diff --git a/drivers/gpio/gpio_scmi.c b/drivers/gpio/gpio_scmi.c
> new file mode 100644
> index 000000000000..a859ad610587
> --- /dev/null
> +++ b/drivers/gpio/gpio_scmi.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright 2026 Linaro Ltd.
> + */
> +
> +#include <asm/gpio.h>
> +#include <dm.h>
> +#include <dm/device_compat.h>
> +#include <scmi_protocols.h>
> +
> +struct scmi_gpio_priv {
> +	struct udevice *pin_dev;
> +	char *bank_name;
> +	u32 num_pins;
> +	u16 *pins;
> +};
> +
> +static int scmi_gpio_request(struct udevice *dev, unsigned int offset, const char *label)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	int pin;
> +	int ret;
> +
> +	if (offset >= priv->num_pins)
> +		return -EINVAL;
> +	pin = priv->pins[offset];
> +
> +	ret = scmi_pinctrl_request(priv->pin_dev, SCMI_PIN, pin);
> +	if (ret == -EOPNOTSUPP)
> +		ret = 0;
> +	if (ret)
> +		dev_err(dev, "%s(): request failed: %d\n", __func__, ret);
> +	return ret;
> +}
> +
> +static int scmi_gpio_rfree(struct udevice *dev, unsigned int offset)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	int pin;
> +	int ret;
> +
> +	if (offset >= priv->num_pins)
> +		return -EINVAL;
> +	pin = priv->pins[offset];
> +
> +	ret = scmi_pinctrl_release(priv->pin_dev, SCMI_PIN, pin);
> +	if (ret == -EOPNOTSUPP)
> +		ret = 0;
> +	if (ret)
> +		dev_err(dev, "%s(): release failed: %d\n", __func__, ret);
> +	return ret;
> +}
> +
> +static int scmi_gpio_set_flags(struct udevice *dev, unsigned int offset, ulong flags)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	const int MAX_FLAGS = 10;
> +	u32 configs[MAX_FLAGS * 2];
> +	int cnt = 0;
> +	u32 pin;
> +
> +	if (offset >= priv->num_pins)
> +		return -EINVAL;
> +	pin = priv->pins[offset];
> +
> +	if (flags & GPIOD_IS_OUT) {
> +		configs[cnt++] = SCMI_PIN_OUTPUT_MODE;
> +		configs[cnt++] = 1;
> +		configs[cnt++] = SCMI_PIN_OUTPUT_VALUE;
> +		if (flags & GPIOD_IS_OUT_ACTIVE)
> +			configs[cnt++] = 1;
> +		else
> +			configs[cnt++] = 0;
> +	}
> +	if (flags & GPIOD_IS_IN) {
> +		configs[cnt++] = SCMI_PIN_INPUT_MODE;
> +		configs[cnt++] = 1;
> +	}
> +	if (flags & GPIOD_OPEN_DRAIN) {
> +		configs[cnt++] = SCMI_PIN_DRIVE_OPEN_DRAIN;
> +		configs[cnt++] = 1;
> +	}
> +	if (flags & GPIOD_OPEN_SOURCE) {
> +		configs[cnt++] = SCMI_PIN_DRIVE_OPEN_SOURCE;
> +		configs[cnt++] = 1;
> +	}
> +	if (flags & GPIOD_PULL_UP) {
> +		configs[cnt++] = SCMI_PIN_BIAS_PULL_UP;
> +		configs[cnt++] = 1;
> +	}
> +	if (flags & GPIOD_PULL_DOWN) {
> +		configs[cnt++] = SCMI_PIN_BIAS_PULL_DOWN;
> +		configs[cnt++] = 1;
> +	}
> +	/* TODO: handle GPIOD_ACTIVE_LOW and GPIOD_IS_AF flags */
> +
> +	return scmi_pinctrl_settings_configure(priv->pin_dev, SCMI_PIN, pin,
> +					       cnt / 2, &configs[0]);
> +}
> +
> +static int scmi_gpio_get_value(struct udevice *dev, unsigned int offset)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	u32 value;
> +	int pin;
> +	int ret;
> +
> +	if (offset >= priv->num_pins)
> +		return -EINVAL;
> +	pin = priv->pins[offset];
> +
> +	ret = scmi_pinctrl_settings_get_one(priv->pin_dev, SCMI_PIN, pin,
> +					    SCMI_PIN_INPUT_VALUE, &value);
> +	if (ret) {
> +		dev_err(dev, "settings_get_one() failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return value;
> +}
> +
> +static int scmi_gpio_get_function(struct udevice *dev, unsigned int offset)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	u32 value;
> +	int pin;
> +	int ret;
> +
> +	if (offset >= priv->num_pins)
> +		return -EINVAL;
> +	pin = priv->pins[offset];
> +
> +	ret = scmi_pinctrl_settings_get_one(priv->pin_dev, SCMI_PIN, pin,
> +					    SCMI_PIN_INPUT_MODE,
> +					    &value);
> +	if (ret) {
> +		dev_err(dev, "settings_get() failed %d\n", ret);
> +		return ret;
> +	}
> +
> +	if (value)
> +		return GPIOF_INPUT;
> +	return GPIOF_OUTPUT;
> +}
> +
> +static const struct dm_gpio_ops scmi_gpio_ops = {
> +	.request	= scmi_gpio_request,
> +	.rfree		= scmi_gpio_rfree,
> +	.set_flags	= scmi_gpio_set_flags,
> +	.get_value	= scmi_gpio_get_value,
> +	.get_function	= scmi_gpio_get_function,
> +};
> +
> +static int get_pins(struct udevice *dev, u32 function, u32 index, char **f_name,
> +		    u16 **pins, u32 *npins)
> +{
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	struct pinctrl_scmi_priv *pin_info = dev_get_priv(priv->pin_dev);
> +	u32 group;
> +
> +	if (function >= pin_info->num_functions)
> +		return -EINVAL;
> +	if (index >= pin_info->function_info[function].num_groups)
> +		return -EINVAL;
> +	group = pin_info->function_info[function].groups[index];
> +	if (group >= pin_info->num_groups)
> +		return -EINVAL;
> +
> +	*f_name = pin_info->function_info[function].name;
> +	*pins = pin_info->group_info[group].pins;
> +	*npins = pin_info->group_info[group].num_pins;
> +
> +	return 0;
> +}
> +
> +static int scmi_gpio_probe(struct udevice *dev)
> +{
> +	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
> +	struct scmi_gpio_priv *priv = dev_get_priv(dev);
> +	struct ofnode_phandle_args args;
> +	int ret;
> +
> +	ret = dev_read_phandle_with_args(dev, "scmi,pinctrl", NULL, 2, 0, &args);
> +	if (ret) {
> +		dev_err(dev, "failed to read scmi,pinctrl phandle: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL, args.node, &priv->pin_dev);
> +	if (ret) {
> +		dev_err(dev, "failed to find pinctrl device: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = get_pins(dev, args.args[0], args.args[1], &priv->bank_name,
> +		       &priv->pins, &priv->num_pins);
> +	if (ret) {
> +		dev_err(dev, "failed to get pins for %u %u\n", args.args[0], args.args[1]);
> +		return ret;
> +	}
> +
> +	uc_priv->bank_name = priv->bank_name;
> +	uc_priv->gpio_count = priv->num_pins;
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id scmi_gpio_match[] = {
> +	{ .compatible = "scmi,gpio" },


Can you point me the dt binding document?

I am aware about this one and grep is not returning me anything from linux-next too

https://lore.kernel.org/all/20231002021602.260100-1-takahiro.akashi@linaro.org/

Thanks,
Michal


More information about the U-Boot mailing list