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(®s->afsla); > + if (alt & NMK_ALT_A) > + val |= mask; > + else > + val &= ~mask; > + writel(val, ®s->afsla); > + > + val = readl(®s->afslb); > + if (alt & NMK_ALT_B) > + val |= mask; > + else > + val &= ~mask; > + writel(val, ®s->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, ®s->dirc); > + if (val == INPUT_NOPULL) { > + setbits_le32(®s->pdis, mask); > + } else { > + clrbits_le32(®s->pdis, mask); > + if (val == INPUT_PULLUP) > + writel(mask, ®s->dats); > + else if (val == INPUT_PULLDOWN) > + writel(mask, ®s->datc); > + else > + return -EINVAL; > + } > + } > + > + if (!ofnode_read_u32(node, "ste,output", &val)) { > + if (val == OUTPUT_HIGH) > + writel(mask, ®s->dats); > + else if (val == OUTPUT_LOW) > + writel(mask, ®s->datc); > + else > + return -EINVAL; > + writel(mask, ®s->dirs); > + } > + > + if (!ofnode_read_u32(node, "ste,lowemi", &val)) { > + if (val) > + setbits_le32(®s->lowemi, mask); > + else > + clrbits_le32(®s->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 >