diff options
| author | Mark Brown <broonie@kernel.org> | 2026-07-06 15:08:52 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-07-06 15:08:52 +0100 |
| commit | 24d5bd9bd8539a2488ac52ec53c83c2fcd6841ce (patch) | |
| tree | e7a5183f171fcdbf1fbd11e6d74f1cd239be4a08 | |
| parent | c3e8e6a6abe0f480dab7c5ea1c41c015b512dd3f (diff) | |
| parent | 94cb9e8f270797e489633cfa53d2d44afecb8bef (diff) | |
| download | linux-next-24d5bd9bd8539a2488ac52ec53c83c2fcd6841ce.tar.gz linux-next-24d5bd9bd8539a2488ac52ec53c83c2fcd6841ce.zip | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml | 1 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml | 90 | ||||
| -rw-r--r-- | MAINTAINERS | 7 | ||||
| -rw-r--r-- | drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c | 6 | ||||
| -rw-r--r-- | drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 | ||||
| -rw-r--r-- | drivers/pinctrl/freescale/pinctrl-imx1-core.c | 7 | ||||
| -rw-r--r-- | drivers/pinctrl/nxp/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/pinctrl/nxp/pinctrl-s32.h | 35 | ||||
| -rw-r--r-- | drivers/pinctrl/nxp/pinctrl-s32cc.c | 748 | ||||
| -rw-r--r-- | drivers/pinctrl/nxp/pinctrl-s32g2.c | 47 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-tb10x.c | 2 |
11 files changed, 846 insertions, 101 deletions
diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml index 76944fd14e2c..fe7cef4fef6a 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml @@ -356,6 +356,7 @@ patternProperties: - I3C8 - I3C9 - JTAGM1 + - JTAGM1TRST - LPC0 - LPC1 - LTPI diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml index a24286e4def6..36f2393fa406 100644 --- a/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -# Copyright 2022 NXP +# Copyright 2022, 2026 NXP %YAML 1.2 --- $id: http://devicetree.org/schemas/pinctrl/nxp,s32g2-siul2-pinctrl.yaml# @@ -17,8 +17,10 @@ description: | SIUL2_0 @ 0x4009c000 SIUL2_1 @ 0x44010000 - Every SIUL2 region has multiple register types, and here only MSCR and - IMCR registers need to be revealed for kernel to configure pinmux. + Every SIUL2 region has multiple register types. MSCR and IMCR registers + need to be revealed for kernel to configure pinmux. PGPDO and PGPDI + registers are used for GPIO output/input operations. EIRQ registers + are used for external interrupt configuration. Please note that some register indexes are reserved in S32G2, such as MSCR102-MSCR111, MSCR123-MSCR143, IMCR84-IMCR118 and IMCR398-IMCR429. @@ -29,14 +31,22 @@ properties: - nxp,s32g2-siul2-pinctrl reg: + minItems: 6 description: | - A list of MSCR/IMCR register regions to be reserved. + A list of MSCR/IMCR/PGPDO/PGPDI/EIRQ register regions to be reserved. - MSCR (Multiplexed Signal Configuration Register) An MSCR register can configure the associated pin as either a GPIO pin or a function output pin depends on the selected signal source. - IMCR (Input Multiplexed Signal Configuration Register) An IMCR register can configure the associated pin as function input pin depends on the selected signal source. + - PGPDO (Parallel GPIO Pad Data Out Register) + A PGPDO register is used to set the output value of a GPIO pin. + - PGPDI (Parallel GPIO Pad Data In Register) + A PGPDI register is used to read the input value of a GPIO pin. + - EIRQ (External Interrupt Request) + EIRQ registers are used to configure and manage external interrupts. + items: - description: MSCR registers group 0 in SIUL2_0 - description: MSCR registers group 1 in SIUL2_1 @@ -44,6 +54,28 @@ properties: - description: IMCR registers group 0 in SIUL2_0 - description: IMCR registers group 1 in SIUL2_1 - description: IMCR registers group 2 in SIUL2_1 + - description: PGPDO registers in SIUL2_0 + - description: PGPDI registers in SIUL2_0 + - description: PGPDO registers in SIUL2_1 + - description: PGPDI registers in SIUL2_1 + - description: EIRQ registers in SIUL2_1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + gpio-ranges: + minItems: 1 + maxItems: 4 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + maxItems: 1 patternProperties: '-pins$': @@ -86,11 +118,38 @@ required: - compatible - reg +oneOf: + - description: Legacy pinctrl-only node + properties: + reg: + maxItems: 6 + + gpio-controller: false + "#gpio-cells": false + gpio-ranges: false + interrupt-controller: false + "#interrupt-cells": false + interrupts: false + + - description: Pinctrl node with GPIO and external interrupt support + required: + - gpio-controller + - "#gpio-cells" + - gpio-ranges + - interrupt-controller + - "#interrupt-cells" + - interrupts + properties: + reg: + minItems: 11 + additionalProperties: false examples: - | - pinctrl@4009c240 { + #include <dt-bindings/interrupt-controller/arm-gic.h> + + pinctrl: pinctrl@4009c240 { compatible = "nxp,s32g2-siul2-pinctrl"; /* MSCR0-MSCR101 registers on siul2_0 */ @@ -104,7 +163,26 @@ examples: /* IMCR119-IMCR397 registers on siul2_1 */ <0x44010c1c 0x45c>, /* IMCR430-IMCR495 registers on siul2_1 */ - <0x440110f8 0x108>; + <0x440110f8 0x108>, + /* PGPDO registers on siul2_0 */ + <0x4009d700 0x10>, + /* PGPDI registers on siul2_0 */ + <0x4009d740 0x10>, + /* PGPDO registers on siul2_1 */ + <0x44011700 0x18>, + /* PGPDI registers on siul2_1 */ + <0x44011740 0x18>, + /* EIRQ registers on siul2_1 */ + <0x44010010 0x34>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 102>, + <&pinctrl 112 112 79>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>; llce-can0-pins { llce-can0-grp0 { diff --git a/MAINTAINERS b/MAINTAINERS index 878b91dde848..52b6c2e1d6a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22380,6 +22380,13 @@ L: linux-arm-msm@vger.kernel.org S: Maintained F: drivers/firmware/qcom/qcom_qseecom_uefisecapp.c +QUALCOMM PINCTRL DRIVERS +M: Bartosz Golaszewski <brgl@kernel.org> +L: linux-arm-msm@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/pinctrl/qcom,*.yaml +F: drivers/pinctrl/qcom/ + QUALCOMM RMNET DRIVER M: Subash Abhinov Kasiviswanathan <subash.a.kasiviswanathan@oss.qualcomm.com> M: Sean Tranchetti <sean.tranchetti@oss.qualcomm.com> diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c index 50027d69c342..f8b4066699ce 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c @@ -1018,7 +1018,8 @@ PIN_GROUP(I3C6, AA22, AB20); PIN_GROUP(I3C7, AF18, AE19); PIN_GROUP(I3C8, AD20, AC20); PIN_GROUP(I3C9, AA21, AB21); -PIN_GROUP(JTAGM1, D12, F10, E11, F11, F13); +PIN_GROUP(JTAGM1, F10, E11, F11, F13); +PIN_GROUP(JTAGM1TRST, D12); PIN_GROUP(LPC0, AF26, AF25, B16, D14, B15, B14, C17, B13, E14, C15); PIN_GROUP(LPC1, C16, C14, C11, D9, F14, D10, C12, C13, AE16, AE17); PIN_GROUP(LTPI, U25, U26, Y26, AA24); @@ -1263,6 +1264,7 @@ static const struct pingroup aspeed_g7_soc1_groups[] = { GROUP(I3C8), GROUP(I3C9), GROUP(JTAGM1), + GROUP(JTAGM1TRST), GROUP(LPC0), GROUP(LPC1), GROUP(LTPI), @@ -1528,7 +1530,7 @@ static const struct aspeed_g7_soc1_function aspeed_g7_soc1_functions[] = { FUNC(I3C7, (1), "I3C7"), FUNC(I3C8, (1), "I3C8"), FUNC(I3C9, (1), "I3C9"), - FUNC(JTAGM1, (1), "JTAGM1"), + FUNC(JTAGM1, (1, 1), "JTAGM1", "JTAGM1TRST"), FUNC(LPC0, (2), "LPC0"), FUNC(LPC1, (2), "LPC1"), FUNC(LTPI, (2), "LTPI"), diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index e7b35019a5a7..725e880ae086 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -1350,7 +1350,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) pc->pctl_desc = *pdata->pctl_desc; pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); if (IS_ERR(pc->pctl_dev)) { - gpiochip_remove(&pc->gpio_chip); return PTR_ERR(pc->pctl_dev); } diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index b7bd4ef9c0db..4a6bdaefa42f 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -547,14 +547,11 @@ static int imx1_pinctrl_parse_functions(struct device_node *np, */ static bool imx1_pinctrl_dt_is_flat_functions(struct device_node *np) { - struct device_node *function_np; - struct device_node *pinctrl_np; - - for_each_child_of_node(np, function_np) { + for_each_child_of_node_scoped(np, function_np) { if (of_property_present(function_np, "fsl,pins")) return true; - for_each_child_of_node(function_np, pinctrl_np) { + for_each_child_of_node_scoped(function_np, pinctrl_np) { if (of_property_present(pinctrl_np, "fsl,pins")) return false; } diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig index abca7ef97003..711c0fe11565 100644 --- a/drivers/pinctrl/nxp/Kconfig +++ b/drivers/pinctrl/nxp/Kconfig @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only config PINCTRL_S32CC bool - depends on ARCH_S32 && OF + depends on ARCH_S32 && OF && GPIOLIB select GENERIC_PINCTRL_GROUPS select GENERIC_PINMUX_FUNCTIONS select GENERIC_PINCONF + select GPIO_REGMAP select REGMAP_MMIO config PINCTRL_S32G2 diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h index 8715befd5f05..028578a090e4 100644 --- a/drivers/pinctrl/nxp/pinctrl-s32.h +++ b/drivers/pinctrl/nxp/pinctrl-s32.h @@ -2,7 +2,7 @@ * * S32 pinmux core definitions * - * Copyright 2016-2020, 2022 NXP + * Copyright 2016-2020, 2022, 2026 NXP * Copyright (C) 2022 SUSE LLC * Copyright 2015-2016 Freescale Semiconductor, Inc. * Copyright (C) 2012 Linaro Ltd. @@ -34,11 +34,42 @@ struct s32_pin_range { unsigned int end; }; +/** + * struct s32_gpio_range - contiguous GPIO pin range within a SIUL2 module + * @gpio_base: first GPIO line offset in the GPIO range + * @pin_base: first pinctrl pin number mapped by this GPIO range + * @gpio_num: number of consecutive GPIO pins in the range + * @sparse: true if the PGPD layout is non-linear (resolved via pad map only); + * pins not found in the pad map are invalid for this range + */ +struct s32_gpio_range { + unsigned int gpio_base; + unsigned int pin_base; + unsigned int gpio_num; + bool sparse; +}; + +/** + * struct s32_gpio_pad_map - mapping between GPIO ranges and PGPD pads + * @gpio_start: first GPIO line offset in the range + * @gpio_end: last GPIO line offset in the range + * @pad: PGPD pad number serving the range + */ +struct s32_gpio_pad_map { + unsigned int gpio_start; + unsigned int gpio_end; + unsigned int pad; +}; + struct s32_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; unsigned int npins; const struct s32_pin_range *mem_pin_ranges; unsigned int mem_regions; + const struct s32_gpio_range *gpio_ranges; + unsigned int num_gpio_ranges; + const struct s32_gpio_pad_map *gpio_pad_maps; + unsigned int num_gpio_pad_maps; }; struct s32_pinctrl_soc_info { @@ -53,6 +84,8 @@ struct s32_pinctrl_soc_info { #define S32_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) #define S32_PIN_RANGE(_start, _end) { .start = _start, .end = _end } +#define S32_GPIO_RANGE(gpio, pin, num) \ + { .gpio_base = gpio, .pin_base = pin, .gpio_num = num } int s32_pinctrl_probe(struct platform_device *pdev, const struct s32_pinctrl_soc_data *soc_data); diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c index 56be6e8d624e..0025add68495 100644 --- a/drivers/pinctrl/nxp/pinctrl-s32cc.c +++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c @@ -2,7 +2,7 @@ /* * Core driver for the S32 CC (Common Chassis) pin controller * - * Copyright 2017-2022,2024-2025 NXP + * Copyright 2017-2022,2024-2026 NXP * Copyright (C) 2022 SUSE LLC * Copyright 2015-2016 Freescale Semiconductor, Inc. */ @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/err.h> #include <linux/gpio/driver.h> +#include <linux/gpio/regmap.h> #include <linux/init.h> #include <linux/io.h> #include <linux/module.h> @@ -39,6 +40,40 @@ #define S32_MSCR_ODE BIT(20) #define S32_MSCR_OBE BIT(21) +#define S32_GPIO_OP_SHIFT 16 +#define S32_GPIO_OP_MASK GENMASK(19, 16) + +#define S32_GPIO_OP_DIR 0 /* MSCR direction */ +#define S32_GPIO_OP_DAT BIT(S32_GPIO_OP_SHIFT) /* PGPDI read */ +#define S32_GPIO_OP_SET BIT(S32_GPIO_OP_SHIFT + 1) /* PGPDO write */ + +/* + * [15:12] = GPIO bank / gpio range index + * [11:0] = real register offset or pin id + */ +#define S32_GPIO_BANK_SHIFT 12 +#define S32_GPIO_BANK_MASK GENMASK(15, 12) +#define S32_GPIO_REG_MASK GENMASK(11, 0) + +#define S32_GPIO_ENCODE(bank, off) \ + ((((bank) << S32_GPIO_BANK_SHIFT) & S32_GPIO_BANK_MASK) | \ + ((off) & S32_GPIO_REG_MASK)) + +#define S32_GPIO_DECODE_BANK(reg) \ + (((reg) & S32_GPIO_BANK_MASK) >> S32_GPIO_BANK_SHIFT) + +#define S32_GPIO_DECODE_OFF(reg) \ + ((reg) & S32_GPIO_REG_MASK) + +/* + * PGPDOs are 16bit registers that come in big endian + * order if they are grouped in pairs of two. + * + * For example, the order is PGPDO1, PGPDO0, PGPDO3, PGPDO2... + */ +#define S32_PGPD(N) (((N) ^ 1) * 2) +#define S32_PGPD_SIZE 16 + enum s32_write_type { S32_PINCONF_UPDATE_ONLY, S32_PINCONF_OVERWRITE, @@ -60,6 +95,12 @@ static u32 get_pin_func(u32 pinmux) return pinmux & GENMASK(3, 0); } +/* + * struct s32_pinctrl_mem_region - memory region for a set of SIUL2 registers + * @map: regmap used for this range + * @pin_range: the pins controlled by these registers + * @name: name of the current range + */ struct s32_pinctrl_mem_region { struct regmap *map; const struct s32_pin_range *pin_range; @@ -67,7 +108,19 @@ struct s32_pinctrl_mem_region { }; /* - * Holds pin configuration for GPIO's. + * struct s32_gpio_regmaps - GPIO register maps for a SIUL2 instance + * @pgpdo: regmap for Parallel GPIO Pad Data Out registers + * @pgpdi: regmap for Parallel GPIO Pad Data In registers + * @range: GPIO range info + */ +struct s32_gpio_regmaps { + struct regmap *pgpdo; + struct regmap *pgpdi; + const struct s32_gpio_range *range; +}; + +/* + * struct gpio_pin_config - holds pin configuration for GPIO's * @pin_id: Pin ID for this GPIO * @config: Pin settings * @list: Linked list entry for each gpio pin @@ -79,26 +132,40 @@ struct gpio_pin_config { }; /* - * Pad config save/restore for power suspend/resume. + * struct s32_pinctrl_context - pad config save/restore for suspend/resume + * @pads: saved values for the pads */ struct s32_pinctrl_context { unsigned int *pads; }; /* + * struct s32_pinctrl - private driver data * @dev: a pointer back to containing device * @pctl: a pointer to the pinctrl device structure * @regions: reserved memory regions with start/end pin * @info: structure containing information about the pin - * @gpio_configs: Saved configurations for GPIO pins - * @gpiop_configs_lock: lock for the `gpio_configs` list - * @s32_pinctrl_context: Configuration saved over system sleep + * @gpio_regmaps: PGPDO/PGPDI regmaps for each SIUL2 module + * @num_gpio_regmaps: number of GPIO regmap entries + * @gpio_regmap: regmap bridging gpio-regmap to SIUL2 registers + * @gpio_rgm: gpio-regmap instance registered for this controller + * @ngpio: total number of GPIO line offsets + * @gpio_names: GPIO line names array passed to gpio-regmap + * @gpio_configs: saved configurations for GPIO pins + * @gpio_configs_lock: lock for the `gpio_configs` list + * @saved_context: configuration saved over system sleep */ struct s32_pinctrl { struct device *dev; struct pinctrl_dev *pctl; struct s32_pinctrl_mem_region *regions; struct s32_pinctrl_soc_info *info; + struct s32_gpio_regmaps *gpio_regmaps; + unsigned int num_gpio_regmaps; + struct regmap *gpio_regmap; + struct gpio_regmap *gpio_rgm; + unsigned int ngpio; + const char *const *gpio_names; struct list_head gpio_configs; spinlock_t gpio_configs_lock; #ifdef CONFIG_PM_SLEEP @@ -123,13 +190,13 @@ s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin) return NULL; } -static inline int s32_check_pin(struct pinctrl_dev *pctldev, - unsigned int pin) +static int s32_check_pin(struct pinctrl_dev *pctldev, + unsigned int pin) { return s32_get_region(pctldev, pin) ? 0 : -EINVAL; } -static inline int s32_regmap_read(struct pinctrl_dev *pctldev, +static int s32_regmap_read(struct pinctrl_dev *pctldev, unsigned int pin, unsigned int *val) { struct s32_pinctrl_mem_region *region; @@ -145,7 +212,7 @@ static inline int s32_regmap_read(struct pinctrl_dev *pctldev, return regmap_read(region->map, offset, val); } -static inline int s32_regmap_write(struct pinctrl_dev *pctldev, +static int s32_regmap_write(struct pinctrl_dev *pctldev, unsigned int pin, unsigned int val) { @@ -163,7 +230,7 @@ static inline int s32_regmap_write(struct pinctrl_dev *pctldev, } -static inline int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin, +static int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin, unsigned int mask, unsigned int val) { struct s32_pinctrl_mem_region *region; @@ -348,88 +415,84 @@ static int s32_pmx_get_funcs_count(struct pinctrl_dev *pctldev) return info->nfunctions; } -static const char *s32_pmx_get_func_name(struct pinctrl_dev *pctldev, - unsigned int selector) -{ - struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct s32_pinctrl_soc_info *info = ipctl->info; - - return info->functions[selector].name; -} - -static int s32_pmx_get_groups(struct pinctrl_dev *pctldev, - unsigned int selector, - const char * const **groups, - unsigned int * const num_groups) -{ - struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - const struct s32_pinctrl_soc_info *info = ipctl->info; - - *groups = info->functions[selector].groups; - *num_groups = info->functions[selector].ngroups; - - return 0; -} - static int s32_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned int offset) + unsigned int pin) { struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct gpio_pin_config *gpio_pin; + struct gpio_pin_config *gpio_pin __free(kfree) = NULL; unsigned int config; - unsigned long flags; int ret; - ret = s32_regmap_read(pctldev, offset, &config); + ret = s32_regmap_read(pctldev, pin, &config); if (ret) return ret; - /* Save current configuration */ - gpio_pin = kmalloc_obj(*gpio_pin); + gpio_pin = kmalloc_obj(*gpio_pin, GFP_KERNEL); if (!gpio_pin) return -ENOMEM; - gpio_pin->pin_id = offset; + gpio_pin->pin_id = pin; gpio_pin->config = config; - INIT_LIST_HEAD(&gpio_pin->list); - - spin_lock_irqsave(&ipctl->gpio_configs_lock, flags); - list_add(&gpio_pin->list, &ipctl->gpio_configs); - spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags); /* GPIO pin means SSS = 0 */ - config &= ~S32_MSCR_SSS_MASK; + ret = s32_regmap_update(pctldev, pin, + S32_MSCR_SSS_MASK | S32_MSCR_IBE, + S32_MSCR_IBE); + if (ret) + return ret; - return s32_regmap_write(pctldev, offset, config); + scoped_guard(spinlock_irqsave, &ipctl->gpio_configs_lock) + list_add(&no_free_ptr(gpio_pin)->list, &ipctl->gpio_configs); + + return 0; } static void s32_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, - unsigned int offset) + unsigned int pin) { struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); - struct gpio_pin_config *gpio_pin, *tmp; + struct gpio_pin_config *gpio_pin, *found = NULL; unsigned long flags; - int ret; spin_lock_irqsave(&ipctl->gpio_configs_lock, flags); - - list_for_each_entry_safe(gpio_pin, tmp, &ipctl->gpio_configs, list) { - if (gpio_pin->pin_id == offset) { - ret = s32_regmap_write(pctldev, gpio_pin->pin_id, - gpio_pin->config); - if (ret != 0) - goto unlock; - + list_for_each_entry(gpio_pin, &ipctl->gpio_configs, list) { + if (gpio_pin->pin_id == pin) { list_del(&gpio_pin->list); - kfree(gpio_pin); + found = gpio_pin; break; } } - -unlock: spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags); + + if (found) { + s32_regmap_write(pctldev, found->pin_id, found->config); + kfree(found); + } +} + +static const char *s32_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + return info->functions[selector].name; +} + +static int s32_pmx_get_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int * const num_groups) +{ + struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct s32_pinctrl_soc_info *info = ipctl->info; + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; } static int s32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, @@ -476,8 +539,8 @@ static int s32_get_slew_regval(int arg) return -EINVAL; } -static inline void s32_pin_set_pull(enum pin_config_param param, - unsigned int *mask, unsigned int *config) +static void s32_pin_set_pull(enum pin_config_param param, + unsigned int *mask, unsigned int *config) { switch (param) { case PIN_CONFIG_BIAS_DISABLE: @@ -641,9 +704,9 @@ static void s32_pinconf_dbg_show(struct pinctrl_dev *pctldev, ret = s32_regmap_read(pctldev, pin_id, &config); if (ret) - return; - - seq_printf(s, "0x%x", config); + seq_printf(s, "error %d", ret); + else + seq_printf(s, "0x%x", config); } static void s32_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, @@ -661,8 +724,11 @@ static void s32_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, for (i = 0; i < grp->data.npins; i++) { name = pin_get_name(pctldev, grp->data.pins[i]); ret = s32_regmap_read(pctldev, grp->data.pins[i], &config); - if (ret) - return; + if (ret) { + seq_printf(s, "%s: error %d\n", name, ret); + continue; + } + seq_printf(s, "%s: 0x%x\n", name, config); } } @@ -675,6 +741,477 @@ static const struct pinconf_ops s32_pinconf_ops = { .pin_config_group_dbg_show = s32_pinconf_group_dbg_show, }; +static void s32_gpio_free_saved_configs(void *data) +{ + struct s32_pinctrl *ipctl = data; + struct gpio_pin_config *gpio_pin, *tmp; + unsigned long flags; + + spin_lock_irqsave(&ipctl->gpio_configs_lock, flags); + list_for_each_entry_safe(gpio_pin, tmp, &ipctl->gpio_configs, list) { + list_del(&gpio_pin->list); + kfree(gpio_pin); + } + spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags); +} + +static unsigned int s32_pin2pad(unsigned int pin) +{ + return pin / S32_PGPD_SIZE; +} + +static u16 s32_pin2mask(unsigned int pin) +{ + /* + * From Reference manual : + * PGPDOx[PPDOy] = GPDO(x × 16) + (15 - y)[PDO_(x × 16) + (15 - y)] + */ + return BIT(S32_PGPD_SIZE - 1 - pin % S32_PGPD_SIZE); +} + +static int s32_gpio_get_range(struct s32_pinctrl *ipctl, + unsigned int gpio, + unsigned int *pin, + unsigned int *bank) +{ + const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data; + const struct s32_gpio_range *range; + int i; + + for (i = 0; i < soc_data->num_gpio_ranges; i++) { + range = &soc_data->gpio_ranges[i]; + + if (gpio < range->gpio_base || + gpio >= range->gpio_base + range->gpio_num) + continue; + + if (pin) + *pin = range->pin_base + gpio - range->gpio_base; + + if (bank) + *bank = i; + + return 0; + } + + return -EINVAL; +} + +static int s32_gpio_pad_map_xlate(struct s32_pinctrl *ipctl, + unsigned int gpio, + unsigned int *reg_offset, + u16 *mask) +{ + const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data; + const struct s32_gpio_pad_map *map; + unsigned int bit; + int i; + + if (!soc_data->gpio_pad_maps || !soc_data->num_gpio_pad_maps) + return -EINVAL; + + for (i = 0; i < soc_data->num_gpio_pad_maps; i++) { + map = &soc_data->gpio_pad_maps[i]; + + if (gpio < map->gpio_start || gpio > map->gpio_end) + continue; + + bit = gpio - map->gpio_start; + *mask = BIT(S32_PGPD_SIZE - 1 - bit); + *reg_offset = S32_PGPD(map->pad); + + return 0; + } + + return -EINVAL; +} + +static bool s32_gpio_pin_is_sparse(struct s32_pinctrl *ipctl, unsigned int pin) +{ + const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data; + const struct s32_gpio_range *range; + int i; + + for (i = 0; i < soc_data->num_gpio_ranges; i++) { + range = &soc_data->gpio_ranges[i]; + if (pin >= range->pin_base && + pin < range->pin_base + range->gpio_num) + return range->sparse; + } + + return false; +} + +static int s32_gpio_xlate_pgpd(struct s32_pinctrl *ipctl, + unsigned int pin, + unsigned int *reg_offset, + u16 *mask) +{ + int ret; + + /* + * Try the pad map first. For sparse ranges (SIUL2_1), only pins + * listed in the pad map are valid, return the error directly without + * falling back to the linear layout. + * For linear ranges (SIUL2_0), fall back to the linear pad-to-PGPD + * formula if no pad map entry matches. + */ + ret = s32_gpio_pad_map_xlate(ipctl, pin, reg_offset, mask); + if (ret != -EINVAL) + return ret; + + if (s32_gpio_pin_is_sparse(ipctl, pin)) + return -EINVAL; + + /* Linear layout fallback for non-sparse ranges. */ + *mask = s32_pin2mask(pin); + *reg_offset = S32_PGPD(s32_pin2pad(pin)); + + return 0; +} + +static int s32_gpio_reg_mask_xlate(struct gpio_regmap *gpio, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask) +{ + struct s32_pinctrl *ipctl = gpio_regmap_get_drvdata(gpio); + unsigned int pgpd_reg, pin, bank; + u16 pgpd_mask; + int ret; + + ret = s32_gpio_get_range(ipctl, offset, &pin, &bank); + if (ret) + return ret; + + switch (base) { + case S32_GPIO_OP_DIR: + /* + * Direction is controlled through MSCR OBE. + * Encode the real pin id in the virtual register. + */ + *reg = S32_GPIO_OP_DIR | pin; + *mask = S32_MSCR_OBE; + return 0; + + case S32_GPIO_OP_DAT: + case S32_GPIO_OP_SET: + ret = s32_gpio_xlate_pgpd(ipctl, pin, &pgpd_reg, &pgpd_mask); + if (ret) + return ret; + /* + * Encode both the GPIO bank and the real PGPD register offset. + */ + *reg = base | S32_GPIO_ENCODE(bank, pgpd_reg); + *mask = pgpd_mask; + return 0; + default: + return -EINVAL; + } +} + +static int s32_gpio_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct s32_pinctrl *ipctl = context; + unsigned int op = reg & S32_GPIO_OP_MASK; + unsigned int vreg = reg & ~S32_GPIO_OP_MASK; + unsigned int bank; + unsigned int offset; + struct regmap *map; + + switch (op) { + case S32_GPIO_OP_DIR: + /* + * Lower bits contain the real MSCR pin id. + */ + offset = S32_GPIO_DECODE_OFF(vreg); + + return s32_regmap_read(ipctl->pctl, offset, val); + + case S32_GPIO_OP_DAT: + bank = S32_GPIO_DECODE_BANK(vreg); + offset = S32_GPIO_DECODE_OFF(vreg); + + if (bank >= ipctl->num_gpio_regmaps) + return -EINVAL; + + map = ipctl->gpio_regmaps[bank].pgpdi; + if (!map) + return -ENODEV; + + return regmap_read(map, offset, val); + + case S32_GPIO_OP_SET: + /* + * gpio-regmap uses update_bits() for set, so it needs to read + * the output register before writing the updated value. + */ + bank = S32_GPIO_DECODE_BANK(vreg); + offset = S32_GPIO_DECODE_OFF(vreg); + + if (bank >= ipctl->num_gpio_regmaps) + return -EINVAL; + + map = ipctl->gpio_regmaps[bank].pgpdo; + if (!map) + return -ENODEV; + + return regmap_read(map, offset, val); + + default: + return -EINVAL; + } +} + +static int s32_gpio_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct s32_pinctrl *ipctl = context; + unsigned int op = reg & S32_GPIO_OP_MASK; + unsigned int vreg = reg & ~S32_GPIO_OP_MASK; + unsigned int bank, offset, config; + struct regmap *map; + + switch (op) { + case S32_GPIO_OP_DIR: + /* + * gpio-regmap sets S32_MSCR_OBE for output and clears it for + * input. Keep IBE enabled for GPIOs in both cases. + */ + offset = S32_GPIO_DECODE_OFF(vreg); + + config = S32_MSCR_IBE; + if (val & S32_MSCR_OBE) + config |= S32_MSCR_OBE; + + return s32_regmap_update(ipctl->pctl, offset, + S32_MSCR_OBE | S32_MSCR_IBE, + config); + + case S32_GPIO_OP_SET: + bank = S32_GPIO_DECODE_BANK(vreg); + offset = S32_GPIO_DECODE_OFF(vreg); + + if (bank >= ipctl->num_gpio_regmaps) + return -EINVAL; + + map = ipctl->gpio_regmaps[bank].pgpdo; + if (!map) + return -ENODEV; + + return regmap_write(map, offset, val); + + default: + return -EINVAL; + } +} + +static const struct regmap_bus s32_gpio_regmap_bus = { + .reg_read = s32_gpio_reg_read, + .reg_write = s32_gpio_reg_write, +}; + +static const struct regmap_config s32_gpio_regmap_config = { + .name = "s32-gpio", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 1, + .max_register = S32_GPIO_OP_SET | S32_GPIO_BANK_MASK | S32_GPIO_REG_MASK, + .cache_type = REGCACHE_NONE, + .fast_io = true, +}; + +static int s32_gpio_get_ngpio(const struct s32_pinctrl_soc_data *soc_data, + unsigned int *ngpio) +{ + const struct s32_gpio_range *range; + unsigned int end, max = 0; + int i; + + if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges) + return -EINVAL; + + for (i = 0; i < soc_data->num_gpio_ranges; i++) { + range = &soc_data->gpio_ranges[i]; + + if (!range->gpio_num) + return -EINVAL; + + end = range->gpio_base + range->gpio_num; + + /* + * gpio_ranges must be ordered by gpio_base and must not overlap. + * The GPIO line space size is derived from the highest range end. + */ + if (i > 0 && range->gpio_base < max) + return -EINVAL; + + if (end > max) + max = end; + } + + *ngpio = max; + + return 0; +} + +static int s32_init_gpio_regmap(struct platform_device *pdev, + struct s32_pinctrl *ipctl) +{ + ipctl->gpio_regmap = + devm_regmap_init(&pdev->dev, &s32_gpio_regmap_bus, + ipctl, &s32_gpio_regmap_config); + if (IS_ERR(ipctl->gpio_regmap)) + return dev_err_probe(&pdev->dev, + PTR_ERR(ipctl->gpio_regmap), + "Failed to init GPIO regmap\n"); + + return 0; +} + +static int s32_init_valid_mask(struct gpio_chip *chip, unsigned long *mask, + unsigned int ngpios) +{ + struct gpio_regmap *gpio = gpiochip_get_data(chip); + struct s32_pinctrl *ipctl = gpio_regmap_get_drvdata(gpio); + unsigned int gpio_num, pin, reg_offset; + u16 pgpd_mask; + int ret; + + bitmap_zero(mask, ngpios); + + for (gpio_num = 0; gpio_num < ngpios; gpio_num++) { + ret = s32_gpio_get_range(ipctl, gpio_num, &pin, NULL); + if (ret) + continue; + + ret = s32_gpio_xlate_pgpd(ipctl, pin, ®_offset, &pgpd_mask); + if (ret) + continue; + + bitmap_set(mask, gpio_num, 1); + } + + return 0; +} + +static int s32_gpio_populate_names(struct s32_pinctrl *ipctl) +{ + char **names; + unsigned int gpio; + unsigned int pin; + char port; + int ret; + + names = devm_kcalloc(ipctl->dev, ipctl->ngpio, sizeof(*names), + GFP_KERNEL); + if (!names) + return -ENOMEM; + + for (gpio = 0; gpio < ipctl->ngpio; gpio++) { + ret = s32_gpio_get_range(ipctl, gpio, &pin, NULL); + if (ret) + continue; + + port = 'A' + pin / 16; + + names[gpio] = devm_kasprintf(ipctl->dev, GFP_KERNEL, + "P%c_%02u", port, pin & 0xf); + if (!names[gpio]) + return -ENOMEM; + } + + ipctl->gpio_names = (const char *const *)names; + + return 0; +} + +static int s32_pinctrl_init_gpio_regmaps(struct platform_device *pdev, + struct s32_pinctrl *ipctl) +{ + const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data; + static const struct regmap_config pgpd_config = { + .reg_bits = 32, + .val_bits = 16, + .reg_stride = 2, + }; + struct regmap_config cfg; + struct resource *res; + void __iomem *base; + unsigned int pgpdo_idx, pgpdi_idx; + unsigned int i; + + if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges) + return 0; + + ipctl->num_gpio_regmaps = soc_data->num_gpio_ranges; + ipctl->gpio_regmaps = devm_kcalloc(&pdev->dev, ipctl->num_gpio_regmaps, + sizeof(*ipctl->gpio_regmaps), + GFP_KERNEL); + if (!ipctl->gpio_regmaps) + return -ENOMEM; + + for (i = 0; i < ipctl->num_gpio_regmaps; i++) { + ipctl->gpio_regmaps[i].range = &soc_data->gpio_ranges[i]; + + /* + * GPIO resources are placed after the pinctrl regions + */ + pgpdo_idx = soc_data->mem_regions + i * 2; + pgpdi_idx = soc_data->mem_regions + i * 2 + 1; + + /* PGPDO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, pgpdo_idx); + if (!res) + return dev_err_probe(&pdev->dev, -ENOENT, + "Missing PGPDO resource %u\n", i); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + cfg = pgpd_config; + cfg.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pgpdo%u", i); + if (!cfg.name) + return -ENOMEM; + + cfg.max_register = resource_size(res) - cfg.reg_stride; + + ipctl->gpio_regmaps[i].pgpdo = + devm_regmap_init_mmio(&pdev->dev, base, &cfg); + if (IS_ERR(ipctl->gpio_regmaps[i].pgpdo)) + return dev_err_probe(&pdev->dev, + PTR_ERR(ipctl->gpio_regmaps[i].pgpdo), + "Failed to init PGPDO regmap %u\n", i); + + /* PGPDI */ + res = platform_get_resource(pdev, IORESOURCE_MEM, pgpdi_idx); + if (!res) + return dev_err_probe(&pdev->dev, -ENOENT, + "Missing PGPDI resource %u\n", i); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + cfg = pgpd_config; + cfg.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pgpdi%u", i); + if (!cfg.name) + return -ENOMEM; + + cfg.max_register = resource_size(res) - cfg.reg_stride; + + ipctl->gpio_regmaps[i].pgpdi = + devm_regmap_init_mmio(&pdev->dev, base, &cfg); + if (IS_ERR(ipctl->gpio_regmaps[i].pgpdi)) + return dev_err_probe(&pdev->dev, + PTR_ERR(ipctl->gpio_regmaps[i].pgpdi), + "Failed to init PGPDI regmap %u\n", i); + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static bool s32_pinctrl_should_save(struct s32_pinctrl *ipctl, unsigned int pin) @@ -701,8 +1238,7 @@ int s32_pinctrl_suspend(struct device *dev) const struct pinctrl_pin_desc *pin; const struct s32_pinctrl_soc_info *info = ipctl->info; struct s32_pinctrl_context *saved_context = &ipctl->saved_context; - int i; - int ret; + int i, ret; unsigned int config; for (i = 0; i < info->soc_data->npins; i++) { @@ -713,7 +1249,7 @@ int s32_pinctrl_suspend(struct device *dev) ret = s32_regmap_read(ipctl->pctl, pin->number, &config); if (ret) - return -EINVAL; + return ret; saved_context->pads[i] = config; } @@ -728,7 +1264,7 @@ int s32_pinctrl_resume(struct device *dev) const struct s32_pinctrl_soc_info *info = ipctl->info; const struct pinctrl_pin_desc *pin; struct s32_pinctrl_context *saved_context = &ipctl->saved_context; - int ret, i; + int i, ret; for (i = 0; i < info->soc_data->npins; i++) { pin = &info->soc_data->pins[i]; @@ -737,7 +1273,7 @@ int s32_pinctrl_resume(struct device *dev) continue; ret = s32_regmap_write(ipctl->pctl, pin->number, - saved_context->pads[i]); + saved_context->pads[i]); if (ret) return ret; } @@ -920,9 +1456,11 @@ int s32_pinctrl_probe(struct platform_device *pdev, #ifdef CONFIG_PM_SLEEP struct s32_pinctrl_context *saved_context; #endif + struct gpio_regmap_config gpio_cfg = {}; struct pinctrl_desc *s32_pinctrl_desc; struct s32_pinctrl_soc_info *info; struct s32_pinctrl *ipctl; + unsigned int ngpio; int ret; if (!soc_data || !soc_data->pins || !soc_data->npins) @@ -948,6 +1486,11 @@ int s32_pinctrl_probe(struct platform_device *pdev, INIT_LIST_HEAD(&ipctl->gpio_configs); spin_lock_init(&ipctl->gpio_configs_lock); + ret = devm_add_action_or_reset(&pdev->dev, + s32_gpio_free_saved_configs, ipctl); + if (ret) + return ret; + s32_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*s32_pinctrl_desc), GFP_KERNEL); if (!s32_pinctrl_desc) @@ -966,11 +1509,16 @@ int s32_pinctrl_probe(struct platform_device *pdev, return dev_err_probe(&pdev->dev, ret, "Fail to probe dt properties\n"); - ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc, - ipctl); - if (IS_ERR(ipctl->pctl)) - return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl), - "could not register s32 pinctrl driver\n"); + ret = s32_pinctrl_init_gpio_regmaps(pdev, ipctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to init GPIO regmaps\n"); + + ret = devm_pinctrl_register_and_init(&pdev->dev, s32_pinctrl_desc, + ipctl, &ipctl->pctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Could not register s32 pinctrl driver\n"); #ifdef CONFIG_PM_SLEEP saved_context = &ipctl->saved_context; @@ -982,7 +1530,47 @@ int s32_pinctrl_probe(struct platform_device *pdev, return -ENOMEM; #endif - dev_info(&pdev->dev, "initialized s32 pinctrl driver\n"); + ret = pinctrl_enable(ipctl->pctl); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to enable pinctrl\n"); + + /* Setup GPIO if GPIO ranges are defined */ + if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges) + return 0; + + ret = s32_gpio_get_ngpio(soc_data, &ngpio); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Invalid GPIO ranges\n"); + + ipctl->ngpio = ngpio; + + ret = s32_gpio_populate_names(ipctl); + if (ret) + return ret; + + ret = s32_init_gpio_regmap(pdev, ipctl); + if (ret) + return ret; + + gpio_cfg.parent = &pdev->dev; + gpio_cfg.fwnode = dev_fwnode(&pdev->dev); + gpio_cfg.label = dev_name(&pdev->dev); + gpio_cfg.regmap = ipctl->gpio_regmap; + gpio_cfg.ngpio = ngpio; + gpio_cfg.names = ipctl->gpio_names; + gpio_cfg.reg_dir_out_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_DIR); + gpio_cfg.reg_dat_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_DAT); + gpio_cfg.reg_set_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_SET); + gpio_cfg.reg_mask_xlate = s32_gpio_reg_mask_xlate; + gpio_cfg.init_valid_mask = s32_init_valid_mask; + gpio_cfg.drvdata = ipctl; + + ipctl->gpio_rgm = devm_gpio_regmap_register(&pdev->dev, &gpio_cfg); + if (IS_ERR(ipctl->gpio_rgm)) + return dev_err_probe(&pdev->dev, + PTR_ERR(ipctl->gpio_rgm), + "Unable to add gpio_regmap chip\n"); return 0; } diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c index c49d28793b69..f9546c67a269 100644 --- a/drivers/pinctrl/nxp/pinctrl-s32g2.c +++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c @@ -3,7 +3,7 @@ * NXP S32G pinctrl driver * * Copyright 2015-2016 Freescale Semiconductor, Inc. - * Copyright 2017-2018, 2020-2022 NXP + * Copyright 2017-2018, 2020-2022, 2025-2026 NXP * Copyright (C) 2022 SUSE LLC */ @@ -773,17 +773,48 @@ static const struct s32_pin_range s32_pin_ranges_siul2[] = { S32_PIN_RANGE(942, 1007), }; -static const struct s32_pinctrl_soc_data s32_pinctrl_data = { +static const struct s32_gpio_range s32_gpio_ranges_siul2[] = { + S32_GPIO_RANGE(0, 0, 102), + /* SIUL2_1: sparse layout, PGPD mapping required for all pins */ + { .gpio_base = 112, .pin_base = 112, .gpio_num = 79, .sparse = true }, +}; + +/* + * SIUL2_1 GPIO ranges mapped to sparse PGPD pads. + * + * SIUL2_1 does not expose GPIO data registers as a linear pad + * sequence. Each entry describes a contiguous GPIO offset range + * and the PGPD pad servicing that range. + */ +static const struct s32_gpio_pad_map s32g_gpio_pad_maps[] = { + { 112, 122, 7 }, /* PH_00 .. PH_10 -> PGPD7 */ + { 144, 159, 9 }, /* PJ_00 .. PJ_15 -> PGPD9 */ + { 160, 175, 10 }, /* PK_00 .. PK_15 -> PGPD10 */ + { 176, 190, 11 }, /* PL_00 .. PL_14 -> PGPD11 */ +}; + +/* Legacy data for old DT bindings without GPIO support */ +static const struct s32_pinctrl_soc_data legacy_s32g_pinctrl_data = { + .pins = s32_pinctrl_pads_siul2, + .npins = ARRAY_SIZE(s32_pinctrl_pads_siul2), + .mem_pin_ranges = s32_pin_ranges_siul2, + .mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2), +}; + +static const struct s32_pinctrl_soc_data s32g_pinctrl_data = { .pins = s32_pinctrl_pads_siul2, .npins = ARRAY_SIZE(s32_pinctrl_pads_siul2), .mem_pin_ranges = s32_pin_ranges_siul2, .mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2), + .gpio_ranges = s32_gpio_ranges_siul2, + .num_gpio_ranges = ARRAY_SIZE(s32_gpio_ranges_siul2), + .gpio_pad_maps = s32g_gpio_pad_maps, + .num_gpio_pad_maps = ARRAY_SIZE(s32g_gpio_pad_maps), }; static const struct of_device_id s32_pinctrl_of_match[] = { { .compatible = "nxp,s32g2-siul2-pinctrl", - .data = &s32_pinctrl_data, }, { /* sentinel */ } }; @@ -792,8 +823,16 @@ MODULE_DEVICE_TABLE(of, s32_pinctrl_of_match); static int s32g_pinctrl_probe(struct platform_device *pdev) { const struct s32_pinctrl_soc_data *soc_data; + struct device_node *np = pdev->dev.of_node; - soc_data = of_device_get_match_data(&pdev->dev); + /* + * Legacy DTs only describe the pinctrl resources. + * New DT changes extend the same node with GPIO resources. + */ + if (of_property_present(np, "gpio-controller")) + soc_data = &s32g_pinctrl_data; + else + soc_data = &legacy_s32g_pinctrl_data; return s32_pinctrl_probe(pdev, soc_data); } diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index 3f581404a9b9..b7cbd69dd877 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -479,7 +479,7 @@ struct tb10x_port { */ struct tb10x_pinctrl { struct pinctrl_dev *pctl; - void *base; + void __iomem *base; const struct tb10x_pinfuncgrp *pingroups; unsigned int pinfuncgrpcnt; unsigned int pinfuncnt; |
