Message ID | 8cd0b743-4fff-e17f-9543-d2d4d7879758@digi.com |
---|---|
State | New |
Headers | show |
Series | [1/6] pinctrl: ls1012a: Add pinctrl driver support | expand |
Am Dienstag, 27. August 2024, 04:05:24 CEST schrieb David Leonard: > Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert > GPIO control over the second I2C bus. Can you please elaborate? AFAIK the pinmuxing is set by the RCW on layerscape. How can you change the pinmuxing at runtime. How is this related to i2c controlling GPIO? Best regards, Alexander > 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 > > 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"); >
On Tue, 27 Aug 2024, Alexander Stein wrote: > Am Dienstag, 27. August 2024, 04:05:24 CEST schrieb David Leonard: >> Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert >> GPIO control over the second I2C bus. > > Can you please elaborate? AFAIK the pinmuxing is set by the RCW on layerscape. > How can you change the pinmuxing at runtime. How is this related to i2c > controlling GPIO? Sure. Two of the Layerscape SoCs have pinmux control registers that override/extend the RCW configuration string. These pinmux registers are not consistent across the family, only a very few pins are muxable, and they're all related to I2C. i2c-core has a bus recovery feature that relies on pinctrl to switch the I2C pins into GPIO mode. Our motivating case is efficient use of the Atmel ATECCx08 crypto processor. It has a peculiar requirement that SDA be held low for a certain amount of time. That kind of control also needs the pins in GPIO mode. >> 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 >> >> 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"); >> > > > -- > TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany > Amtsgericht München, HRB 105018 > Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider > https://linkprotect.cudasvc.com/url?a=http%3a%2f%2fwww.tq-group.com%2f&c=E,1,cVMx__vg5fEF9T8hc39kPIKQSP2rTuv_7tLSPVEOmXyD87IrvYM0OP8NYwIfDnnSUGCAVzkTBOPCUCOCeZryyztWlYAicjWaEwH2S14xgFbq58j7P7TreOLl&typo=1 > > >
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. 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, 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