lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <3eb7bd2e-bb25-57b8-2ad3-f1fdfa25136f@digi.com>
Date: Tue, 27 Aug 2024 22:23:01 +1000 (AEST)
From: David Leonard <David.Leonard@...i.com>
To: Alexander Stein <alexander.stein@...tq-group.com>
cc: linux-arm-kernel@...ts.infradead.org, Dong Aisheng <aisheng.dong@....com>, 
    Fabio Estevam <festevam@...il.com>, Shawn Guo <shawnguo@...nel.org>, 
    Jacky Bai <ping.bai@....com>, 
    Pengutronix Kernel Team <kernel@...gutronix.de>, 
    Linus Walleij <linus.walleij@...aro.org>, linux-kernel@...r.kernel.org, 
    linux-gpio@...r.kernel.org
Subject: Re: [PATCH 1/6] pinctrl: ls1012a: Add pinctrl driver support

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@...i.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@...i.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
>
>
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ