On 5/7/26 01:31, David Lechner wrote:
> On 5/4/26 8:03 AM, Mikhail Kshevetskiy wrote:
>> This patch introduce shared Airoha pinctrl code.
>>
>> Signed-off-by: Mikhail Kshevetskiy <[email protected]>
>> ---
>>  drivers/pinctrl/Kconfig                 |   1 +
>>  drivers/pinctrl/Makefile                |   1 +
>>  drivers/pinctrl/airoha/Kconfig          |  11 +
>>  drivers/pinctrl/airoha/Makefile         |   3 +
>>  drivers/pinctrl/airoha/airoha-common.h  | 512 ++++++++++++++
>>  drivers/pinctrl/airoha/pinctrl-airoha.c | 843 ++++++++++++++++++++++++
>>  6 files changed, 1371 insertions(+)
>>  create mode 100644 drivers/pinctrl/airoha/Kconfig
>>  create mode 100644 drivers/pinctrl/airoha/Makefile
>>  create mode 100644 drivers/pinctrl/airoha/airoha-common.h
>>  create mode 100644 drivers/pinctrl/airoha/pinctrl-airoha.c
> I don't remember if I asked before...
>
> Should we add a MAINTAINERS entry for this new directory?

Good questions. Probably Markus Gothe or Benjamin Larsson are better
maintainers candidates.

Markus Gothe, Benjamin Larsson what do you think?

>
>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
>> index 578edbf8168..46a95a1ab6b 100644
>> --- a/drivers/pinctrl/Kconfig
>> +++ b/drivers/pinctrl/Kconfig
>> @@ -405,6 +405,7 @@ config SPL_PINCTRL_ZYNQMP
>>  
>>  endif
>>  
>> +source "drivers/pinctrl/airoha/Kconfig"
>>  source "drivers/pinctrl/broadcom/Kconfig"
>>  source "drivers/pinctrl/exynos/Kconfig"
>>  source "drivers/pinctrl/intel/Kconfig"
>> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
>> index 29fb9b484d0..b03e838ab39 100644
>> --- a/drivers/pinctrl/Makefile
>> +++ b/drivers/pinctrl/Makefile
>> @@ -24,6 +24,7 @@ obj-$(CONFIG_PINCTRL_PIC32)        += pinctrl_pic32.o
>>  obj-$(CONFIG_PINCTRL_EXYNOS)        += exynos/
>>  obj-$(CONFIG_PINCTRL_K210)  += pinctrl-k210.o
>>  obj-$(CONFIG_PINCTRL_MESON) += meson/
>> +obj-$(CONFIG_PINCTRL_AIROHA)        += airoha/
> I still think this could be better placed. It looks like there is
> at leaset some attempt to put these in alphabetical order.
will fix.
>
>>  obj-$(CONFIG_PINCTRL_MTK)   += mediatek/
>>  obj-$(CONFIG_PINCTRL_MSCC)  += mscc/
>>  obj-$(CONFIG_ARCH_MVEBU)    += mvebu/
>> diff --git a/drivers/pinctrl/airoha/Kconfig b/drivers/pinctrl/airoha/Kconfig
>> new file mode 100644
>> index 00000000000..eb87afbb374
>> --- /dev/null
>> +++ b/drivers/pinctrl/airoha/Kconfig
>> @@ -0,0 +1,11 @@
>> +# SPDX-License-Identifier: GPL-2.0-only
>> +
>> +config PINCTRL_AIROHA
>> +    depends on ARCH_AIROHA
>> +    select PINCTRL_FULL
>> +    select PINCTRL_GENERIC
>> +    select PINMUX
>> +    select PINCONF
>> +    select REGMAP
>> +    select SYSCON
>> +    bool
>> diff --git a/drivers/pinctrl/airoha/Makefile 
>> b/drivers/pinctrl/airoha/Makefile
>> new file mode 100644
>> index 00000000000..a25b744dd7a
>> --- /dev/null
>> +++ b/drivers/pinctrl/airoha/Makefile
>> @@ -0,0 +1,3 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +
>> +obj-$(CONFIG_PINCTRL_AIROHA)                += pinctrl-airoha.o
>> diff --git a/drivers/pinctrl/airoha/airoha-common.h 
>> b/drivers/pinctrl/airoha/airoha-common.h
>> new file mode 100644
>> index 00000000000..af4964bf25d
>> --- /dev/null
>> +++ b/drivers/pinctrl/airoha/airoha-common.h
>> @@ -0,0 +1,512 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +#ifndef __AIROHA_COMMON_HEADER__
>> +#define __AIROHA_COMMON_HEADER__
>> +
> ...
>
>> +static const u32 gpio_data_regs[] = {
>> +    REG_GPIO_DATA,
>> +    REG_GPIO_DATA1
>> +};
>> +
>> +static const u32 gpio_out_regs[] = {
>> +    REG_GPIO_OE,
>> +    REG_GPIO_OE1
>> +};
>> +
>> +static const u32 gpio_dir_regs[] = {
>> +    REG_GPIO_CTRL,
>> +    REG_GPIO_CTRL1,
>> +    REG_GPIO_CTRL2,
>> +    REG_GPIO_CTRL3
>> +};
>> +
>> +static const u32 irq_status_regs[] = {
>> +    REG_GPIO_INT,
>> +    REG_GPIO_INT1
>> +};
>> +
>> +static const u32 irq_level_regs[] = {
>> +    REG_GPIO_INT_LEVEL,
>> +    REG_GPIO_INT_LEVEL1,
>> +    REG_GPIO_INT_LEVEL2,
>> +    REG_GPIO_INT_LEVEL3
>> +};
>> +
>> +static const u32 irq_edge_regs[] = {
>> +    REG_GPIO_INT_EDGE,
>> +    REG_GPIO_INT_EDGE1,
>> +    REG_GPIO_INT_EDGE2,
>> +    REG_GPIO_INT_EDGE3
>> +};
> Putting these arrays in the header isn't a good idea. Each compile
> unit (C file) that includes this header will have them repeated. It
> looks like they are only used in pinctrl-arioha.c anyway, so they
> should should just be moved there.
will fix
>
>> diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c 
>> b/drivers/pinctrl/airoha/pinctrl-airoha.c
>> new file mode 100644
>> index 00000000000..11830c44612
>> --- /dev/null
>> +++ b/drivers/pinctrl/airoha/pinctrl-airoha.c
>> @@ -0,0 +1,843 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Author: Lorenzo Bianconi <[email protected]>
>> + * Author: Benjamin Larsson <[email protected]>
>> + * Author: Markus Gothe <[email protected]>
>> + * Author: Mikhail Kshevetskiy <[email protected]>
>> + */
>> +#include <dm.h>
>> +#include <dm/device_compat.h>
>> +#include <dm/device-internal.h>
>> +#include <dm/lists.h>
>> +#include <dm/ofnode.h>
>> +#include <asm-generic/gpio.h>
>> +#include <dt-bindings/pinctrl/mt65xx.h>
>> +#include <regmap.h>
>> +
>> +#include <syscon.h>
>> +#include <asm/arch/scu-regmap.h>
> Not sure I understand the organization of the includes
> above. Why the blank line between regmap and syscon? Why
> not everything in alphabetical order?
No special ordering. Just a kind of ecstatic.
Will fix a bit.
>> +
>> +#include "airoha-common.h"
>> +
>> +
>> +static int pin_in_group(unsigned int pin, const struct pingroup *grp)
>> +{
>> +    for (int i = 0; i < grp->npins; i++) {
>> +            if (grp->pins[i] == pin)
>> +                    return 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int pin_to_gpio(struct airoha_pinctrl *pinctrl, unsigned int pin)
>> +{
>> +    struct airoha_pinctrl_match_data *data = pinctrl->data;
>> +
>> +    if ((pin < data->gpio_offs) ||
>> +        (pin > data->gpio_offs + data->gpio_pin_cnt))
> Should this be >= for the upper bound check?
>
> Also has unnecessary ().
nice catch, will fix
>
>> +            return -EINVAL;
>> +
>> +    return pin - data->gpio_offs;
>> +}
>> +
>
>
>> +static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl,
>> +                               enum airoha_pinctrl_confs_type conf_type,
>> +                               int pin, u32 *val)
>> +{
>> +    const struct airoha_pinctrl_confs_info *confs_info;
>> +    const struct airoha_pinctrl_reg *reg;
>> +
>> +    confs_info = &pinctrl->data->confs_info[conf_type];
>> +
>> +    reg = airoha_pinctrl_get_conf_reg(confs_info->confs,
>> +                                      confs_info->num_confs,
>> +                                      pin);
>> +    if (!reg)
>> +            return -EINVAL;
>> +
>> +    if (regmap_read(pinctrl->chip_scu, reg->offset, val))
>> +            return -EINVAL;
>> +
>> +    *val = (*val & reg->mask) >> __ffs(reg->mask);
> field_get()?
will fix
>
>> +
>> +    return 0;
>> +}
>> +
>> +static int airoha_pinctrl_set_conf(struct airoha_pinctrl *pinctrl,
>> +                               enum airoha_pinctrl_confs_type conf_type,
>> +                               int pin, u32 val)
>> +{
>> +    const struct airoha_pinctrl_confs_info *confs_info;
>> +    const struct airoha_pinctrl_reg *reg = NULL;
>> +
>> +    confs_info = &pinctrl->data->confs_info[conf_type];
>> +
>> +    reg = airoha_pinctrl_get_conf_reg(confs_info->confs,
>> +                                      confs_info->num_confs,
>> +                                      pin);
>> +    if (!reg)
>> +            return -EINVAL;
>> +
>> +    if (regmap_update_bits(pinctrl->chip_scu, reg->offset, reg->mask,
>> +                           val << __ffs(reg->mask)))
> field_prep()?
will fix
>
>> +            return -EINVAL;
>> +
>> +    return 0;
>> +}
>> +
>> +static int airoha_pinconf_get_direction(struct airoha_pinctrl *pinctrl, u32 
>> p)
>> +{
>> +    int gpio;
>> +
>> +    gpio = pin_to_gpio(pinctrl, p);
>> +    if (gpio < 0)
>> +            return gpio;
>> +
>> +    return airoha_gpio_get_direction(pinctrl, gpio);
>> +}
>> +
>> +static int airoha_pinconf_get(struct airoha_pinctrl *pinctrl,
>> +                          unsigned int pin, unsigned long *config)
>> +{
>> +    enum pin_config_param param = pinconf_to_config_param(*config);
>> +    u32 arg;
>> +
>> +    switch (param) {
>> +    case PIN_CONFIG_BIAS_PULL_DOWN:
>> +    case PIN_CONFIG_BIAS_DISABLE:
>> +    case PIN_CONFIG_BIAS_PULL_UP: {
>> +            u32 pull_up, pull_down;
>> +
>> +            if (airoha_pinctrl_get_pullup_conf(pinctrl, pin, &pull_up) ||
>> +                airoha_pinctrl_get_pulldown_conf(pinctrl, pin, &pull_down))
>> +                    return -EINVAL;
>> +
>> +            if (param == PIN_CONFIG_BIAS_PULL_UP &&
>> +                !(pull_up && !pull_down))
>> +                    return -EINVAL;
>> +            else if (param == PIN_CONFIG_BIAS_PULL_DOWN &&
>> +                     !(pull_down && !pull_up))
>> +                    return -EINVAL;
>> +            else if (pull_up || pull_down)
>> +                    return -EINVAL;
>> +
>> +            arg = 1;
>> +            break;
>> +    }
>> +    case PIN_CONFIG_DRIVE_STRENGTH: {
>> +            u32 e2, e4;
>> +
>> +            if (airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, &e2) ||
>> +                airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, &e4))
>> +                    return -EINVAL;
>> +
>> +            arg = e4 << 1 | e2;
>> +            break;
>> +    }
>> +    case PIN_CONFIG_DRIVE_OPEN_DRAIN:
>> +            if (airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, &arg))
>> +                    return -EINVAL;
>> +            break;
>> +    case PIN_CONFIG_OUTPUT_ENABLE:
>> +    case PIN_CONFIG_INPUT_ENABLE:
>> +            arg = airoha_pinconf_get_direction(pinctrl, pin);
>> +            if (arg != param)
> How does this work? It looks like airoha_pinconf_get_direction()
> returns enum gpio_func_t or negative error code.
>
> Should we check for error first before comparing?
>
> Do we need some kind of conversion between enum gpio_func_t and
> enum pin_config_param in airoha_pinconf_get_direction()?
The bug caused by linux driver porting, will fix.
>> +                    return -EINVAL;
>> +
>> +            arg = 1;
>> +            break;
>> +    default:
>> +            return -EOPNOTSUPP;
>> +    }
>> +
>> +    *config = pinconf_to_config_packed(param, arg);
>> +
>> +    return 0;
>> +}
>> +
>> +static int airoha_pinconf_set_pin_value(struct airoha_pinctrl *pinctrl,
>> +                                    unsigned int p, bool value)
>> +{
>> +    int gpio;
>> +
>> +    gpio = pin_to_gpio(pinctrl, p);
>> +    if (gpio < 0)
>> +            return gpio;
>> +
>> +    return airoha_gpio_set(pinctrl, gpio, value);
>> +}
>> +
>> +static int airoha_pinconf_set(struct airoha_pinctrl *pinctrl,
>> +                          unsigned int pin, unsigned long *configs,
>> +                          unsigned int num_configs)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < num_configs; i++) {
>> +            u32 param = pinconf_to_config_param(configs[i]);
>> +            u32 arg = pinconf_to_config_argument(configs[i]);
>> +
> In all of the cases below, I would expect that we should be checking
> the return value for error. Or add a comment on why it is safe to ignore
> the return value if that is the case.
will fix
>> +            switch (param) {
>> +            case PIN_CONFIG_BIAS_DISABLE:
>> +                    airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0);
>> +                    airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0);
>> +                    break;
>> +            case PIN_CONFIG_BIAS_PULL_UP:
>> +                    airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0);
>> +                    airoha_pinctrl_set_pullup_conf(pinctrl, pin, 1);
>> +                    break;
>> +            case PIN_CONFIG_BIAS_PULL_DOWN:
>> +                    airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 1);
>> +                    airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0);
>> +                    break;
>> +            case PIN_CONFIG_DRIVE_STRENGTH: {
>> +                    u32 e2 = 0, e4 = 0;
>> +
>> +                    switch (arg) {
>> +                    case MTK_DRIVE_2mA:
>> +                            break;
>> +                    case MTK_DRIVE_4mA:
>> +                            e2 = 1;
>> +                            break;
>> +                    case MTK_DRIVE_6mA:
>> +                            e4 = 1;
>> +                            break;
>> +                    case MTK_DRIVE_8mA:
>> +                            e2 = 1;
>> +                            e4 = 1;
>> +                            break;
>> +                    default:
>> +                            return -EINVAL;
>> +                    }
>> +
>> +                    airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, e2);
>> +                    airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, e4);
>> +                    break;
>> +            }
>> +            case PIN_CONFIG_DRIVE_OPEN_DRAIN:
>> +                    airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, 
>> !!arg);
>> +                    break;
>> +            case PIN_CONFIG_OUTPUT_ENABLE:
>> +            case PIN_CONFIG_INPUT_ENABLE:
>> +            case PIN_CONFIG_OUTPUT: {
>> +                    bool input = param == PIN_CONFIG_INPUT_ENABLE;
>> +                    int err;
>> +
>> +                    err = airoha_pinmux_set_direction(pinctrl, pin, input);
>> +                    if (err)
>> +                            return err;
>> +
>> +                    if (param == PIN_CONFIG_OUTPUT) {
>> +                            err = airoha_pinconf_set_pin_value(pinctrl,
>> +                                                               pin, !!arg);
>> +                            if (err)
>> +                                    return err;
>> +                    }
>> +
>> +                    break;
>> +            }
>> +            default:
>> +                    return -EOPNOTSUPP;
>> +            }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>
>> +/**************************
>> + * pinctrl driver interface
>> + **************************/
>> +static int airoha_get_pins_count(struct udevice *dev)
>> +{
>> +    struct airoha_pinctrl *pinctrl = dev_get_priv(dev);
>> +
>> +    return pinctrl->data->num_pins;
>> +}
>> +
>> +static const char *airoha_get_pin_name(struct udevice *dev, unsigned 
>> selector)
> Inconsitent use of unsigned. Preferred is unsigned int. 
will fix
>
>> +{
>> +    struct airoha_pinctrl *pinctrl = dev_get_priv(dev);
>> +
>> +    return pinctrl->data->pins[selector].name;
>> +}
>> +
>
>> +static int airoha_pinconf_set_handler(struct udevice *dev, unsigned 
>> pin_selector,
>> +                                  unsigned param, unsigned argument)
>> +{
>> +    struct airoha_pinctrl *pinctrl = dev_get_priv(dev);
>> +    unsigned long configs[1] = { pinconf_to_config_packed(param, argument) 
>> };
>> +    unsigned int pin = pinctrl->data->pins[pin_selector].number;
>> +
>> +    dev_dbg(dev, "enabling %s=%d property for pin %s\n",
>> +            airoha_pinconf_params[param].property, argument,
> This will result in out of bounds access. param is not the index but rather
> a field in the struct in the array.
>
> Easiset would be to just print numeric value of param, otherwise we need a
> lookup function.
yeah, will create a lookup function.
>> +            airoha_get_pin_name(dev, pin_selector));
>> +
>> +    return airoha_pinconf_set(pinctrl, pin, configs,
>> +                              ARRAY_SIZE(configs));
>> +}
>> +
>> +static int airoha_pinconf_group_set_handler(struct udevice *dev, unsigned 
>> group_selector,
>> +                                        unsigned param, unsigned argument)
>> +{
>> +    struct airoha_pinctrl *pinctrl = dev_get_priv(dev);
>> +    unsigned long configs[1] = { pinconf_to_config_packed(param, argument) 
>> };
>> +
>> +    dev_dbg(dev, "enabling %s=%d property for pin group %s\n",
>> +            airoha_pinconf_params[param].property, argument,
> ditto
>
>> +            airoha_get_group_name(dev, group_selector));
>> +
>> +    return airoha_pinconf_group_set(pinctrl, group_selector,
>> +                                    configs, ARRAY_SIZE(configs));
>> +}
>> +
>> +static int airoha_get_pin_muxing(struct udevice *dev, unsigned int selector,
>> +                             char *buf, int size)
>> +{
>> +    struct airoha_pinctrl *pinctrl = dev_get_priv(dev);
>> +    struct airoha_pinctrl_match_data *data = pinctrl->data;
>> +    const char *name, *type;
>> +    int ret, gpio, found = 0;
>> +    unsigned long config;
>> +    unsigned int param, pin;
>> +    u32 val;
>> +
>> +    pin = data->pins[selector].number;
>> +    for (int i = 0; i < data->num_grps; i++) {
>> +            if (!pin_in_group(pin, &data->grps[i]))
>> +                    continue;
>> +
>> +            name = data->grps[i].name;
>> +            for (int j = 0; j < data->num_funcs; j++) {
>> +                    if (!func_grp_active(pinctrl, &data->funcs[j], name))
>> +                            continue;
>> +
>> +                    ret = snprintf(buf, size, "%s(%s)",
>> +                                   data->funcs[j].desc.name, name);
> Should use scnprintf(). snprintf() returns the number that would have been
> written, which can be larger than number actually written.
>
> Same applies elsewhere in this patch.
>
will fix

Reply via email to