pinctrl: s32cc: implement GPIO functionality

The updated SIUL2 block groups pinctrl, GPIO data access
and interrupt control within the same hardware unit.
The SIUL2 driver is therefore structured as a monolithic
pinctrl/GPIO driver.

GPIO data access and direction handling are implemented using the
gpio-regmap library backed by a virtual regmap. The virtual regmap
translates the gpio-regmap register model to the underlying SIUL2
registers: MSCR for direction, PGPDI for input values and PGPDO for
output values.

The existing pinctrl GPIO callbacks are used for the request/free path:
they switch the pad to GPIO mode on request and restore the previous
MSCR configuration when the GPIO is released.

This change came as a result of upstream review in the
following series:
https://lore.kernel.org/linux-gpio/20260120115923.3463866-4-khristineandreea.barbulescu@oss.nxp.com/T/#m543c9edbdde74bdc68b6a2364e8b975356c33043
https://lore.kernel.org/all/20260504131148.3622697-7-khristineandreea.barbulescu@oss.nxp.com/

Support both SIUL2 DT layouts:
- legacy pinctrl-only binding
- extended pinctrl/GPIO/irqchip binding

Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Link: https://lore.kernel.org/linux-gpio/20260120115923.3463866-4-khristineandreea.barbulescu@oss.nxp.com/T/#m543c9edbdde74bdc68b6a2364e8b975356c33043
Link: https://lore.kernel.org/all/20260504131148.3622697-7-khristineandreea.barbulescu@oss.nxp.com/
Signed-off-by: Linus Walleij <linusw@kernel.org>
This commit is contained in:
Andrei Stefanescu
2026-07-01 12:33:18 +02:00
committed by Linus Walleij
parent e91152802f
commit 94cb9e8f27
4 changed files with 727 additions and 79 deletions
+2 -1
View File
@@ -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
+34 -1
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+43 -4
View File
@@ -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);
}