Message ID | 8cd0b743-4fff-e17f-9543-d2d4d7879758@digi.com |
---|---|
State | New |
Headers | show |
Series | [1/6] pinctrl: ls1012a: Add pinctrl driver support | expand |
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 > >
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 --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");
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