[PATCH v3] gpio: UniPhier: add driver for UniPhier GPIO controller

Masahiro Yamada yamada.masahiro at socionext.com
Wed Jul 15 20:44:31 PDT 2015


Hi Linus,


2015-07-15 23:15 GMT+09:00 Linus Walleij <linus.walleij at linaro.org>:
> On Tue, Jul 14, 2015 at 4:43 AM, Masahiro Yamada
> <yamada.masahiro at socionext.com> wrote:
>
>> This GPIO controller device is used on UniPhier SoCs.
>>
>> Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>
>> ---
>>
>> Changes in v3:
>>   - Use module_platform_driver()
>>
>> Changes in v2:
>>   - Fix typos in the comment block
>
> OK why no device tree bindings? Are they in a separate patch?


Sorry, I was planning to do it later.

OK.  I will come back with
Documentation/devicetree/bindings/gpio/uniphier-gpio.txt in binding info in it.


>> +/*
>> + * Unfortunately, the hardware specification adopts weird GPIO pin labeling.
>> + * The ports are named as
>> + *   PORT00,  PORT01,  PORT02,  ..., PORT07,
>> + *   PORT10,  PORT11,  PORT12,  ..., PORT17,
>> + *   PORT20,  PORT21,  PORT22,  ..., PORT27,
>> + *    ...
>> + *   PORT90,  PORT91,  PORT92,  ..., PORT97,
>> + *   PORT100, PORT101, PORT102, ..., PORT107,
>> + *    ...
>> + *
>> + * The PORTs with 8 or 9 in the one's place are missing, i.e. the one's place
>> + * is octal, while the other places are decimal.  If we handle the port numbers
>> + * as seen in the hardware documents, the GPIO offsets must be non-contiguous.
>> + * It is possible to have sparse GPIO pins, but not handy for GPIO range
>> + * mappings, register accessing, etc.
>> + *
>> + * To make things simpler (for driver and device tree implementation), this
>> + * driver takes contiguously-numbered GPIO offsets.  GPIO consumers should make
>> + * sure to convert the PORT number into the one that fits in this driver.
>> + * The conversion logic is very easy math, for example,
>> + *   PORT15  -->  GPIO offset 13   (8 * 1 + 5)
>> + *   PORT123 -->  GPIO offset 99   (8 * 12 + 3)
>> + */
>> +#define UNIPHIER_GPIO_PORTS_PER_BANK   8
>> +#define UNIPHIER_GPIO_BANK_MASK                \
>> +                               ((1UL << (UNIPHIER_GPIO_PORTS_PER_BANK)) - 1)
>
>
>
>> +
>> +#define UNIPHIER_GPIO_REG_DATA         0       /* data */
>> +#define UNIPHIER_GPIO_REG_DIR          4       /* direction (1:in, 0:out) */
>> +
>> +struct uniphier_gpio_priv {
>> +       struct of_mm_gpio_chip mmchip;
>> +       spinlock_t lock;
>> +};
>> +
>> +static unsigned uniphier_gpio_bank_to_reg(unsigned bank, unsigned reg_type)
>> +{
>> +       unsigned reg;
>> +
>> +       reg = (bank + 1) * 8 + reg_type;
>> +
>> +       /*
>> +        * Unfortunately, there is a register hole at offset 0x90-0x9f.
>> +        * Add 0x10 when crossing the hole.
>> +        */
>> +       if (reg >= 0x90)
>> +               reg += 0x10;
>> +
>> +       return reg;
>> +}
>> +
>> +static void uniphier_gpio_bank_write(struct gpio_chip *chip,
>> +                                    unsigned bank, unsigned reg_type,
>> +                                    unsigned mask, unsigned value)
>> +{
>> +       struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
>> +       struct uniphier_gpio_priv *priv;
>> +       unsigned long flags;
>> +       unsigned reg;
>> +       u32 tmp;
>> +
>> +       if (!mask)
>> +               return;
>> +
>> +       priv = container_of(mmchip, struct uniphier_gpio_priv, mmchip);
>> +
>> +       reg = uniphier_gpio_bank_to_reg(bank, reg_type);
>> +
>> +       /*
>> +        * Note
>> +        * regmap_update_bits() should not be used here.
>> +        *
>> +        * The DATA registers return the current readback of pins, not the
>> +        * previously written data when they are configured as "input".
>> +        * The DATA registers must be overwritten even if the data you are
>> +        * going to write is the same as what readl() has returned.
>> +        *
>> +        * regmap_update_bits() does not write back if the data is not changed.
>> +        */
>
> Why is this mentioned when the driver doesn't even use regmap?
> Development artifact?


At first, I thought regmap_update_bits() might be useful,
but it tuned out a bad idea.

Anyway, it did not use regmap in this driver, so this comment sounds a
bit weird.
I will delete it in v4.



>> +static int uniphier_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       return uniphier_gpio_offset_read(chip, UNIPHIER_GPIO_REG_DIR, offset) ?
>> +                                               GPIOF_DIR_IN : GPIOF_DIR_OUT;
>
> Just use
> return !!uniphier_gpio_offset_read(chip, UNIPHIER_GPIO_REG_DIR, offset);


OK, will fix.

>> +static int uniphier_gpio_get(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_REG_DATA);
>
> return !!uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_REG_DATA);

Likewise.


>> +static void uniphier_gpio_set_multiple(struct gpio_chip *chip,
>> +                                      unsigned long *mask,
>> +                                      unsigned long *bits)
>> +{
>> +       unsigned bank, shift, bank_mask, bank_bits;
>> +       int i;
>> +
>> +       for (i = 0; i < chip->ngpio; i += UNIPHIER_GPIO_PORTS_PER_BANK) {
>> +               bank = i / UNIPHIER_GPIO_PORTS_PER_BANK;
>> +               shift = i % BITS_PER_LONG;
>> +               bank_mask = (mask[BIT_WORD(i)] >> shift) &
>> +                                               UNIPHIER_GPIO_BANK_MASK;
>> +               bank_bits = bits[BIT_WORD(i)] >> shift;
>> +
>> +               uniphier_gpio_bank_write(chip, bank, UNIPHIER_GPIO_REG_DATA,
>> +                                        bank_mask, bank_bits);
>> +       }
>
> This looks like a piece of algorithm that we could make generic like in a
> static function in drivers/gpio/gpiolib.h or so, that it may be shared with
> other drivers. Do you see some clear way to break out the core of this?
> Or is it as generic as I think?

I assume this comment has no intention to block my patch.



We already have a generic handling in gpio_chip_set_multiple()
in case .set_multiple() is not supported.

Given that not many drivers support .set_multiple,
I am not sure if we should add another generalized helper func.





>> +static int uniphier_gpio_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct uniphier_gpio_priv *priv;
>> +       u32 ngpio;
>> +       int ret;
>> +
>> +       ret = of_property_read_u32(dev->of_node, "ngpio", &ngpio);
>> +       if (ret) {
>> +               dev_err(dev, "failed to get ngpio property\n");
>> +               return ret;
>> +       }
>
> This needs to be documented, plus I don't see why it's needed.
> The driver for this very specific hardware should already know
> how many GPIOs there are in this hardware, it should not come
> from the device tree.

I want to use this driver on various SoCs, but
the number of GPIO pins varies by SoC.

ngpio == 248 for some SoCs,
and ngpio == 136 for some, etc.


I will document it.


> ngpio is typically for the case where the hardware has 32 bits
> for GPIO pins, but only the first 11 are actually used in the hardware.
>
>> +static const struct of_device_id uniphier_gpio_match[] = {
>> +       { .compatible = "socionext,uniphier-gpio" },
>> +       { /* sentinel */ }
>> +};
>
> Needs a binding document.
>
> Apart from this it looks nice!
>
> Yours,
> Linus Walleij
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Best Regards
Masahiro Yamada



More information about the linux-arm-kernel mailing list