[PATCH v4 3/5] gpio: msc313: MStar MSC313 GPIO driver

Arnd Bergmann arnd at kernel.org
Wed Dec 9 16:58:09 EST 2020


On Sun, Nov 29, 2020 at 12:12 PM Daniel Palmer <daniel at 0x0f.com> wrote:
>
> This adds a driver that supports the GPIO block found in
> MStar/SigmaStar ARMv7 SoCs.
>
> The controller seems to have enough register for 128 lines
> but where they are wired up differs between chips and
> no currently known chip uses anywhere near 128 lines so there
> needs to be some per-chip data to collect together what lines
> actually have physical pins attached and map the right names to them.

I took a closer  look at the driver now, to figure out why this even
needs a dt-bindings header in the first place. I noticed a few other
things as well:

> +#define OFF_SR_IO3     0x8c
> +#define OFF_SR_IO4     0x90
> +#define OFF_SR_IO5     0x94
> +#define OFF_SR_IO6     0x98
> +#define OFF_SR_IO7     0x9c
> +#define OFF_SR_IO8     0xa0
> +#define OFF_SR_IO9     0xa4
> +#define OFF_SR_IO10    0xa8
> +#define OFF_SR_IO11    0xac
> +#define OFF_SR_IO12    0xb0
> +#define OFF_SR_IO13    0xb4
> +#define OFF_SR_IO14    0xb8
> +#define OFF_SR_IO15    0xbc
> +#define OFF_SR_IO16    0xc0
> +#define OFF_SR_IO17    0xc4
> +
> +#define SR_OFFSETS     \
> +       OFF_SR_IO2,     \
> +       OFF_SR_IO3,     \
> +       OFF_SR_IO4,     \
> +       OFF_SR_IO5,     \
> +       OFF_SR_IO6,     \
> +       OFF_SR_IO7,     \
> +       OFF_SR_IO8,     \
> +       OFF_SR_IO9,     \
> +       OFF_SR_IO10,    \
> +       OFF_SR_IO11,    \
> +       OFF_SR_IO12,    \
> +       OFF_SR_IO13,    \
> +       OFF_SR_IO14,    \
> +       OFF_SR_IO15,    \
> +       OFF_SR_IO16,    \
> +       OFF_SR_IO17
> +
> +#define SD_NAMES               \
> +       MSC313_PINNAME_SD_CLK,  \
> +       MSC313_PINNAME_SD_CMD,  \
> +       MSC313_PINNAME_SD_D0,   \
> +       MSC313_PINNAME_SD_D1,   \
> +       MSC313_PINNAME_SD_D2,   \
> +       MSC313_PINNAME_SD_D3
> +
> +#define OFF_SD_CLK     0x140
> +#define OFF_SD_CMD     0x144
> +#define OFF_SD_D0      0x148
> +#define OFF_SD_D1      0x14c
> +#define OFF_SD_D2      0x150
> +#define OFF_SD_D3      0x154

These seem to just be contiguous ranges, so I probably would have
suggested describing them as separate gpio controllers to avoid
all the complexity with the names. As Linus already merged the
driver into the gpio tree, I won't complain too much about it.

Maybe you can do that for the other chips though and have one
implementation that works for all others, leaving only the msc313
as the one with the extra complexity.

> +#define MSC313_GPIO_CHIPDATA(_chip) \
> static const struct msc313_gpio_data _chip##_data = { \
> +       .names = _chip##_names, \
> +       .offsets = _chip##_offsets, \
> +       .num = ARRAY_SIZE(_chip##_offsets), \
> +}

> +#ifdef CONFIG_MACH_INFINITY
> +static const char * const msc313_names[] = {
> +       FUART_NAMES,
> +       SR_NAMES,

I would try to avoid the #ifdefs and the macros here, don't overthink
it. The macro really hurts readability with the ## concatenation
making it impossible to grep for where things are defined, and
the #ifdef means you get worse compile test coverage compared
to an if(IS_ENABLED()) check in the place where the identifiers
are actually used.

Even better would be to completely avoid the lookup tables here,
and have one driver that is instantiated based on settings from
the DT.

> +struct msc313_gpio {
> +       void __iomem *base;
> +       const struct msc313_gpio_data *gpio_data;
> +       u8 *saved;
> +};
> +
> +static void msc313_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
> +{
> +       struct msc313_gpio *gpio = gpiochip_get_data(chip);
> +       u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
> +
> +       if (value)
> +               gpioreg |= MSC313_GPIO_OUT;
> +       else
> +               gpioreg &= ~MSC313_GPIO_OUT;
> +
> +       writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
> +}

It would be helpful here to replace all the readb_relaxed/writeb_relaxed()
with normal readb()/writeb(). Don't use _relaxed() unless there is a strong
reason why you have to do it, and if you do, explain it in a comment what
the reason is.

> +static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value)
> +{
> +       struct msc313_gpio *gpio = gpiochip_get_data(chip);
> +       u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
> +
> +       gpioreg &= ~MSC313_GPIO_OEN;
> +       if (value)
> +               gpioreg |= MSC313_GPIO_OUT;
> +       else
> +               gpioreg &= ~MSC313_GPIO_OUT;
> +       writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);

These look like they also need a spinlock to avoid races between concurrent
read-modify-write cycles on the same register.

> +builtin_platform_driver(msc313_gpio_driver);

There is a trend to make all drivers optionally loadable modules these days.
Is there a reason this has to be built-in?

       Arnd



More information about the linux-arm-kernel mailing list