Re: [PATCH v5 01/13] pinctrl: Add compact Nomadik pin controller

Stephan Gerhold <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
On Sun, Aug 23, 2026 at 10:39:20PM +0200, Linus Walleij wrote:
> Add the minimal pin control support needed to consume default states from
> the upstream DB8500 device trees. Resolve the nine Nomadik GPIO banks
> through nomadik-gpio-chips and apply the mux, direction, value, pull and
> low-EMI settings directly to their registers.
> 
> Only the DB8500 binding and default-state configuration needed by
> U-Boot are supported. There is no GPIO ownership or sleep-state
> handling.
> 
> Signed-off-by: Linus Walleij <[email protected]>

Reviewed-by: Stephan Gerhold <[email protected]>

Thanks!

> ---
>  MAINTAINERS                       |   1 +
>  arch/arm/Kconfig                  |   2 +
>  drivers/pinctrl/Kconfig           |   7 ++
>  drivers/pinctrl/Makefile          |   1 +
>  drivers/pinctrl/pinctrl-nomadik.c | 230 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 241 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index eb48eea55c5a..a5d6b5be29dc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -787,6 +787,7 @@ S:	Maintained
>  F:	arch/arm/dts/ste-*
>  F:	arch/arm/mach-u8500/
>  F:	drivers/gpio/nmk_gpio.c
> +F:	drivers/pinctrl/pinctrl-nomadik.c
>  F:	drivers/phy/phy-ab8500-usb.c
>  F:	drivers/power/pmic/ab8500.c
>  F:	drivers/timer/nomadik-mtu-timer.c
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 1b474a346bf2..5b02ff18bd0e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1278,6 +1278,8 @@ config ARCH_U8500
>  	imply DM_RTC
>  	imply NOMADIK_GPIO
>  	imply NOMADIK_MTU_TIMER
> +	imply PINCTRL
> +	imply PINCTRL_NOMADIK
>  	imply PHY
>  	imply PL01X_SERIAL
>  	imply PMIC_AB8500
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index fd30aaeeaa89..04785a927fec 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -75,6 +75,13 @@ config PINCONF_RECURSIVE
>  	  configuration; you can save memory footprint when this feature is
>  	  no needed.
>  
> +config PINCTRL_NOMADIK
> +	bool "Nomadik pin control driver"
> +	depends on PINCTRL_FULL
> +	help
> +	  Enable pin multiplexing and configuration support for the Nomadik
> +	  GPIO blocks in the ST-Ericsson DB8500.
> +
>  config SPL_PINCTRL
>  	bool "Support pin controllers in SPL"
>  	depends on SPL && SPL_DM
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index 91149796bb5f..23219626e392 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -25,6 +25,7 @@ obj-$(CONFIG_PINCTRL_K210)		+= pinctrl-k210.o
>  obj-$(CONFIG_PINCTRL_MESON)		+= meson/
>  obj-$(CONFIG_PINCTRL_MSCC)		+= mscc/
>  obj-$(CONFIG_PINCTRL_MTK)		+= mediatek/
> +obj-$(CONFIG_PINCTRL_NOMADIK)		+= pinctrl-nomadik.o
>  obj-$(CONFIG_PINCTRL_PIC32)		+= pinctrl_pic32.o
>  obj-$(CONFIG_PINCTRL_QCOM)		+= qcom/
>  obj-$(CONFIG_PINCTRL_QE)		+= pinctrl-qe-io.o
> diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
> new file mode 100644
> index 000000000000..12d032226608
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-nomadik.c
> @@ -0,0 +1,230 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (C) 2026 Linus Walleij <[email protected]> */
> +
> +#include <dm.h>
> +#include <dm/pinctrl.h>
> +#include <dt-bindings/pinctrl/nomadik.h>
> +#include <vsprintf.h>
> +#include <asm/io.h>
> +
> +#define NMK_GPIO_BANKS		9
> +#define NMK_GPIO_PER_BANK	32
> +
> +struct nmk_gpio_regs {
> +	u32 dat;
> +	u32 dats;
> +	u32 datc;
> +	u32 pdis;
> +	u32 dir;
> +	u32 dirs;
> +	u32 dirc;
> +	u32 slpm;
> +	u32 afsla;
> +	u32 afslb;
> +	u32 lowemi;
> +};
> +
> +struct nmk_pinctrl_priv {
> +	struct nmk_gpio_regs *bank[NMK_GPIO_BANKS];
> +};
> +
> +enum nmk_alt {
> +	NMK_ALT_GPIO,
> +	NMK_ALT_A,
> +	NMK_ALT_B,
> +	NMK_ALT_C,
> +};
> +
> +static int nmk_pinctrl_parse_pin(const char *name, unsigned int *pin)
> +{
> +	char *end;
> +
> +	if (strncmp(name, "GPIO", 4))
> +		return -EINVAL;
> +
> +	*pin = dectoul(name + 4, &end);
> +	if (end == name + 4 || *end != '_' ||
> +	    *pin >= NMK_GPIO_BANKS * NMK_GPIO_PER_BANK)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static struct nmk_gpio_regs *
> +nmk_pinctrl_bank(struct udevice *dev, unsigned int pin)
> +{
> +	struct nmk_pinctrl_priv *priv = dev_get_priv(dev);
> +
> +	return priv->bank[pin / NMK_GPIO_PER_BANK];
> +}
> +
> +static void nmk_pinctrl_set_mux(struct udevice *dev, unsigned int pin,
> +				unsigned int alt)
> +{
> +	struct nmk_gpio_regs *regs = nmk_pinctrl_bank(dev, pin);
> +	u32 mask = BIT(pin % NMK_GPIO_PER_BANK);
> +	u32 val;
> +
> +	val = readl(&regs->afsla);
> +	if (alt & NMK_ALT_A)
> +		val |= mask;
> +	else
> +		val &= ~mask;
> +	writel(val, &regs->afsla);
> +
> +	val = readl(&regs->afslb);
> +	if (alt & NMK_ALT_B)
> +		val |= mask;
> +	else
> +		val &= ~mask;
> +	writel(val, &regs->afslb);
> +}
> +
> +static int nmk_pinctrl_set_config(struct udevice *dev, ofnode node,
> +				  unsigned int pin)
> +{
> +	struct nmk_gpio_regs *regs = nmk_pinctrl_bank(dev, pin);
> +	u32 mask = BIT(pin % NMK_GPIO_PER_BANK);
> +	u32 val;
> +
> +	if (!ofnode_read_u32(node, "ste,input", &val)) {
> +		writel(mask, &regs->dirc);
> +		if (val == INPUT_NOPULL) {
> +			setbits_le32(&regs->pdis, mask);
> +		} else {
> +			clrbits_le32(&regs->pdis, mask);
> +			if (val == INPUT_PULLUP)
> +				writel(mask, &regs->dats);
> +			else if (val == INPUT_PULLDOWN)
> +				writel(mask, &regs->datc);
> +			else
> +				return -EINVAL;
> +		}
> +	}
> +
> +	if (!ofnode_read_u32(node, "ste,output", &val)) {
> +		if (val == OUTPUT_HIGH)
> +			writel(mask, &regs->dats);
> +		else if (val == OUTPUT_LOW)
> +			writel(mask, &regs->datc);
> +		else
> +			return -EINVAL;
> +		writel(mask, &regs->dirs);
> +	}
> +
> +	if (!ofnode_read_u32(node, "ste,lowemi", &val)) {
> +		if (val)
> +			setbits_le32(&regs->lowemi, mask);
> +		else
> +			clrbits_le32(&regs->lowemi, mask);
> +	}
> +
> +	return 0;
> +}
> +
> +static int nmk_pinctrl_get_alt(ofnode node, unsigned int *alt)
> +{
> +	const char *group;
> +
> +	if (ofnode_read_string_index(node, "groups", 0, &group))
> +		return -EINVAL;
> +
> +	if (strstr(group, "_a_"))
> +		*alt = NMK_ALT_A;
> +	else if (strstr(group, "_b_"))
> +		*alt = NMK_ALT_B;
> +	else if (strstr(group, "_c_"))
> +		*alt = NMK_ALT_C;
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int nmk_pinctrl_set_state(struct udevice *dev, struct udevice *config)
> +{
> +	unsigned int alt = NMK_ALT_GPIO;
> +	ofnode node;
> +	int count;
> +	int ret;
> +	int i;
> +
> +	dev_for_each_subnode(node, config) {
> +		if (ofnode_read_string(node, "function")) {
> +			ret = nmk_pinctrl_get_alt(node, &alt);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	dev_for_each_subnode(node, config) {
> +		ofnode cfg;
> +
> +		count = ofnode_read_string_count(node, "pins");
> +		if (count < 0)
> +			continue;
> +
> +		cfg = ofnode_parse_phandle(node, "ste,config", 0);
> +		if (!ofnode_valid(cfg))
> +			cfg = node;
> +
> +		for (i = 0; i < count; i++) {
> +			const char *name;
> +			unsigned int pin;
> +
> +			ret = ofnode_read_string_index(node, "pins", i, &name);
> +			if (ret)
> +				return ret;
> +			ret = nmk_pinctrl_parse_pin(name, &pin);
> +			if (ret)
> +				return ret;
> +			ret = nmk_pinctrl_set_config(dev, cfg, pin);
> +			if (ret)
> +				return ret;
> +			nmk_pinctrl_set_mux(dev, pin, alt);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int nmk_pinctrl_probe(struct udevice *dev)
> +{
> +	struct nmk_pinctrl_priv *priv = dev_get_priv(dev);
> +	struct ofnode_phandle_args args;
> +	fdt_addr_t addr;
> +	int ret;
> +	int i;
> +
> +	for (i = 0; i < NMK_GPIO_BANKS; i++) {
> +		ret = dev_read_phandle_with_args(dev, "nomadik-gpio-chips",
> +						 NULL, 0, i, &args);
> +		if (ret)
> +			return ret;
> +
> +		addr = ofnode_get_addr(args.node);
> +		if (addr == FDT_ADDR_T_NONE)
> +			return -EINVAL;
> +		priv->bank[i] = (struct nmk_gpio_regs *)addr;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct pinctrl_ops nmk_pinctrl_ops = {
> +	.set_state = nmk_pinctrl_set_state,
> +};
> +
> +static const struct udevice_id nmk_pinctrl_ids[] = {
> +	{ .compatible = "stericsson,db8500-pinctrl" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(pinctrl_nomadik) = {
> +	.name = "pinctrl_nomadik",
> +	.id = UCLASS_PINCTRL,
> +	.of_match = nmk_pinctrl_ids,
> +	.probe = nmk_pinctrl_probe,
> +	.priv_auto = sizeof(struct nmk_pinctrl_priv),
> +	.ops = &nmk_pinctrl_ops,
> +};
> 
> -- 
> 2.55.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.