[PATCH 4/6] pinctrl: ls1046a: Add pinctrl driver support

Frank Li Frank.li at nxp.com
Tue Aug 27 12:19:55 PDT 2024


On Tue, Aug 27, 2024 at 12:12:24PM +1000, David Leonard wrote:
>
> Add QorIQ LS1046A pinctrl driver allowing i2c-core to exert
> GPIO control over the third and fourth I2C buses.
>
> Signed-off-by: David Leonard <David.Leonard at digi.com>
> ---

Why not use pinctrl-single,  please ref fsl,lx2160x.dtsi for GPIO/i2c
recover.

Frank

>  drivers/pinctrl/freescale/Kconfig           |   8 +
>  drivers/pinctrl/freescale/Makefile          |   1 +
>  drivers/pinctrl/freescale/pinctrl-ls1046a.c | 224 ++++++++++++++++++++
>  3 files changed, 233 insertions(+)
>  create mode 100644 drivers/pinctrl/freescale/pinctrl-ls1046a.c
>
> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index a2038042eeae..2641db6c64c7 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -217,6 +217,14 @@ config PINCTRL_LS1012A
>  	help
>  	  Say Y here to enable the ls1012a pinctrl driver
>
> +config PINCTRL_LS1046A
> +	tristate "LS1046A pinctrl driver"
> +	depends on ARCH_LAYERSCAPE && OF || COMPILE_TEST
> +	select PINMUX
> +	select GENERIC_PINCONF
> +	help
> +	  Say Y here to enable the ls1046a 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 6926529d8635..66fec747af73 100644
> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile
> @@ -36,3 +36,4 @@ 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
> +obj-$(CONFIG_PINCTRL_LS1046A)	+= pinctrl-ls1046a.o
> diff --git a/drivers/pinctrl/freescale/pinctrl-ls1046a.c b/drivers/pinctrl/freescale/pinctrl-ls1046a.c
> new file mode 100644
> index 000000000000..9f5ec31f1e05
> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-ls1046a.c
> @@ -0,0 +1,224 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Pin controller for NXP QorIQ LS1046A.
> + *
> + * Copyright (c) 2024 Digi International, Inc.
> + * Author: David Leonard <David.Leonard at 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/platform_device.h>
> +#include <linux/sys_soc.h>
> +
> +struct ls1046a_pinctrl_pdata {
> +	struct pinctrl_dev *pctl_dev;
> +	void __iomem *cr0mem;
> +	bool big_endian;
> +	u32 ssc;
> +};
> +
> +/*
> + *       L4           M4            M3           N3
> + *  i2c  IIC3_SCL     IIC3_SDA      IIC4_SCL     IIC4_SDA
> + *  gpio GPIO_4[10]   GPIO_4[11]    GPIO_4[12]   GPIO_4[13]
> + *  evt  EVT_B[5]     EVT_B[6]      EVT_B[7]     EVT_B[8]
> + *  usb  USB2_DRVVBUS USB2_PWRFAULT USB3_DRVVBUS USB3_PWRFAULT
> + *  ftm  FTM8_CH0     FTM8_CH1      FTM3_FAULT   FTM_EXT3CLK
> + */
> +
> +/* SCFG_RCWPMUXCR0 pinmux control register */
> +#define SCFG_RCWPMUXCR0			0x0157040c
> +#define RCWPMUXCR0_FIELD(shift, func)	((u32)(func) << (29 - (shift)))
> +#define RCWPMUXCR0_MASK(shift)		RCWPMUXCR0_FIELD(shift, RCWPMUXCR0_FUNC_MASK)
> +#define RCWPMUXCR0_IIC3_SCL_SHIFT	17
> +#define RCWPMUXCR0_IIC3_SDA_SHIFT	21
> +#define RCWPMUXCR0_IIC4_SCL_SHIFT	25
> +#define RCWPMUXCR0_IIC4_SDA_SHIFT	29
> +#define RCWPMUXCR0_FUNC_I2C		0
> +#define RCWPMUXCR0_FUNC_GPIO		1
> +#define RCWPMUXCR0_FUNC_EVT		2
> +#define RCWPMUXCR0_FUNC_USB		3
> +#define RCWPMUXCR0_FUNC_FTM		5
> +#define RCWPMUXCR0_FUNC_CLK		6
> +#define RCWPMUXCR0_FUNC_MASK		7
> +
> +#define PIN_L4 0 /* IIC3_SCL/GPIO_4[10]/EVT_B[5]/USB2_DRVVBUS/FTM8_CH0 */
> +#define PIN_M4 1 /* IIC3_SDA/GPIO_4[11]/EVT_B[6]/USB2_PWRFAULT/FTM8_CH1 */
> +#define PIN_M3 2 /* IIC4_SCL/GPIO_4[12]/EVT_B[7]/USB3_DRVVBUS/FTM3_FAULT */
> +#define PIN_N3 3 /* IIC4_SDA/GPIO_4[13]/EVT_B[8]/USB3_PWRFAULT/FTM_EXT3CLK */
> +
> +const struct pinctrl_pin_desc ls1046a_pins[] = {
> +	PINCTRL_PIN(PIN_L4, "L4"),
> +	PINCTRL_PIN(PIN_M4, "M4"),
> +	PINCTRL_PIN(PIN_M3, "M3"),
> +	PINCTRL_PIN(PIN_N3, "N3"),
> +};
> +
> +/* Each pin is its own group */
> +static const char * const ls1046a_groups[] = { "L4", "M4", "M3", "N3" };
> +
> +static int ls1046a_get_groups_count(struct pinctrl_dev *pcdev)
> +{
> +	return ARRAY_SIZE(ls1046a_pins);
> +}
> +
> +static const char *ls1046a_get_group_name(struct pinctrl_dev *pcdev,
> +	unsigned int selector)
> +{
> +	return ls1046a_pins[selector].name;
> +}
> +
> +static int ls1046a_get_group_pins(struct pinctrl_dev *pcdev,
> +	unsigned int selector, const unsigned int **pins, unsigned int *npins)
> +{
> +	*pins = &ls1046a_pins[selector].number;
> +	*npins = 1;
> +	return 0;
> +}
> +
> +static const struct pinctrl_ops ls1046a_pinctrl_ops = {
> +	.get_groups_count = ls1046a_get_groups_count,
> +	.get_group_name = ls1046a_get_group_name,
> +	.get_group_pins = ls1046a_get_group_pins,
> +	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
> +	.dt_free_map = pinconf_generic_dt_free_map,
> +};
> +
> +/* Every pin has the same set of functions */
> +#define FUNC_i2c	0
> +#define FUNC_gpio	1
> +#define FUNC_evt	2
> +#define FUNC_usb	3
> +#define FUNC_ftm	4
> +
> +#define _PINFUNC(name) \
> +	[FUNC_##name] = PINCTRL_PINFUNCTION(#name, ls1046a_groups, ARRAY_SIZE(ls1046a_groups))
> +static const struct pinfunction ls1046a_functions[] = {
> +	_PINFUNC(i2c),
> +	_PINFUNC(gpio),
> +	_PINFUNC(evt),
> +	_PINFUNC(usb),
> +	_PINFUNC(ftm),
> +};
> +
> +static int ls1046a_get_functions_count(struct pinctrl_dev *pctldev)
> +{
> +	return ARRAY_SIZE(ls1046a_functions);
> +}
> +
> +static const char *ls1046a_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
> +{
> +	return ls1046a_functions[func].name;
> +}
> +
> +static int ls1046a_get_function_groups(struct pinctrl_dev *pctldev, unsigned int func,
> +	const char * const **groups,
> +	unsigned int * const ngroups)
> +{
> +	*groups = ls1046a_functions[func].groups;
> +	*ngroups = ls1046a_functions[func].ngroups;
> +	return 0;
> +}
> +
> +static int ls1046a_set_mux(struct pinctrl_dev *pcdev,
> +	unsigned int func, unsigned int pin)
> +{
> +	struct ls1046a_pinctrl_pdata *pd = pinctrl_dev_get_drvdata(pcdev);
> +	static const u32 cr0_reg_func[] = {
> +		[FUNC_i2c] = RCWPMUXCR0_FUNC_I2C,
> +		[FUNC_gpio] = RCWPMUXCR0_FUNC_GPIO,
> +		[FUNC_evt] = RCWPMUXCR0_FUNC_EVT,
> +		[FUNC_usb] = RCWPMUXCR0_FUNC_USB,
> +		[FUNC_ftm] = RCWPMUXCR0_FUNC_FTM,
> +	};
> +	static const unsigned int cr0_pin_shift[] = {
> +		[PIN_L4] = RCWPMUXCR0_IIC3_SCL_SHIFT,
> +		[PIN_M4] = RCWPMUXCR0_IIC3_SDA_SHIFT,
> +		[PIN_M3] = RCWPMUXCR0_IIC4_SCL_SHIFT,
> +		[PIN_N3] = RCWPMUXCR0_IIC4_SDA_SHIFT,
> +	};
> +	u32 cr0;
> +
> +	if (pd->big_endian)
> +		cr0 = ioread32be(pd->cr0mem);
> +	else
> +		cr0 = ioread32(pd->cr0mem);
> +
> +	unsigned int pin_shift = cr0_pin_shift[pin];
> +	u32 reg_func = cr0_reg_func[func];
> +	u32 newcr0 = (cr0 & ~RCWPMUXCR0_MASK(pin_shift)) |
> +		RCWPMUXCR0_FIELD(pin_shift, reg_func);
> +
> +	if (pd->big_endian)
> +		iowrite32be(newcr0, pd->cr0mem);
> +	else
> +		iowrite32(newcr0, pd->cr0mem);
> +	return 0;
> +}
> +
> +static const struct pinmux_ops ls1046a_pinmux_ops = {
> +	.get_functions_count = ls1046a_get_functions_count,
> +	.get_function_name = ls1046a_get_function_name,
> +	.get_function_groups = ls1046a_get_function_groups,
> +	.set_mux = ls1046a_set_mux,
> +};
> +
> +static const struct pinctrl_desc ls1046a_pinctrl_desc = {
> +	.name = "ls1046a",
> +	.pins = ls1046a_pins,
> +	.npins = ARRAY_SIZE(ls1046a_pins),
> +	.pctlops = &ls1046a_pinctrl_ops,
> +	.pmxops = &ls1046a_pinmux_ops,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int ls1046a_pinctrl_probe(struct platform_device *pdev)
> +{
> +	struct ls1046a_pinctrl_pdata *pd;
> +	int ret;
> +
> +	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");
> +
> +	ret = devm_pinctrl_register_and_init(&pdev->dev, &ls1046a_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 ls1046a_pinctrl_match_table[] = {
> +	{ .compatible = "fsl,ls1046a-pinctrl" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver ls1046a_pinctrl_driver = {
> +	.driver = {
> +		.name = "ls1046a_pinctrl",
> +		.of_match_table = ls1046a_pinctrl_match_table,
> +	},
> +	.probe = ls1046a_pinctrl_probe,
> +};
> +
> +builtin_platform_driver(ls1046a_pinctrl_driver)
> +
> +MODULE_DESCRIPTION("LS1046A pinctrl driver");
> +MODULE_LICENSE("GPL");
> --
> 2.43.0
>



More information about the linux-arm-kernel mailing list