[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250710142038.1986052-8-andrei.stefanescu@oss.nxp.com>
Date: Thu, 10 Jul 2025 17:20:30 +0300
From: Andrei Stefanescu <andrei.stefanescu@....nxp.com>
To: linus.walleij@...aro.org,
brgl@...ev.pl,
robh@...nel.org,
krzk+dt@...nel.org,
conor+dt@...nel.org,
chester62515@...il.com,
mbrugger@...e.com,
Ghennadi.Procopciuc@....com,
larisa.grigore@....com,
lee@...nel.org,
shawnguo@...nel.org,
s.hauer@...gutronix.de,
festevam@...il.com,
aisheng.dong@....com,
ping.bai@....com,
gregkh@...uxfoundation.org,
rafael@...nel.org,
srini@...nel.org
Cc: linux-gpio@...r.kernel.org,
devicetree@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org,
s32@....com,
clizzi@...hat.com,
aruizrui@...hat.com,
eballetb@...hat.com,
echanude@...hat.com,
kernel@...gutronix.de,
imx@...ts.linux.dev,
vincent.guittot@...aro.org,
Andrei Stefanescu <andrei.stefanescu@....nxp.com>
Subject: [PATCH v7 07/12] pinctrl: s32g2: change the driver to also be probed as an MFD cell
The old pinctrl bindings for SIUL2 are deprecated by a previous commit.
The new bindings for the SIUL2 represent it as an MFD device:
- one cell for combined pinctrl&GPIO
- one cell for an NVMEM driver
This commit allows the existing driver to also be probed as an MFD cell.
The changes only impact the way the driver initializes the regmaps for
accessing MSCR and IMCR registers.
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@....nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32.h | 4 +-
drivers/pinctrl/nxp/pinctrl-s32cc.c | 132 ++++++++++++++++++++++------
drivers/pinctrl/nxp/pinctrl-s32g2.c | 32 +++++--
3 files changed, 136 insertions(+), 32 deletions(-)
diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h
index add3c77ddfed..6ce7981208c7 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, 2025 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
@@ -28,6 +28,7 @@ struct s32_pin_group {
* struct s32_pin_range - pin ID range for each memory region.
* @start: start pin ID
* @end: end pin ID
+ * @legacy: legacy standalone pinctrl driver or MFD cell
*/
struct s32_pin_range {
unsigned int start;
@@ -39,6 +40,7 @@ struct s32_pinctrl_soc_data {
unsigned int npins;
const struct s32_pin_range *mem_pin_ranges;
unsigned int mem_regions;
+ bool legacy;
};
struct s32_pinctrl_soc_info {
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index c03dac643cb3..18b81b246bec 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -12,6 +12,7 @@
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mfd/nxp-siul2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -39,6 +40,8 @@
#define S32_MSCR_ODE BIT(20)
#define S32_MSCR_OBE BIT(21)
+#define NVMEM_LAYOUT "nvmem-layout"
+
enum s32_write_type {
S32_PINCONF_UPDATE_ONLY,
S32_PINCONF_OVERWRITE,
@@ -101,6 +104,8 @@ struct s32_pinctrl_context {
* @gpio_configs: saved configurations for GPIO pins
* @gpio_configs_lock: lock for the `gpio_configs` list
* @saved_context: configuration saved over system sleep
+ * @legacy: true if the old pinctrl bindings are in use
+ * instead of the newer MFD based ones
*/
struct s32_pinctrl {
struct device *dev;
@@ -112,6 +117,7 @@ struct s32_pinctrl {
#ifdef CONFIG_PM_SLEEP
struct s32_pinctrl_context saved_context;
#endif
+ bool legacy;
};
static struct s32_pinctrl_mem_region *
@@ -131,6 +137,19 @@ s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin)
return NULL;
}
+static struct device *s32_get_dev(struct s32_pinctrl *ipctl)
+{
+ if (ipctl->legacy)
+ return ipctl->dev;
+
+ return ipctl->dev->parent;
+}
+
+static struct device_node *s32_get_np(struct s32_pinctrl *ipctl)
+{
+ return s32_get_dev(ipctl)->of_node;
+}
+
static int s32_check_pin(struct pinctrl_dev *pctldev,
unsigned int pin)
{
@@ -231,7 +250,7 @@ static int s32_dt_group_node_to_map(struct pinctrl_dev *pctldev,
const char *func_name)
{
struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct device *dev = ipctl->dev;
+ struct device *dev = s32_get_dev(ipctl);
unsigned long *cfgs = NULL;
unsigned int n_cfgs, reserve = 1;
int n_pins, ret;
@@ -682,6 +701,11 @@ static const struct pinconf_ops s32_pinconf_ops = {
.pin_config_group_dbg_show = s32_pinconf_group_dbg_show,
};
+static struct s32_pinctrl *to_s32_pinctrl(struct gpio_chip *chip)
+{
+ return container_of(chip, struct s32_pinctrl, gc);
+}
+
#ifdef CONFIG_PM_SLEEP
static bool s32_pinctrl_should_save(struct s32_pinctrl *ipctl,
unsigned int pin)
@@ -803,8 +827,8 @@ static int s32_pinctrl_parse_groups(struct device_node *np,
}
static int s32_pinctrl_parse_functions(struct device_node *np,
- struct s32_pinctrl_soc_info *info,
- u32 index)
+ struct s32_pinctrl_soc_info *info,
+ u32 index)
{
struct pinfunction *func;
struct s32_pin_group *grp;
@@ -842,31 +866,24 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
return 0;
}
-static int s32_pinctrl_probe_dt(struct platform_device *pdev,
- struct s32_pinctrl *ipctl)
+static int legacy_s32_pinctrl_regmap_init(struct platform_device *pdev,
+ struct s32_pinctrl *ipctl)
{
struct s32_pinctrl_soc_info *info = ipctl->info;
- struct device_node *np = pdev->dev.of_node;
+ const struct s32_pinctrl_soc_data *soc_data;
+ unsigned int mem_regions;
struct resource *res;
struct regmap *map;
void __iomem *base;
- unsigned int mem_regions = info->soc_data->mem_regions;
- int ret;
- u32 nfuncs = 0;
u32 i = 0;
- if (!np)
- return -ENODEV;
+ soc_data = info->soc_data;
- if (mem_regions == 0 || mem_regions >= 10000) {
- dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions);
- return -EINVAL;
- }
-
- ipctl->regions = devm_kcalloc(&pdev->dev, mem_regions,
- sizeof(*ipctl->regions), GFP_KERNEL);
- if (!ipctl->regions)
- return -ENOMEM;
+ mem_regions = info->soc_data->mem_regions;
+ if (mem_regions == 0 || mem_regions >= 10000)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "mem_regions is invalid: %u\n",
+ mem_regions);
for (i = 0; i < mem_regions; i++) {
base = devm_platform_get_and_ioremap_resource(pdev, i, &res);
@@ -881,7 +898,7 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
s32_regmap_config.reg_stride;
map = devm_regmap_init_mmio(&pdev->dev, base,
- &s32_regmap_config);
+ &s32_regmap_config);
if (IS_ERR(map)) {
dev_err(&pdev->dev, "Failed to init regmap[%u]\n", i);
return PTR_ERR(map);
@@ -891,7 +908,53 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
ipctl->regions[i].pin_range = &info->soc_data->mem_pin_ranges[i];
}
- nfuncs = of_get_child_count(np);
+ return 0;
+}
+
+static int s32_pinctrl_mfd_regmap_init(struct platform_device *pdev,
+ struct s32_pinctrl *ipctl)
+
+{
+ struct nxp_siul2_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
+ struct s32_pinctrl_soc_info *info = ipctl->info;
+ const struct s32_pinctrl_soc_data *soc_data;
+ unsigned int mem_regions;
+ u8 regmap_type;
+ u32 i = 0, j;
+
+ soc_data = info->soc_data;
+
+ /* One MSCR and one IMCR region per SIUL2 module. */
+ mem_regions = info->soc_data->mem_regions;
+ if (mem_regions != mfd->num_siul2 * 2)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "mem_regions is invalid: %u\n",
+ mem_regions);
+
+ for (i = 0; i < mem_regions; i++) {
+ regmap_type = i < mem_regions / 2 ? SIUL2_MSCR : SIUL2_IMCR;
+ j = i % mfd->num_siul2;
+ ipctl->regions[i].map = mfd->siul2[j].regmaps[regmap_type];
+ ipctl->regions[i].pin_range = &info->soc_data->mem_pin_ranges[i];
+ }
+
+ return 0;
+}
+
+static int s32_pinctrl_probe_dt(struct platform_device *pdev,
+ struct s32_pinctrl *ipctl)
+{
+ struct s32_pinctrl_soc_info *info = ipctl->info;
+ struct device_node *np = s32_get_np(ipctl);
+ u32 nfuncs = 0, i = 0;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ for_each_child_of_node_scoped(np, child)
+ if (strncmp(child->name, NVMEM_LAYOUT, sizeof(NVMEM_LAYOUT)))
+ ++nfuncs;
if (nfuncs <= 0)
return dev_err_probe(&pdev->dev, -EINVAL,
"No functions defined\n");
@@ -904,15 +967,18 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
info->ngroups = 0;
for_each_child_of_node_scoped(np, child)
- info->ngroups += of_get_child_count(child);
+ if (strncmp(child->name, NVMEM_LAYOUT, sizeof(NVMEM_LAYOUT)))
+ info->ngroups += of_get_child_count(child);
info->groups = devm_kcalloc(&pdev->dev, info->ngroups,
sizeof(*info->groups), GFP_KERNEL);
if (!info->groups)
return -ENOMEM;
- i = 0;
for_each_child_of_node_scoped(np, child) {
+ if (!strncmp(child->name, NVMEM_LAYOUT, sizeof(NVMEM_LAYOUT)))
+ continue;
+
ret = s32_pinctrl_parse_functions(child, info, i++);
if (ret)
return ret;
@@ -968,12 +1034,28 @@ int s32_pinctrl_probe(struct platform_device *pdev,
s32_pinctrl_desc->confops = &s32_pinconf_ops;
s32_pinctrl_desc->owner = THIS_MODULE;
+ ipctl->regions = devm_kcalloc(&pdev->dev, soc_data->mem_regions,
+ sizeof(*ipctl->regions), GFP_KERNEL);
+ if (!ipctl->regions)
+ return -ENOMEM;
+
+ ipctl->legacy = soc_data->legacy;
+ if (soc_data->legacy)
+ ret = legacy_s32_pinctrl_regmap_init(pdev, ipctl);
+ else
+ ret = s32_pinctrl_mfd_regmap_init(pdev, ipctl);
+
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to init driver regmap!\n");
+
ret = s32_pinctrl_probe_dt(pdev, ipctl);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Fail to probe dt properties\n");
- ret = devm_pinctrl_register_and_init(&pdev->dev, s32_pinctrl_desc,
+ ret = devm_pinctrl_register_and_init(s32_get_dev(ipctl),
+ s32_pinctrl_desc,
ipctl, &ipctl->pctl);
if (ret)
return dev_err_probe(&pdev->dev, ret,
diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c
index c49d28793b69..2d56ffb1a109 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, 2024-2025 NXP
* Copyright (C) 2022 SUSE LLC
*/
@@ -762,7 +762,7 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = {
S32_PINCTRL_PIN(S32G_IMCR_SIUL_EIRQ31),
};
-static const struct s32_pin_range s32_pin_ranges_siul2[] = {
+static const struct s32_pin_range legacy_s32_pin_ranges_siul2[] = {
/* MSCR pin ID ranges */
S32_PIN_RANGE(0, 101),
S32_PIN_RANGE(112, 122),
@@ -773,27 +773,47 @@ 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_pinctrl_soc_data legacy_s32_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),
+ .mem_pin_ranges = legacy_s32_pin_ranges_siul2,
+ .mem_regions = ARRAY_SIZE(legacy_s32_pin_ranges_siul2),
+ .legacy = true,
};
static const struct of_device_id s32_pinctrl_of_match[] = {
{
.compatible = "nxp,s32g2-siul2-pinctrl",
- .data = &s32_pinctrl_data,
+ .data = &legacy_s32_pinctrl_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, s32_pinctrl_of_match);
+static const struct s32_pin_range s32_pin_ranges_siul2[] = {
+ /* MSCR pin ID ranges */
+ S32_PIN_RANGE(0, 101),
+ S32_PIN_RANGE(112, 190),
+ /* IMCR pin ID ranges */
+ S32_PIN_RANGE(512, 595),
+ S32_PIN_RANGE(631, 1007),
+};
+
+static const struct s32_pinctrl_soc_data s32_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),
+ .legacy = false,
+};
+
static int s32g_pinctrl_probe(struct platform_device *pdev)
{
const struct s32_pinctrl_soc_data *soc_data;
soc_data = of_device_get_match_data(&pdev->dev);
+ if (!soc_data)
+ soc_data = &s32_pinctrl_data;
return s32_pinctrl_probe(pdev, soc_data);
}
--
2.45.2
Powered by blists - more mailing lists