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@oss.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
Hi Andrei, kernel test robot noticed the following build warnings: [auto build test WARNING on linusw-pinctrl/devel] [also build test WARNING on linusw-pinctrl/for-next lee-mfd/for-mfd-next lee-mfd/for-mfd-fixes linus/master v6.16-rc5] [cannot apply to shawnguo/for-next next-20250710] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Andrei-Stefanescu/dt-bindings-mfd-add-support-for-the-NXP-SIUL2-module/20250710-222538 base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git devel patch link: https://lore.kernel.org/r/20250710142038.1986052-8-andrei.stefanescu%40oss.nxp.com patch subject: [PATCH v7 07/12] pinctrl: s32g2: change the driver to also be probed as an MFD cell config: arm64-randconfig-003-20250711 (https://download.01.org/0day-ci/archive/20250711/202507111841.QdQ2DVpT-lkp@intel.com/config) compiler: aarch64-linux-gcc (GCC) 12.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250711/202507111841.QdQ2DVpT-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202507111841.QdQ2DVpT-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from include/linux/bits.h:32, from include/linux/bitops.h:6, from drivers/pinctrl/nxp/pinctrl-s32cc.c:10: drivers/pinctrl/nxp/pinctrl-s32cc.c: In function 'to_s32_pinctrl': include/linux/container_of.h:20:54: error: 'struct s32_pinctrl' has no member named 'gc' 20 | static_assert(__same_type(*(ptr), ((type *)0)->member) || \ | ^~ include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert' 78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg) | ^~~~ include/linux/container_of.h:20:9: note: in expansion of macro 'static_assert' 20 | static_assert(__same_type(*(ptr), ((type *)0)->member) || \ | ^~~~~~~~~~~~~ include/linux/container_of.h:20:23: note: in expansion of macro '__same_type' 20 | static_assert(__same_type(*(ptr), ((type *)0)->member) || \ | ^~~~~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c:706:16: note: in expansion of macro 'container_of' 706 | return container_of(chip, struct s32_pinctrl, gc); | ^~~~~~~~~~~~ include/linux/compiler_types.h:503:27: error: expression in static assertion is not an integer 503 | #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/build_bug.h:78:56: note: in definition of macro '__static_assert' 78 | #define __static_assert(expr, msg, ...) _Static_assert(expr, msg) | ^~~~ include/linux/container_of.h:20:9: note: in expansion of macro 'static_assert' 20 | static_assert(__same_type(*(ptr), ((type *)0)->member) || \ | ^~~~~~~~~~~~~ include/linux/container_of.h:20:23: note: in expansion of macro '__same_type' 20 | static_assert(__same_type(*(ptr), ((type *)0)->member) || \ | ^~~~~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c:706:16: note: in expansion of macro 'container_of' 706 | return container_of(chip, struct s32_pinctrl, gc); | ^~~~~~~~~~~~ In file included from include/uapi/linux/posix_types.h:5, from include/uapi/linux/types.h:14, from include/linux/types.h:6, from include/linux/kasan-checks.h:5, from include/asm-generic/rwonce.h:26, from arch/arm64/include/asm/rwonce.h:67, from include/linux/compiler.h:390, from include/linux/build_bug.h:5: include/linux/stddef.h:16:33: error: 'struct s32_pinctrl' has no member named 'gc' 16 | #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) | ^~~~~~~~~~~~~~~~~~ include/linux/container_of.h:23:28: note: in expansion of macro 'offsetof' 23 | ((type *)(__mptr - offsetof(type, member))); }) | ^~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c:706:16: note: in expansion of macro 'container_of' 706 | return container_of(chip, struct s32_pinctrl, gc); | ^~~~~~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c: In function 'legacy_s32_pinctrl_regmap_init': >> drivers/pinctrl/nxp/pinctrl-s32cc.c:873:44: warning: variable 'soc_data' set but not used [-Wunused-but-set-variable] 873 | const struct s32_pinctrl_soc_data *soc_data; | ^~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c: In function 's32_pinctrl_mfd_regmap_init': drivers/pinctrl/nxp/pinctrl-s32cc.c:920:44: warning: variable 'soc_data' set but not used [-Wunused-but-set-variable] 920 | const struct s32_pinctrl_soc_data *soc_data; | ^~~~~~~~ drivers/pinctrl/nxp/pinctrl-s32cc.c: At top level: drivers/pinctrl/nxp/pinctrl-s32cc.c:704:28: warning: 'to_s32_pinctrl' defined but not used [-Wunused-function] 704 | static struct s32_pinctrl *to_s32_pinctrl(struct gpio_chip *chip) | ^~~~~~~~~~~~~~ vim +/soc_data +873 drivers/pinctrl/nxp/pinctrl-s32cc.c 868 869 static int legacy_s32_pinctrl_regmap_init(struct platform_device *pdev, 870 struct s32_pinctrl *ipctl) 871 { 872 struct s32_pinctrl_soc_info *info = ipctl->info; > 873 const struct s32_pinctrl_soc_data *soc_data; 874 unsigned int mem_regions; 875 struct resource *res; 876 struct regmap *map; 877 void __iomem *base; 878 u32 i = 0; 879 880 soc_data = info->soc_data; 881 882 mem_regions = info->soc_data->mem_regions; 883 if (mem_regions == 0 || mem_regions >= 10000) 884 return dev_err_probe(&pdev->dev, -EINVAL, 885 "mem_regions is invalid: %u\n", 886 mem_regions); 887 888 for (i = 0; i < mem_regions; i++) { 889 base = devm_platform_get_and_ioremap_resource(pdev, i, &res); 890 if (IS_ERR(base)) 891 return PTR_ERR(base); 892 893 snprintf(ipctl->regions[i].name, 894 sizeof(ipctl->regions[i].name), "map%u", i); 895 896 s32_regmap_config.name = ipctl->regions[i].name; 897 s32_regmap_config.max_register = resource_size(res) - 898 s32_regmap_config.reg_stride; 899 900 map = devm_regmap_init_mmio(&pdev->dev, base, 901 &s32_regmap_config); 902 if (IS_ERR(map)) { 903 dev_err(&pdev->dev, "Failed to init regmap[%u]\n", i); 904 return PTR_ERR(map); 905 } 906 907 ipctl->regions[i].map = map; 908 ipctl->regions[i].pin_range = &info->soc_data->mem_pin_ranges[i]; 909 } 910 911 return 0; 912 } 913 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.