[PATCH 6/8] gpio-tz1090: add TZ1090 gpio driver
Linus Walleij
linus.walleij at linaro.org
Fri Apr 26 09:01:01 EST 2013
On Tue, Apr 23, 2013 at 4:33 PM, James Hogan <james.hogan at imgtec.com> wrote:
> Add a GPIO driver for the main GPIOs found in the TZ1090 (Comet) SoC.
> This doesn't include low-power GPIOs as they're controlled separately
> via the Powerdown Controller (PDC) registers.
>
> The driver is instantiated by device tree and supports interrupts for
> all GPIOs.
>
> Signed-off-by: James Hogan <james.hogan at imgtec.com>
> Cc: Grant Likely <grant.likely at secretlab.ca>
> Cc: Rob Herring <rob.herring at calxeda.com>
> Cc: Rob Landley <rob at landley.net>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: linux-doc at vger.kernel.org
(...)
> + - #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
> + nodes should have the following values.
> + <[phandle of the gpio controller node]
> + [gpio number within the gpio bank]
> + [standard Linux gpio flags]>
So when someone using this device tree for Symbian or Windows
Mobile start to work, what does "standard Linux gpio flags" tell them?
> + Values for gpio specifier:
> + - GPIO number: a value in the range 0 to 29.
> + - GPIO flags: standard Linux GPIO flags as found in of_gpio.h
Dito. Linux-specifics are not generally allowed in device trees,
and if they are anyway used they shall be prefixed with "linux,"
> + Bank subnode optional properties:
> + - gpio-ranges: Mapping to pin controller pins
Here you seem to use DT GPIO ranges, yet the pinctrl driver registers
some GPIO range, care to explain how that fits together?
> + - #interrupt-cells: Should be 2. The syntax of the interrupt specifier used by
> + client nodes should have the following values.
> + <[phandle of the interurupt controller]
> + [gpio number within the gpio bank]
> + [standard Linux irq flags]>
> +
> + Values for irq specifier:
> + - GPIO number: a value in the range 0 to 29
> + - IRQ flags: standard Linux IRQ flags for edge and level triggering
Same comments.
(...)
+#include <asm/global_lock.h>
What on earth is that. I can only fear it. I don't like the
looks of that thing.
(...)
> +/* Convenience register accessors */
> +static void tz1090_gpio_write(struct tz1090_gpio_bank *bank,
> + unsigned int reg_offs, u32 data)
> +{
> + iowrite32(data, bank->reg + reg_offs);
> +}
> +
> +static u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank,
> + unsigned int reg_offs)
> +{
> + return ioread32(bank->reg + reg_offs);
> +}
The pinctrl driver included the keyword "inline" for these so
this should be consistent and do that too.
(...)
> +static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
> + unsigned int reg_offs,
> + unsigned int offset)
> +{
> + int lstat;
> +
> + __global_lock2(lstat);
> + _tz1090_gpio_clear_bit(bank, reg_offs, offset);
> + __global_unlock2(lstat);
> +}
This global lock scares me.
+static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ u32 value;
+
+ value = tz1090_gpio_read(bank, reg_offs);
+ value &= ~(0x1 << offset);
I usually do this:
#include <linux/bitops.h>
value &= ~BIT(offset);
+ tz1090_gpio_write(bank, reg_offs, value);
+}
> +/* caller must hold LOCK2 */
> +static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
> + unsigned int reg_offs,
> + unsigned int offset)
> +{
> + u32 value;
> +
> + value = tz1090_gpio_read(bank, reg_offs);
> + value |= 0x1 << offset;
I usually do this:
#include <linux/bitops.h>
value |= BIT(offset);
> +/* caller must hold LOCK2 */
> +static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
> + unsigned int reg_offs,
> + unsigned int offset,
> + int val)
If val is used as it is, make it a bool.
> +{
> + u32 value;
> +
> + value = tz1090_gpio_read(bank, reg_offs);
> + value &= ~(0x1 << offset);
> + value |= !!val << offset;
You're claming val to [0,1] obviously it's a bool.
> + tz1090_gpio_write(bank, reg_offs, value);
> +}
(...)
> +static int tz1090_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> + struct tz1090_gpio_bank *bank = to_bank(chip);
> + int ret;
> +
> + ret = pinctrl_request_gpio(chip->base + offset);
> + if (ret)
> + return ret;
> +
> + tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
> + tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset);
> +
> + return 0;
> +}
This is nice, it just glues smoothly into pinctrl here.
> +static void tz1090_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> + struct tz1090_gpio_bank *bank = to_bank(chip);
> +
> + pinctrl_free_gpio(chip->base + offset);
> +
> + tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset);
> +}
And here.
(...)
> +static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type)
> +{
> + struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
> + unsigned int type;
> + unsigned int polarity;
> +
> + switch (flow_type) {
> + case IRQ_TYPE_EDGE_BOTH:
> + type = GPIO_EDGE_TRIGGERED;
> + polarity = GPIO_POLARITY_LOW;
> + break;
> + case IRQ_TYPE_EDGE_RISING:
> + type = GPIO_EDGE_TRIGGERED;
> + polarity = GPIO_POLARITY_HIGH;
> + break;
> + case IRQ_TYPE_EDGE_FALLING:
> + type = GPIO_EDGE_TRIGGERED;
> + polarity = GPIO_POLARITY_LOW;
> + break;
> + case IRQ_TYPE_LEVEL_HIGH:
> + type = GPIO_LEVEL_TRIGGERED;
> + polarity = GPIO_POLARITY_HIGH;
> + break;
> + case IRQ_TYPE_LEVEL_LOW:
> + type = GPIO_LEVEL_TRIGGERED;
> + polarity = GPIO_POLARITY_LOW;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + tz1090_gpio_irq_type(bank, data->hwirq, type);
> + if (type == GPIO_LEVEL_TRIGGERED)
> + __irq_set_handler_locked(data->irq, handle_level_irq);
> + else
> + __irq_set_handler_locked(data->irq, handle_edge_irq);
> +
> + if (flow_type == IRQ_TYPE_EDGE_BOTH)
> + tz1090_gpio_irq_next_edge(bank, data->hwirq);
> + else
> + tz1090_gpio_irq_polarity(bank, data->hwirq, polarity);
> +
> + return 0;
> +}
This is also very nice and handling the toggling edge in
a working way.
Overall looking very nice, just needs som polishing, and I'm way
scared about that global lock.
Yours,
Linus Walleij
More information about the devicetree-discuss
mailing list