[PATCH v6 4/7] pinctrl: s32: convert the driver into an mfd cell

Andrei Stefanescu
2024-11-13T10:12:43Z

The SIUL2 module is now represented as an mfd device. The pinctrl driver
is now an mfd_cell. Therefore, remove its compatible and adjust its
probing in order to get the necessary information from its mfd parent.

This change came as a result of upstream review in the following series:
https://lore.kernel.org/linux-gpio/a924bbb6-96ec-40be-9d82-a76b2ab73afd@oss.nxp.com/
https://lore.kernel.org/all/20240926143122.1385658-3-andrei.stefanescu@oss.nxp.com/

The SIUL2 module has multiple capabilities. It has support for reading
SoC information, pinctrl and GPIO. All of this functionality is part of
the same register space. The initial pinctrl driver treated the pinctrl
functionality as separate from the GPIO one. However, they do rely on
common registers and a long, detailed and specific register range list
would be required for pinctrl&GPIO (carving out the necessary memory
for each function). Moreover, in some cases this wouldn't be enough. For
example reading a GPIO's direction would require a read of the MSCR
register corresponding to that pin. This would not be possible in the
GPIO driver because all of the MSCR registers are referenced by the
pinctrl driver.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32.h | 3 +-
drivers/pinctrl/nxp/pinctrl-s32cc.c | 143 ++++++++++++----------------
drivers/pinctrl/nxp/pinctrl-s32g2.c | 25 +----
3 files changed, 66 insertions(+), 105 deletions(-)

diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h
index add3c77ddfed..d52c6f814de8 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, 2024 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
@@ -38,6 +38,7 @@ struct s32_pinctrl_soc_data {
const struct pinctrl_pin_desc *pins;
unsigned int npins;
const struct s32_pin_range *mem_pin_ranges;
+ const struct regmap **regmaps;
unsigned int mem_regions;
};

diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 501eb296c760..bb2f8127c2b7 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>
@@ -44,12 +45,6 @@ enum s32_write_type {
S32_PINCONF_OVERWRITE,
};

-static struct regmap_config s32_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
-};
-
static u32 get_pin_no(u32 pinmux)
{
return (pinmux & S32_PIN_ID_MASK) >> S32_PIN_ID_SHIFT;
@@ -85,14 +80,15 @@ 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_configs_lock: lock for the `gpio_configs` list
+ * @saved_context: Configuration saved over system sleep
*/
struct s32_pinctrl {
struct device *dev;
@@ -123,14 +119,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,
- unsigned int pin, unsigned int *val)
+static int s32_regmap_read(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned int *val)
{
struct s32_pinctrl_mem_region *region;
unsigned int offset;
@@ -145,7 +140,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 +158,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;
@@ -236,10 +231,10 @@ static int s32_dt_group_node_to_map(struct pinctrl_dev *pctldev,
}

ret = pinconf_generic_parse_dt_config(np, pctldev, &cfgs, &n_cfgs);
- if (ret) {
- dev_err(dev, "%pOF: could not parse node property\n", np);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "%pOF: could not parse node property\n",
+ np);

if (n_cfgs)
reserve++;
@@ -321,7 +316,7 @@ static int s32_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector,
/* Check beforehand so we don't have a partial config. */
for (i = 0; i < grp->data.npins; i++) {
if (s32_check_pin(pctldev, grp->data.pins[i]) != 0) {
- dev_err(info->dev, "invalid pin: %u in group: %u\n",
+ dev_err(info->dev, "Invalid pin: %u in group: %u\n",
grp->data.pins[i], group);
return -EINVAL;
}
@@ -475,8 +470,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:
@@ -762,15 +757,15 @@ static int s32_pinctrl_parse_groups(struct device_node *np,
grp->data.name = np->name;

npins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32));
- if (npins < 0) {
- dev_err(dev, "Failed to read 'pinmux' property in node %s.\n",
- grp->data.name);
- return -EINVAL;
- }
- if (!npins) {
- dev_err(dev, "The group %s has no pins.\n", grp->data.name);
- return -EINVAL;
- }
+ if (npins < 0)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to read 'pinmux' in node %s\n",
+ grp->data.name);
+
+ if (!npins)
+ return dev_err_probe(dev, -EINVAL,
+ "The group %s has no pins\n",
+ grp->data.name);

grp->data.npins = npins;

@@ -811,11 +806,9 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
/* Initialise function */
func->name = np->name;
func->ngroups = of_get_child_count(np);
- if (func->ngroups == 0) {
- dev_err(info->dev, "no groups defined in %pOF\n", np);
- return -EINVAL;
- }
-
+ if (func->ngroups == 0)
+ return dev_err_probe(info->dev, -EINVAL,
+ "No groups defined in %pOF\n", np);
groups = devm_kcalloc(info->dev, func->ngroups,
sizeof(*func->groups), GFP_KERNEL);
if (!groups)
@@ -838,57 +831,42 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
static int s32_pinctrl_probe_dt(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;
- struct device_node *np = pdev->dev.of_node;
- struct resource *res;
- struct regmap *map;
- void __iomem *base;
- unsigned int mem_regions = info->soc_data->mem_regions;
+ unsigned int mem_regions;
+ struct device_node *np;
+ u32 nfuncs = 0, i = 0, j;
+ u8 regmap_type;
int ret;
- u32 nfuncs = 0;
- u32 i = 0;

+ np = pdev->dev.parent->of_node;
if (!np)
return -ENODEV;

- if (mem_regions == 0 || mem_regions >= 10000) {
- dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions);
- return -EINVAL;
- }
+ /* 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);

ipctl->regions = devm_kcalloc(&pdev->dev, mem_regions,
sizeof(*ipctl->regions), GFP_KERNEL);
if (!ipctl->regions)
return -ENOMEM;

+ /* Order is MSCR regions first, then IMCR ones */
for (i = 0; i < mem_regions; i++) {
- base = devm_platform_get_and_ioremap_resource(pdev, i, &res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- snprintf(ipctl->regions[i].name,
- sizeof(ipctl->regions[i].name), "map%u", i);
-
- s32_regmap_config.name = ipctl->regions[i].name;
- s32_regmap_config.max_register = resource_size(res) -
- s32_regmap_config.reg_stride;
-
- map = devm_regmap_init_mmio(&pdev->dev, base,
- &s32_regmap_config);
- if (IS_ERR(map)) {
- dev_err(&pdev->dev, "Failed to init regmap[%u]\n", i);
- return PTR_ERR(map);
- }
-
- ipctl->regions[i].map = map;
+ 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];
}

nfuncs = of_get_child_count(np);
- if (nfuncs <= 0) {
- dev_err(&pdev->dev, "no functions defined\n");
- return -EINVAL;
- }
+ if (nfuncs <= 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "No functions defined\n");

info->nfunctions = nfuncs;
info->functions = devm_kcalloc(&pdev->dev, nfuncs,
@@ -918,18 +896,17 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
int s32_pinctrl_probe(struct platform_device *pdev,
const struct s32_pinctrl_soc_data *soc_data)
{
- struct s32_pinctrl *ipctl;
- int ret;
- struct pinctrl_desc *s32_pinctrl_desc;
- struct s32_pinctrl_soc_info *info;
#ifdef CONFIG_PM_SLEEP
struct s32_pinctrl_context *saved_context;
#endif
+ struct pinctrl_desc *s32_pinctrl_desc;
+ struct s32_pinctrl_soc_info *info;
+ struct s32_pinctrl *ipctl;
+ int ret;

- if (!soc_data || !soc_data->pins || !soc_data->npins) {
- dev_err(&pdev->dev, "wrong pinctrl info\n");
- return -EINVAL;
- }
+ if (!soc_data || !soc_data->pins || !soc_data->npins)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Wrong pinctrl info\n");

info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -964,17 +941,15 @@ int s32_pinctrl_probe(struct platform_device *pdev,
s32_pinctrl_desc->owner = THIS_MODULE;

ret = s32_pinctrl_probe_dt(pdev, ipctl);
- if (ret) {
- dev_err(&pdev->dev, "fail to probe dt properties\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed 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");
-
+ "Could not register s32 pinctrl driver\n");
#ifdef CONFIG_PM_SLEEP
saved_context = &ipctl->saved_context;
saved_context->pads =
diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c
index 440ff1879424..27669991c339 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32g2.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c
@@ -3,13 +3,14 @@
* NXP S32G pinctrl driver
*
* Copyright 2015-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018, 2020-2022 NXP
+ * Copyright 2017-2018, 2020-2022, 2024 NXP
* Copyright (C) 2022 SUSE LLC
*/

#include <linux/err.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>
@@ -713,12 +714,10 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = {
static const struct s32_pin_range s32_pin_ranges_siul2[] = {
/* MSCR pin ID ranges */
S32_PIN_RANGE(0, 101),
- S32_PIN_RANGE(112, 122),
- S32_PIN_RANGE(144, 190),
+ S32_PIN_RANGE(112, 190),
/* IMCR pin ID ranges */
S32_PIN_RANGE(512, 595),
- S32_PIN_RANGE(631, 909),
- S32_PIN_RANGE(942, 1007),
+ S32_PIN_RANGE(631, 1007),
};

static const struct s32_pinctrl_soc_data s32_pinctrl_data = {
@@ -728,22 +727,9 @@ static const struct s32_pinctrl_soc_data s32_pinctrl_data = {
.mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2),
};

-static const struct of_device_id s32_pinctrl_of_match[] = {
- {
- .compatible = "nxp,s32g2-siul2-pinctrl",
- .data = &s32_pinctrl_data,
- },
- { /* sentinel */ }
-};
-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;
-
- soc_data = of_device_get_match_data(&pdev->dev);
-
- return s32_pinctrl_probe(pdev, soc_data);
+ return s32_pinctrl_probe(pdev, &s32_pinctrl_data);
}

static const struct dev_pm_ops s32g_pinctrl_pm_ops = {
@@ -753,7 +739,6 @@ static const struct dev_pm_ops s32g_pinctrl_pm_ops = {
static struct platform_driver s32g_pinctrl_driver = {
.driver = {
.name = "s32g-siul2-pinctrl",
- .of_match_table = s32_pinctrl_of_match,
.pm = pm_sleep_ptr(&s32g_pinctrl_pm_ops),
.suppress_bind_attrs = true,
},
--
2.45.2