diff mbox series

[1/6] pinctrl: ls1012a: Add pinctrl driver support

Message ID 8cd0b743-4fff-e17f-9543-d2d4d7879758@digi.com
State New
Headers show
Series [1/6] pinctrl: ls1012a: Add pinctrl driver support | expand

Commit Message

David Leonard Aug. 27, 2024, 2:05 a.m. UTC
Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert
GPIO control over the second I2C bus.

Signed-off-by: David Leonard <David.Leonard@digi.com>
---
  drivers/pinctrl/freescale/Kconfig           |   8 +
  drivers/pinctrl/freescale/Makefile          |   1 +
  drivers/pinctrl/freescale/pinctrl-ls1012a.c | 381 ++++++++++++++++++++
  3 files changed, 390 insertions(+)
  create mode 100644 drivers/pinctrl/freescale/pinctrl-ls1012a.c

Comments

Frank Li Aug. 27, 2024, 6:14 p.m. UTC | #1
On Tue, Aug 27, 2024 at 02:12:04PM -0400, Frank Li wrote:
> On Tue, Aug 27, 2024 at 12:05:24PM +1000, David Leonard wrote:
> >
> > Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert
> > GPIO control over the second I2C bus.
> >
> > Signed-off-by: David Leonard <David.Leonard@digi.com>
> > ---
>
> Why not use pinctrl-single ?
>
> You can ref arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
>
> It did similar thing to use GPIO recover i2c bus.
>
> Just need change dts file.

Next time, please cc: imx@lists.linux.dev

Frank

>
> Frank
>
>
> >  drivers/pinctrl/freescale/Kconfig           |   8 +
> >  drivers/pinctrl/freescale/Makefile          |   1 +
> >  drivers/pinctrl/freescale/pinctrl-ls1012a.c | 381 ++++++++++++++++++++
> >  3 files changed, 390 insertions(+)
> >  create mode 100644 drivers/pinctrl/freescale/pinctrl-ls1012a.c
> >
> > diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> > index 3b59d7189004..a2038042eeae 100644
> > --- a/drivers/pinctrl/freescale/Kconfig
> > +++ b/drivers/pinctrl/freescale/Kconfig
> > @@ -209,6 +209,14 @@ config PINCTRL_IMX93
> >  	help
> >  	  Say Y here to enable the imx93 pinctrl driver
> >
> > +config PINCTRL_LS1012A
> > +	tristate "LS1012A pinctrl driver"
> > +	depends on ARCH_LAYERSCAPE && OF || COMPILE_TEST
> > +	select PINMUX
> > +	select GENERIC_PINCONF
> > +	help
> > +	  Say Y here to enable the ls1012a pinctrl driver
> > +
> >  config PINCTRL_VF610
> >  	bool "Freescale Vybrid VF610 pinctrl driver"
> >  	depends on SOC_VF610
> > diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
> > index d27085c2b4c4..6926529d8635 100644
> > --- a/drivers/pinctrl/freescale/Makefile
> > +++ b/drivers/pinctrl/freescale/Makefile
> > @@ -35,3 +35,4 @@ obj-$(CONFIG_PINCTRL_IMX25)	+= pinctrl-imx25.o
> >  obj-$(CONFIG_PINCTRL_IMX28)	+= pinctrl-imx28.o
> >  obj-$(CONFIG_PINCTRL_IMXRT1050)	+= pinctrl-imxrt1050.o
> >  obj-$(CONFIG_PINCTRL_IMXRT1170)	+= pinctrl-imxrt1170.o
> > +obj-$(CONFIG_PINCTRL_LS1012A)	+= pinctrl-ls1012a.o
> > diff --git a/drivers/pinctrl/freescale/pinctrl-ls1012a.c b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
> > new file mode 100644
> > index 000000000000..d4c535ed6c07
> > --- /dev/null
> > +++ b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
> > @@ -0,0 +1,381 @@
> > +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> > +/*
> > + * Pin controller for NXP QorIQ LS1012A.
> > + *
> > + * Copyright (c) 2024 Digi International, Inc.
> > + * Author: David Leonard <David.Leonard@digi.com>
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/pinctrl/pinctrl.h>
> > +#include <linux/pinctrl/pinmux.h>
> > +#include <linux/pinctrl/pinconf-generic.h>
> > +#include <linux/of.h>
> > +#include <linux/io.h>
> > +#include <linux/regmap.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/sys_soc.h>
> > +
> > +struct ls1012a_pinctrl_pdata {
> > +	struct pinctrl_dev *pctl_dev;
> > +	void __iomem *cr0mem;
> > +	bool big_endian;
> > +	u32 ssc;
> > +};
> > +
> > +/* Bitfield macros for masks and values that follow the datasheet's
> > + * bit numbering schemes for registers of different bit-endianess. */
> > +#define BITV_BE(hi, v)	((v) << (31 - (hi) % 32))
> > +#define BITM_BE(hi, lo)	(((1 << ((hi) - (lo) + 1)) - 1) << (31 - (hi) % 32))
> > +#define BITV_LE(lo, v)	((v) << ((lo) % 32))
> > +#define BITM_LE(lo, hi)	(((1 << ((hi) - (lo) + 1)) - 1) << ((lo) % 32))
> > +
> > +/* SCFG PMUXCR0 pinmux control register */
> > +#define SCFG_PMUXCR0			0x430
> > +#define QSPI_MUX_OVRD_MASK		BITM_BE(0, 0)	/* [0] */
> > +#define QSPI_MUX_DISABLE		BITV_BE(0, 0)	/*  use RCW */
> > +#define QSPI_MUX_ENABLE			BITV_BE(0, 1)	/*  use PMUXCR0 */
> > +#define QSPI_DATA0_GPIO_OVR_MASK	BITM_BE(1, 1)	/* [1] */
> > +#define QSPI_DATA0_GPIO_SEL_SPI		BITV_BE(1, 0)	/*  DATA0,SCK,CS0 */
> > +#define QSPI_DATA0_GPIO_SEL_GPIO	BITV_BE(1, 1)	/*  GPIO1[4,11,5] */
> > +#define QSPI_DATA1_GPIO_OVR_MASK	BITM_BE(3, 2)	/* [3:2] */
> > +#define QSPI_DATA1_GPIO_SEL_SPI		BITV_BE(3, 0)	/*  DATA1 */
> > +#define QSPI_DATA1_GPIO_SEL_GPIO	BITV_BE(3, 1)	/*  GPIO1[12] */
> > +#define QSPI_IIC2_OVR_MASK		BITM_BE(5, 4)	/* [5:4] */
> > +#define QSPI_IIC2_SEL_GPIO		BITV_BE(5, 0)	/*  GPIO1[13,14] */
> > +#define QSPI_IIC2_SEL_I2C		BITV_BE(5, 1)	/*  SCL,SDA (rev0) */
> > +#define QSPI_IIC2_SEL_SPI		BITV_BE(5, 2)	/*  DATA2,DATA3 */
> > +
> > +/* RCW SoC-specific configuration (read-only) */
> > +#define DCFG_RCWSR			0x100
> > +#define SOC_SPEC_CONFIG			416		/* word 13 */
> > +#define DCFG_SSC_REG			(DCFG_RCWSR + SOC_SPEC_CONFIG / 8)
> > +#define SSC_DATA0_GPIO_MASK		BITM_LE(421, 421)
> > +#define SSC_DATA0_GPIO_SEL_SPI		BITV_LE(421, 0)	/*  DATA0,SCK,CS0 */
> > +#define SSC_DATA0_GPIO_SEL_GPIO		BITV_LE(421, 1)	/*  GPIO1[11,4,5] */
> > +#define SSC_DATA1_GPIO_MASK		BITM_LE(422, 423)
> > +#define SSC_DATA1_GPIO_SEL_SPI		BITV_LE(422, 0)	/*  DATA1 */
> > +#define SSC_DATA1_GPIO_SEL_GPIO		BITV_LE(422, 2)	/*  GPIO1[12] */
> > +#define SSC_IIC2_MASK			BITM_LE(424, 425)
> > +#define SSC_IIC2_SEL_GPIO		BITV_LE(424, 0)	/*  GPIO1[13,14] */
> > +#define SSC_IIC2_SEL_I2C		BITV_LE(424, 2)	/*  SCL,SDA */
> > +#define SSC_IIC2_SEL_SPI		BITV_LE(424, 1)	/*  DATA2,DATA3 */
> > +#define SSC_IIC2_SEL_GPIO_RESET		BITV_LE(424, 3)	/*  GPIO1[13],RESET_REQ_B*/
> > +
> > +const struct pinctrl_pin_desc ls1012a_pins[] = {
> > +	PINCTRL_PIN(60, "QSPI_A_DATA3/GPIO1_14/IIC2_SDA/RESET_REQ_B"),
> > +	PINCTRL_PIN(61, "QSPI_A_DATA1/GPIO1_12"),
> > +	PINCTRL_PIN(62, "QSPI_A_SCK/GPIO1_04"),
> > +	PINCTRL_PIN(122, "QSPI_A_DATA2/GPIO1_13/IIC2_SCL"),
> > +	PINCTRL_PIN(123, "QSPI_A_DATA0/GPIO1_11"),
> > +	PINCTRL_PIN(124, "QSPI_A_CS0/GPIO1_05"),
> > +};
> > +
> > +static const unsigned int qspi_1_grp[] = { 62, 123, 124 };
> > +static const unsigned int qspi_2_grp[] = { 61 };
> > +static const unsigned int qspi_3_grp[] = { 122, 60 };
> > +
> > +#define GRP_qspi_1	0	/* SCK,CS0,DATA0 */
> > +#define GRP_qspi_2	1	/* DATA1 */
> > +#define GRP_qspi_3	2	/* DATA2,DATA3 */
> > +#define _GRP_max	3
> > +
> > +#define _PINGROUP(name) \
> > +	[GRP_##name] = PINCTRL_PINGROUP(#name "_grp", name##_grp, ARRAY_SIZE(name##_grp))
> > +static const struct pingroup ls1012a_groups[] = {
> > +	_PINGROUP(qspi_1),
> > +	_PINGROUP(qspi_2),
> > +	_PINGROUP(qspi_3),
> > +};
> > +
> > +
> > +static void ls1012a_write_cr0(struct ls1012a_pinctrl_pdata *pd, u32 val)
> > +{
> > +	if (pd->big_endian)
> > +		iowrite32be(val, pd->cr0mem);
> > +	else
> > +		iowrite32(val, pd->cr0mem);
> > +}
> > +
> > +static u32 ls1012a_read_cr0(struct ls1012a_pinctrl_pdata *pd)
> > +{
> > +	return pd->big_endian ? ioread32be(pd->cr0mem) : ioread32(pd->cr0mem);
> > +}
> > +
> > +static int ls1012a_get_groups_count(struct pinctrl_dev *pcdev)
> > +{
> > +	return ARRAY_SIZE(ls1012a_groups);
> > +}
> > +
> > +static const char *ls1012a_get_group_name(struct pinctrl_dev *pcdev,
> > +	unsigned int selector)
> > +{
> > +	return ls1012a_groups[selector].name;
> > +}
> > +
> > +static int ls1012a_get_group_pins(struct pinctrl_dev *pcdev,
> > +	unsigned int selector, const unsigned int **pins, unsigned int *npins)
> > +{
> > +	*pins = ls1012a_groups[selector].pins;
> > +	*npins = ls1012a_groups[selector].npins;
> > +	return 0;
> > +}
> > +
> > +static const struct pinctrl_ops ls1012a_pinctrl_ops = {
> > +	.get_groups_count = ls1012a_get_groups_count,
> > +	.get_group_name = ls1012a_get_group_name,
> > +	.get_group_pins = ls1012a_get_group_pins,
> > +	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
> > +	.dt_free_map = pinconf_generic_dt_free_map,
> > +};
> > +
> > +static const char * const i2c_groups[] = { "qspi_3_grp" };
> > +static const char * const spi_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
> > +static const char * const gpio_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
> > +static const char * const gpio_reset_groups[] = { "qspi_3_grp" };
> > +
> > +#define FUNC_i2c	0
> > +#define FUNC_spi	1
> > +#define FUNC_gpio	2
> > +#define FUNC_gpio_reset 3
> > +#define _FUNC_max	4
> > +
> > +#define _PINFUNC(name) \
> > +	[FUNC_##name] = PINCTRL_PINFUNCTION(#name, name##_groups, ARRAY_SIZE(name##_groups))
> > +static const struct pinfunction ls1012a_functions[] = {
> > +	_PINFUNC(i2c),
> > +	_PINFUNC(spi),
> > +	_PINFUNC(gpio),
> > +	_PINFUNC(gpio_reset),
> > +};
> > +
> > +static int ls1012a_get_functions_count(struct pinctrl_dev *pctldev)
> > +{
> > +	return ARRAY_SIZE(ls1012a_functions);
> > +}
> > +
> > +static const char *ls1012a_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
> > +{
> > +	return ls1012a_functions[func].name;
> > +}
> > +
> > +static int ls1012a_get_function_groups(struct pinctrl_dev *pctldev, unsigned int func,
> > +	const char * const **groups,
> > +	unsigned int * const ngroups)
> > +{
> > +	*groups = ls1012a_functions[func].groups;
> > +	*ngroups = ls1012a_functions[func].ngroups;
> > +	return 0;
> > +}
> > +
> > +/*
> > + * LS1012A
> > + *    Group: qspi_1             qspi_2      qspi_3
> > + *           ================== =========== =============
> > + *    Pin:   62    123    124   61          122    60
> > + *           ----- ------ ----- ----------- ------ ------
> > + * i2c                                      SCL    SDA    (RCW only)
> > + * spi       SCK   DATA0
> > + * spi       SCK   DATA0        DATA1
> > + * spi       SCK   DATA0        DATA1       DATA2  DATA3
> > + * gpio      GPIO4 GPIO11 GPIO5
> > + * gpio                         GPIO12
> > + * gpio                                     GPIO13 GPIO14
> > + * gpio_reset                               GPIO13 REQ_B  (RCW only)
> > + */
> > +
> > +static const struct ls1012a_func_mux {
> > +	u32 cr0mask, cr0; /* mux control */
> > +	u32 sscmask, ssc; /* equivalent in RCW */
> > +} ls1012a_func_mux[_FUNC_max][_GRP_max] = {
> > +	[FUNC_i2c] = {
> > +		[GRP_qspi_3] = {
> > +			.sscmask = SSC_IIC2_MASK,
> > +			.ssc =     SSC_IIC2_SEL_I2C,
> > +		},
> > +	},
> > +	[FUNC_spi] = {
> > +		[GRP_qspi_1] = {
> > +			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
> > +			.cr0 =     QSPI_DATA0_GPIO_SEL_SPI,
> > +			.sscmask = SSC_DATA0_GPIO_MASK,
> > +			.ssc =     SSC_DATA0_GPIO_SEL_SPI
> > +		},
> > +		[GRP_qspi_2] = {
> > +			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
> > +			.cr0 =     QSPI_DATA1_GPIO_SEL_SPI,
> > +			.sscmask = SSC_DATA1_GPIO_MASK,
> > +			.ssc =     SSC_DATA1_GPIO_SEL_SPI,
> > +		},
> > +		[GRP_qspi_3] = {
> > +			.cr0mask = QSPI_IIC2_OVR_MASK,
> > +			.cr0 =     QSPI_IIC2_SEL_SPI,
> > +			.sscmask = SSC_IIC2_MASK,
> > +			.ssc =     SSC_IIC2_SEL_SPI,
> > +		},
> > +	},
> > +	[FUNC_gpio] = {
> > +		[GRP_qspi_1] = {
> > +			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
> > +			.cr0 =     QSPI_DATA0_GPIO_SEL_GPIO,
> > +			.sscmask = SSC_DATA0_GPIO_MASK,
> > +			.ssc =     SSC_DATA0_GPIO_SEL_GPIO,
> > +		},
> > +		[GRP_qspi_2] = {
> > +			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
> > +			.cr0 =     QSPI_DATA1_GPIO_SEL_GPIO,
> > +			.sscmask = SSC_DATA1_GPIO_MASK,
> > +			.ssc =     SSC_DATA1_GPIO_SEL_GPIO,
> > +		},
> > +		[GRP_qspi_3] = {
> > +			.cr0mask = QSPI_IIC2_OVR_MASK,
> > +			.cr0 =     QSPI_IIC2_SEL_GPIO,
> > +			.sscmask = SSC_IIC2_MASK,
> > +			.ssc =     SSC_IIC2_SEL_GPIO,
> > +		},
> > +	},
> > +	[FUNC_gpio_reset] = {
> > +		[GRP_qspi_3] = {
> > +			.sscmask = SSC_IIC2_MASK,
> > +			.ssc =     SSC_IIC2_SEL_GPIO_RESET,
> > +		},
> > +	},
> > +};
> > +
> > +static int ls1012a_set_mux(struct pinctrl_dev *pcdev,
> > +	unsigned int func, unsigned int group)
> > +{
> > +	struct ls1012a_pinctrl_pdata *pd = pinctrl_dev_get_drvdata(pcdev);
> > +	const struct ls1012a_func_mux *fm = &ls1012a_func_mux[func][group];
> > +	u32 cr0 = ls1012a_read_cr0(pd);
> > +
> > +	if (!fm->cr0mask) {
> > +		if ((pd->ssc & fm->sscmask) != fm->ssc)
> > +			return -EOPNOTSUPP;
> > +		cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_DISABLE;
> > +	} else {
> > +		cr0 = (cr0 & ~fm->cr0mask) | fm->cr0;
> > +		if ((pd->ssc & fm->sscmask) != fm->ssc)
> > +			cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_ENABLE;
> > +	}
> > +	ls1012a_write_cr0(pd, cr0);
> > +	return 0;
> > +}
> > +
> > +static void ls1012a_init_mux(struct ls1012a_pinctrl_pdata *pd)
> > +{
> > +	unsigned int func, group;
> > +	const struct ls1012a_func_mux *fm;
> > +	u32 cr0;
> > +
> > +	cr0 = ls1012a_read_cr0(pd);
> > +	if ((cr0 & QSPI_MUX_OVRD_MASK) == QSPI_MUX_DISABLE) {
> > +		/*
> > +		 * Prepare a disabled MUXCR0 to have a same/similar
> > +		 * configuration as RCW SSC, and leave it disabled.
> > +		 */
> > +		for (func = 0; func < _FUNC_max; func++) {
> > +			for (group = 0; group < _GRP_max; group++) {
> > +				fm = &ls1012a_func_mux[func][group];
> > +				if (fm->sscmask &&
> > +				    fm->ssc == (pd->ssc & fm->sscmask)) {
> > +					cr0 &= ~fm->cr0mask;
> > +					cr0 |= fm->cr0;
> > +				}
> > +			}
> > +		}
> > +		ls1012a_write_cr0(pd, cr0);
> > +	}
> > +}
> > +
> > +static const struct pinmux_ops ls1012a_pinmux_ops = {
> > +	.get_functions_count = ls1012a_get_functions_count,
> > +	.get_function_name = ls1012a_get_function_name,
> > +	.get_function_groups = ls1012a_get_function_groups,
> > +	.set_mux = ls1012a_set_mux,
> > +};
> > +
> > +static struct pinctrl_desc ls1012a_pinctrl_desc = {
> > +	.name = "ls1012a",
> > +	.pins = ls1012a_pins,
> > +	.npins = ARRAY_SIZE(ls1012a_pins),
> > +	.pctlops = &ls1012a_pinctrl_ops,
> > +	.pmxops = &ls1012a_pinmux_ops,
> > +	.owner = THIS_MODULE,
> > +};
> > +
> > +static int ls1012a_pinctrl_probe(struct platform_device *pdev)
> > +{
> > +	struct ls1012a_pinctrl_pdata *pd;
> > +	int ret;
> > +	u32 dcfg_ssc;
> > +	struct regmap *dcfg_regmap;
> > +
> > +	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
> > +	if (!pd)
> > +		return -ENOMEM;
> > +	platform_set_drvdata(pdev, pd);
> > +
> > +	pd->big_endian = device_is_big_endian(&pdev->dev);
> > +
> > +	/* SCFG PMUX0 */
> > +	pd->cr0mem = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(pd->cr0mem))
> > +		return PTR_ERR(pd->cr0mem);
> > +	dev_dbg(&pdev->dev, "scfg pmuxcr0 at %px %s", pd->cr0mem,
> > +		pd->big_endian ? "be" : "le");
> > +
> > +	/* DCFG RCW SSC */
> > +	dcfg_regmap = syscon_regmap_lookup_by_phandle(
> > +		dev_of_node(&pdev->dev), "dcfg-regmap");
> > +	if (IS_ERR(dcfg_regmap)) {
> > +		dev_err(&pdev->dev, "dcfg regmap: %pe\n", dcfg_regmap);
> > +		return -EINVAL;
> > +	}
> > +	ret = regmap_read(dcfg_regmap, DCFG_SSC_REG, &dcfg_ssc);
> > +	if (ret) {
> > +		dev_err(&pdev->dev, "dcfg-regmap read: %d\n", ret);
> > +		return ret;
> > +	}
> > +	pd->ssc = swab32(dcfg_ssc); /* untwist RCW fields */
> > +
> > +	dev_dbg(&pdev->dev, "dcfg ssc = %08x (grp1=%s grp2=%s grp3=%s)\n",
> > +		pd->ssc,
> > +		(pd->ssc & SSC_DATA0_GPIO_MASK) == SSC_DATA0_GPIO_SEL_SPI ? "spi" : "gpio",
> > +		(pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_SPI ? "spi"
> > +		: (pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_GPIO ? "gpio"
> > +		: (pd->ssc & SSC_DATA1_GPIO_MASK) == 0x80 ? "10" : "11",
> > +		(pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_GPIO ? "gpio"
> > +		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_I2C ? "i2c"
> > +		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_SPI ? "spi"
> > +		: "gpio+reset");
> > +
> > +	ls1012a_init_mux(pd);
> > +
> > +	ret = devm_pinctrl_register_and_init(&pdev->dev, &ls1012a_pinctrl_desc,
> > +		pd, &pd->pctl_dev);
> > +	if (ret)
> > +		return dev_err_probe(&pdev->dev, ret, "Failed pinctrl init\n");
> > +
> > +	pinctrl_enable(pd->pctl_dev);
> > +	return ret;
> > +}
> > +
> > +static const struct of_device_id ls1012a_pinctrl_match_table[] = {
> > +	{ .compatible = "fsl,ls1012a-pinctrl" },
> > +	{ /* sentinel */ }
> > +};
> > +
> > +static struct platform_driver ls1012a_pinctrl_driver = {
> > +	.driver = {
> > +		.name = "ls1012a_pinctrl",
> > +		.of_match_table = ls1012a_pinctrl_match_table,
> > +	},
> > +	.probe = ls1012a_pinctrl_probe,
> > +};
> > +
> > +builtin_platform_driver(ls1012a_pinctrl_driver)
> > +
> > +MODULE_DESCRIPTION("LS1012A pinctrl driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.43.0
> >
David Leonard Aug. 28, 2024, 1:13 a.m. UTC | #2
On Tue, 27 Aug 2024, Frank Li wrote:

> On Tue, Aug 27, 2024 at 12:05:24PM +1000, David Leonard wrote:
>> Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert
>> GPIO control over the second I2C bus.
>>
>> Signed-off-by: David Leonard <David.Leonard@digi.com>
>> ---
>
> Why not use pinctrl-single ?
>
> You can ref arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
>
> It did similar thing to use GPIO recover i2c bus.
>
> Just need change dts file.

This is a great suggestion for the LS1046A and means I could
withdraw the "fsl,ls1046a-pinctrl" driver, which I'll do.

But I don't think it's suitable for use with the LS1012A.
The reason is that the the LS1012A's pinmux register PMUXCR0 is more
complicated. It has a global override bit, overriding the "backing"
RCW configuration for 3 pingroups. In addition, when overriding, the
PMUXCR0 can only supply a subset of the functions that RCW can.

/*
  * LS1012A
  *    Group: qspi_1             qspi_2      qspi_3
  *           ================== =========== =============
  *    Pin:   62    123    124   61          122    60
  *           ----- ------ ----- ----------- ------ ------
  * i2c                                      SCL    SDA    (RCW only)
  * spi       SCK   DATA0
  * spi       SCK   DATA0        DATA1
  * spi       SCK   DATA0        DATA1       DATA2  DATA3
  * gpio      GPIO4 GPIO11 GPIO5
  * gpio                         GPIO12
  * gpio                                     GPIO13 GPIO14
  * gpio_reset                               GPIO13 REQ_B  (RCW only)
  */

In particular, when PMUXCR0 is overriding RCW, it can't provide "i2c"
or "gpio_reset" functions for qspi_3. It can only provide "spi" and "gpio".

The fsl,ls1012a-pinctrl driver recognises when you are asking
for the configuration that the RCW can provide, and diables the
override.

Cheers,

David
diff mbox series

Patch

diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index 3b59d7189004..a2038042eeae 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -209,6 +209,14 @@  config PINCTRL_IMX93
  	help
  	  Say Y here to enable the imx93 pinctrl driver

+config PINCTRL_LS1012A
+	tristate "LS1012A pinctrl driver"
+	depends on ARCH_LAYERSCAPE && OF || COMPILE_TEST
+	select PINMUX
+	select GENERIC_PINCONF
+	help
+	  Say Y here to enable the ls1012a pinctrl driver
+
  config PINCTRL_VF610
  	bool "Freescale Vybrid VF610 pinctrl driver"
  	depends on SOC_VF610
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index d27085c2b4c4..6926529d8635 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -35,3 +35,4 @@  obj-$(CONFIG_PINCTRL_IMX25)	+= pinctrl-imx25.o
  obj-$(CONFIG_PINCTRL_IMX28)	+= pinctrl-imx28.o
  obj-$(CONFIG_PINCTRL_IMXRT1050)	+= pinctrl-imxrt1050.o
  obj-$(CONFIG_PINCTRL_IMXRT1170)	+= pinctrl-imxrt1170.o
+obj-$(CONFIG_PINCTRL_LS1012A)	+= pinctrl-ls1012a.o
diff --git a/drivers/pinctrl/freescale/pinctrl-ls1012a.c b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
new file mode 100644
index 000000000000..d4c535ed6c07
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
@@ -0,0 +1,381 @@ 
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Pin controller for NXP QorIQ LS1012A.
+ *
+ * Copyright (c) 2024 Digi International, Inc.
+ * Author: David Leonard <David.Leonard@digi.com>
+ */
+
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
+
+struct ls1012a_pinctrl_pdata {
+	struct pinctrl_dev *pctl_dev;
+	void __iomem *cr0mem;
+	bool big_endian;
+	u32 ssc;
+};
+
+/* Bitfield macros for masks and values that follow the datasheet's
+ * bit numbering schemes for registers of different bit-endianess. */
+#define BITV_BE(hi, v)	((v) << (31 - (hi) % 32))
+#define BITM_BE(hi, lo)	(((1 << ((hi) - (lo) + 1)) - 1) << (31 - (hi) % 32))
+#define BITV_LE(lo, v)	((v) << ((lo) % 32))
+#define BITM_LE(lo, hi)	(((1 << ((hi) - (lo) + 1)) - 1) << ((lo) % 32))
+
+/* SCFG PMUXCR0 pinmux control register */
+#define SCFG_PMUXCR0			0x430
+#define QSPI_MUX_OVRD_MASK		BITM_BE(0, 0)	/* [0] */
+#define QSPI_MUX_DISABLE		BITV_BE(0, 0)	/*  use RCW */
+#define QSPI_MUX_ENABLE			BITV_BE(0, 1)	/*  use PMUXCR0 */
+#define QSPI_DATA0_GPIO_OVR_MASK	BITM_BE(1, 1)	/* [1] */
+#define QSPI_DATA0_GPIO_SEL_SPI		BITV_BE(1, 0)	/*  DATA0,SCK,CS0 */
+#define QSPI_DATA0_GPIO_SEL_GPIO	BITV_BE(1, 1)	/*  GPIO1[4,11,5] */
+#define QSPI_DATA1_GPIO_OVR_MASK	BITM_BE(3, 2)	/* [3:2] */
+#define QSPI_DATA1_GPIO_SEL_SPI		BITV_BE(3, 0)	/*  DATA1 */
+#define QSPI_DATA1_GPIO_SEL_GPIO	BITV_BE(3, 1)	/*  GPIO1[12] */
+#define QSPI_IIC2_OVR_MASK		BITM_BE(5, 4)	/* [5:4] */
+#define QSPI_IIC2_SEL_GPIO		BITV_BE(5, 0)	/*  GPIO1[13,14] */
+#define QSPI_IIC2_SEL_I2C		BITV_BE(5, 1)	/*  SCL,SDA (rev0) */
+#define QSPI_IIC2_SEL_SPI		BITV_BE(5, 2)	/*  DATA2,DATA3 */
+
+/* RCW SoC-specific configuration (read-only) */
+#define DCFG_RCWSR			0x100
+#define SOC_SPEC_CONFIG			416		/* word 13 */
+#define DCFG_SSC_REG			(DCFG_RCWSR + SOC_SPEC_CONFIG / 8)
+#define SSC_DATA0_GPIO_MASK		BITM_LE(421, 421)
+#define SSC_DATA0_GPIO_SEL_SPI		BITV_LE(421, 0)	/*  DATA0,SCK,CS0 */
+#define SSC_DATA0_GPIO_SEL_GPIO		BITV_LE(421, 1)	/*  GPIO1[11,4,5] */
+#define SSC_DATA1_GPIO_MASK		BITM_LE(422, 423)
+#define SSC_DATA1_GPIO_SEL_SPI		BITV_LE(422, 0)	/*  DATA1 */
+#define SSC_DATA1_GPIO_SEL_GPIO		BITV_LE(422, 2)	/*  GPIO1[12] */
+#define SSC_IIC2_MASK			BITM_LE(424, 425)
+#define SSC_IIC2_SEL_GPIO		BITV_LE(424, 0)	/*  GPIO1[13,14] */
+#define SSC_IIC2_SEL_I2C		BITV_LE(424, 2)	/*  SCL,SDA */
+#define SSC_IIC2_SEL_SPI		BITV_LE(424, 1)	/*  DATA2,DATA3 */
+#define SSC_IIC2_SEL_GPIO_RESET		BITV_LE(424, 3)	/*  GPIO1[13],RESET_REQ_B*/
+
+const struct pinctrl_pin_desc ls1012a_pins[] = {
+	PINCTRL_PIN(60, "QSPI_A_DATA3/GPIO1_14/IIC2_SDA/RESET_REQ_B"),
+	PINCTRL_PIN(61, "QSPI_A_DATA1/GPIO1_12"),
+	PINCTRL_PIN(62, "QSPI_A_SCK/GPIO1_04"),
+	PINCTRL_PIN(122, "QSPI_A_DATA2/GPIO1_13/IIC2_SCL"),
+	PINCTRL_PIN(123, "QSPI_A_DATA0/GPIO1_11"),
+	PINCTRL_PIN(124, "QSPI_A_CS0/GPIO1_05"),
+};
+
+static const unsigned int qspi_1_grp[] = { 62, 123, 124 };
+static const unsigned int qspi_2_grp[] = { 61 };
+static const unsigned int qspi_3_grp[] = { 122, 60 };
+
+#define GRP_qspi_1	0	/* SCK,CS0,DATA0 */
+#define GRP_qspi_2	1	/* DATA1 */
+#define GRP_qspi_3	2	/* DATA2,DATA3 */
+#define _GRP_max	3
+
+#define _PINGROUP(name) \
+	[GRP_##name] = PINCTRL_PINGROUP(#name "_grp", name##_grp, ARRAY_SIZE(name##_grp))
+static const struct pingroup ls1012a_groups[] = {
+	_PINGROUP(qspi_1),
+	_PINGROUP(qspi_2),
+	_PINGROUP(qspi_3),
+};
+
+
+static void ls1012a_write_cr0(struct ls1012a_pinctrl_pdata *pd, u32 val)
+{
+	if (pd->big_endian)
+		iowrite32be(val, pd->cr0mem);
+	else
+		iowrite32(val, pd->cr0mem);
+}
+
+static u32 ls1012a_read_cr0(struct ls1012a_pinctrl_pdata *pd)
+{
+	return pd->big_endian ? ioread32be(pd->cr0mem) : ioread32(pd->cr0mem);
+}
+
+static int ls1012a_get_groups_count(struct pinctrl_dev *pcdev)
+{
+	return ARRAY_SIZE(ls1012a_groups);
+}
+
+static const char *ls1012a_get_group_name(struct pinctrl_dev *pcdev,
+	unsigned int selector)
+{
+	return ls1012a_groups[selector].name;
+}
+
+static int ls1012a_get_group_pins(struct pinctrl_dev *pcdev,
+	unsigned int selector, const unsigned int **pins, unsigned int *npins)
+{
+	*pins = ls1012a_groups[selector].pins;
+	*npins = ls1012a_groups[selector].npins;
+	return 0;
+}
+
+static const struct pinctrl_ops ls1012a_pinctrl_ops = {
+	.get_groups_count = ls1012a_get_groups_count,
+	.get_group_name = ls1012a_get_group_name,
+	.get_group_pins = ls1012a_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static const char * const i2c_groups[] = { "qspi_3_grp" };
+static const char * const spi_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
+static const char * const gpio_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
+static const char * const gpio_reset_groups[] = { "qspi_3_grp" };
+
+#define FUNC_i2c	0
+#define FUNC_spi	1
+#define FUNC_gpio	2
+#define FUNC_gpio_reset 3
+#define _FUNC_max	4
+
+#define _PINFUNC(name) \
+	[FUNC_##name] = PINCTRL_PINFUNCTION(#name, name##_groups, ARRAY_SIZE(name##_groups))
+static const struct pinfunction ls1012a_functions[] = {
+	_PINFUNC(i2c),
+	_PINFUNC(spi),
+	_PINFUNC(gpio),
+	_PINFUNC(gpio_reset),
+};
+
+static int ls1012a_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(ls1012a_functions);
+}
+
+static const char *ls1012a_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
+{
+	return ls1012a_functions[func].name;
+}
+
+static int ls1012a_get_function_groups(struct pinctrl_dev *pctldev, unsigned int func,
+	const char * const **groups,
+	unsigned int * const ngroups)
+{
+	*groups = ls1012a_functions[func].groups;
+	*ngroups = ls1012a_functions[func].ngroups;
+	return 0;
+}
+
+/*
+ * LS1012A
+ *    Group: qspi_1             qspi_2      qspi_3
+ *           ================== =========== =============
+ *    Pin:   62    123    124   61          122    60
+ *           ----- ------ ----- ----------- ------ ------
+ * i2c                                      SCL    SDA    (RCW only)
+ * spi       SCK   DATA0
+ * spi       SCK   DATA0        DATA1
+ * spi       SCK   DATA0        DATA1       DATA2  DATA3
+ * gpio      GPIO4 GPIO11 GPIO5
+ * gpio                         GPIO12
+ * gpio                                     GPIO13 GPIO14
+ * gpio_reset                               GPIO13 REQ_B  (RCW only)
+ */
+
+static const struct ls1012a_func_mux {
+	u32 cr0mask, cr0; /* mux control */
+	u32 sscmask, ssc; /* equivalent in RCW */
+} ls1012a_func_mux[_FUNC_max][_GRP_max] = {
+	[FUNC_i2c] = {
+		[GRP_qspi_3] = {
+			.sscmask = SSC_IIC2_MASK,
+			.ssc =     SSC_IIC2_SEL_I2C,
+		},
+	},
+	[FUNC_spi] = {
+		[GRP_qspi_1] = {
+			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
+			.cr0 =     QSPI_DATA0_GPIO_SEL_SPI,
+			.sscmask = SSC_DATA0_GPIO_MASK,
+			.ssc =     SSC_DATA0_GPIO_SEL_SPI
+		},
+		[GRP_qspi_2] = {
+			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
+			.cr0 =     QSPI_DATA1_GPIO_SEL_SPI,
+			.sscmask = SSC_DATA1_GPIO_MASK,
+			.ssc =     SSC_DATA1_GPIO_SEL_SPI,
+		},
+		[GRP_qspi_3] = {
+			.cr0mask = QSPI_IIC2_OVR_MASK,
+			.cr0 =     QSPI_IIC2_SEL_SPI,
+			.sscmask = SSC_IIC2_MASK,
+			.ssc =     SSC_IIC2_SEL_SPI,
+		},
+	},
+	[FUNC_gpio] = {
+		[GRP_qspi_1] = {
+			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
+			.cr0 =     QSPI_DATA0_GPIO_SEL_GPIO,
+			.sscmask = SSC_DATA0_GPIO_MASK,
+			.ssc =     SSC_DATA0_GPIO_SEL_GPIO,
+		},
+		[GRP_qspi_2] = {
+			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
+			.cr0 =     QSPI_DATA1_GPIO_SEL_GPIO,
+			.sscmask = SSC_DATA1_GPIO_MASK,
+			.ssc =     SSC_DATA1_GPIO_SEL_GPIO,
+		},
+		[GRP_qspi_3] = {
+			.cr0mask = QSPI_IIC2_OVR_MASK,
+			.cr0 =     QSPI_IIC2_SEL_GPIO,
+			.sscmask = SSC_IIC2_MASK,
+			.ssc =     SSC_IIC2_SEL_GPIO,
+		},
+	},
+	[FUNC_gpio_reset] = {
+		[GRP_qspi_3] = {
+			.sscmask = SSC_IIC2_MASK,
+			.ssc =     SSC_IIC2_SEL_GPIO_RESET,
+		},
+	},
+};
+
+static int ls1012a_set_mux(struct pinctrl_dev *pcdev,
+	unsigned int func, unsigned int group)
+{
+	struct ls1012a_pinctrl_pdata *pd = pinctrl_dev_get_drvdata(pcdev);
+	const struct ls1012a_func_mux *fm = &ls1012a_func_mux[func][group];
+	u32 cr0 = ls1012a_read_cr0(pd);
+
+	if (!fm->cr0mask) {
+		if ((pd->ssc & fm->sscmask) != fm->ssc)
+			return -EOPNOTSUPP;
+		cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_DISABLE;
+	} else {
+		cr0 = (cr0 & ~fm->cr0mask) | fm->cr0;
+		if ((pd->ssc & fm->sscmask) != fm->ssc)
+			cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_ENABLE;
+	}
+	ls1012a_write_cr0(pd, cr0);
+	return 0;
+}
+
+static void ls1012a_init_mux(struct ls1012a_pinctrl_pdata *pd)
+{
+	unsigned int func, group;
+	const struct ls1012a_func_mux *fm;
+	u32 cr0;
+
+	cr0 = ls1012a_read_cr0(pd);
+	if ((cr0 & QSPI_MUX_OVRD_MASK) == QSPI_MUX_DISABLE) {
+		/*
+		 * Prepare a disabled MUXCR0 to have a same/similar
+		 * configuration as RCW SSC, and leave it disabled.
+		 */
+		for (func = 0; func < _FUNC_max; func++) {
+			for (group = 0; group < _GRP_max; group++) {
+				fm = &ls1012a_func_mux[func][group];
+				if (fm->sscmask &&
+				    fm->ssc == (pd->ssc & fm->sscmask)) {
+					cr0 &= ~fm->cr0mask;
+					cr0 |= fm->cr0;
+				}
+			}
+		}
+		ls1012a_write_cr0(pd, cr0);
+	}
+}
+
+static const struct pinmux_ops ls1012a_pinmux_ops = {
+	.get_functions_count = ls1012a_get_functions_count,
+	.get_function_name = ls1012a_get_function_name,
+	.get_function_groups = ls1012a_get_function_groups,
+	.set_mux = ls1012a_set_mux,
+};
+
+static struct pinctrl_desc ls1012a_pinctrl_desc = {
+	.name = "ls1012a",
+	.pins = ls1012a_pins,
+	.npins = ARRAY_SIZE(ls1012a_pins),
+	.pctlops = &ls1012a_pinctrl_ops,
+	.pmxops = &ls1012a_pinmux_ops,
+	.owner = THIS_MODULE,
+};
+
+static int ls1012a_pinctrl_probe(struct platform_device *pdev)
+{
+	struct ls1012a_pinctrl_pdata *pd;
+	int ret;
+	u32 dcfg_ssc;
+	struct regmap *dcfg_regmap;
+
+	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, pd);
+
+	pd->big_endian = device_is_big_endian(&pdev->dev);
+
+	/* SCFG PMUX0 */
+	pd->cr0mem = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(pd->cr0mem))
+		return PTR_ERR(pd->cr0mem);
+	dev_dbg(&pdev->dev, "scfg pmuxcr0 at %px %s", pd->cr0mem,
+		pd->big_endian ? "be" : "le");
+
+	/* DCFG RCW SSC */
+	dcfg_regmap = syscon_regmap_lookup_by_phandle(
+		dev_of_node(&pdev->dev), "dcfg-regmap");
+	if (IS_ERR(dcfg_regmap)) {
+		dev_err(&pdev->dev, "dcfg regmap: %pe\n", dcfg_regmap);
+		return -EINVAL;
+	}
+	ret = regmap_read(dcfg_regmap, DCFG_SSC_REG, &dcfg_ssc);
+	if (ret) {
+		dev_err(&pdev->dev, "dcfg-regmap read: %d\n", ret);
+		return ret;
+	}
+	pd->ssc = swab32(dcfg_ssc); /* untwist RCW fields */
+
+	dev_dbg(&pdev->dev, "dcfg ssc = %08x (grp1=%s grp2=%s grp3=%s)\n",
+		pd->ssc,
+		(pd->ssc & SSC_DATA0_GPIO_MASK) == SSC_DATA0_GPIO_SEL_SPI ? "spi" : "gpio",
+		(pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_SPI ? "spi"
+		: (pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_GPIO ? "gpio"
+		: (pd->ssc & SSC_DATA1_GPIO_MASK) == 0x80 ? "10" : "11",
+		(pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_GPIO ? "gpio"
+		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_I2C ? "i2c"
+		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_SPI ? "spi"
+		: "gpio+reset");
+
+	ls1012a_init_mux(pd);
+
+	ret = devm_pinctrl_register_and_init(&pdev->dev, &ls1012a_pinctrl_desc,
+		pd, &pd->pctl_dev);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "Failed pinctrl init\n");
+
+	pinctrl_enable(pd->pctl_dev);
+	return ret;
+}
+
+static const struct of_device_id ls1012a_pinctrl_match_table[] = {
+	{ .compatible = "fsl,ls1012a-pinctrl" },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver ls1012a_pinctrl_driver = {
+	.driver = {
+		.name = "ls1012a_pinctrl",
+		.of_match_table = ls1012a_pinctrl_match_table,
+	},
+	.probe = ls1012a_pinctrl_probe,
+};
+
+builtin_platform_driver(ls1012a_pinctrl_driver)
+
+MODULE_DESCRIPTION("LS1012A pinctrl driver");
+MODULE_LICENSE("GPL");