diff options
author | Simon Glass <sjg@chromium.org> | 2014-10-29 13:08:57 -0600 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2014-11-21 08:08:19 +0100 |
commit | 918354b18e190a0e42748457470db539ed12fde3 (patch) | |
tree | 0cfcc83d786e8ac35ccd9c8330361c7722ae05f0 | |
parent | cd052cd9353cb483e3a4852cedbd6860bfb488c4 (diff) |
dm: at91: Add driver model support for atmel GPIO driver
Modify this driver to support driver model, with platform data required to
determine the GPIOs that it controls.
Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | arch/arm/include/asm/arch-at91/gpio.h | 6 | ||||
-rw-r--r-- | drivers/gpio/at91_gpio.c | 241 |
2 files changed, 193 insertions, 54 deletions
diff --git a/arch/arm/include/asm/arch-at91/gpio.h b/arch/arm/include/asm/arch-at91/gpio.h index 71213883d7..6d2a7b72ff 100644 --- a/arch/arm/include/asm/arch-at91/gpio.h +++ b/arch/arm/include/asm/arch-at91/gpio.h @@ -253,4 +253,10 @@ static inline unsigned at91_gpio_to_pin(unsigned gpio) return gpio % 32; } +/* Platform data for each GPIO port */ +struct at91_port_platdata { + uint32_t base_addr; + const char *bank_name; +}; + #endif /* __ASM_ARCH_AT91_GPIO_H */ diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c index 6517af1628..6129c020ea 100644 --- a/drivers/gpio/at91_gpio.c +++ b/drivers/gpio/at91_gpio.c @@ -10,11 +10,14 @@ #include <config.h> #include <common.h> +#include <dm.h> #include <asm/io.h> #include <linux/sizes.h> +#include <asm/gpio.h> #include <asm/arch/hardware.h> #include <asm/arch/at91_pio.h> -#include <asm/arch/gpio.h> + +#define GPIO_PER_BANK 32 static struct at91_port *at91_pio_get_port(unsigned port) { @@ -39,19 +42,25 @@ static struct at91_port *at91_pio_get_port(unsigned port) } } +static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + if (use_pullup) + writel(mask, &at91_port->puer); + else + writel(mask, &at91_port->pudr); + writel(mask, &at91_port->per); +} + int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (use_pullup) - writel(1 << pin, &at91_port->puer); - else - writel(1 << pin, &at91_port->pudr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_pullup(at91_port, pin, use_pullup); return 0; } @@ -64,7 +73,7 @@ int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -82,7 +91,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -108,7 +117,7 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -135,7 +144,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -157,7 +166,7 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -172,6 +181,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) } #endif +#ifdef CONFIG_DM_GPIO +static bool at91_get_port_output(struct at91_port *at91_port, int offset) +{ + u32 mask, val; + + mask = 1 << offset; + val = readl(&at91_port->osr); + return val & mask; +} +#endif + +static void at91_set_port_input(struct at91_port *at91_port, int offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + at91_set_port_pullup(at91_port, offset, use_pullup); + writel(mask, &at91_port->odr); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and * configure it for an input. @@ -179,19 +211,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - at91_set_pio_pullup(port, pin, use_pullup); - writel(mask, &at91_port->odr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_input(at91_port, pin, use_pullup); return 0; } +static void at91_set_port_output(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + writel(mask, &at91_port->pudr); + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); + writel(mask, &at91_port->oer); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), * and configure it for an output. @@ -199,19 +241,9 @@ int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) int at91_set_pio_output(unsigned port, u32 pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - writel(mask, &at91_port->pudr); - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - writel(mask, &at91_port->oer); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_output(at91_port, pin, value); return 0; } @@ -224,7 +256,7 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { #if defined(CPU_HAS_PIO3) @@ -248,7 +280,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { writel(mask, &at91_port->ifscer); @@ -271,7 +303,7 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->pudr); if (is_on) @@ -291,7 +323,7 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(readl(&at91_port->schmitt) | mask, &at91_port->schmitt); @@ -310,7 +342,7 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) writel(mask, &at91_port->mder); @@ -321,41 +353,54 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) return 0; } +static void at91_set_port_value(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); +} + /* * assuming the pin is muxed as a gpio output, set its value. */ int at91_set_pio_value(unsigned port, unsigned pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_value(at91_port, pin, value); return 0; } +static int at91_get_port_value(struct at91_port *at91_port, int offset) +{ + u32 pdsr = 0, mask; + + mask = 1 << offset; + pdsr = readl(&at91_port->pdsr) & mask; + + return pdsr != 0; +} /* * read the pin's value (works even if it's not muxed as a gpio). */ int at91_get_pio_value(unsigned port, unsigned pin) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 pdsr = 0, mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - pdsr = readl(&at91_port->pdsr) & mask; - } + if (at91_port && (pin < GPIO_PER_BANK)) + return at91_get_port_value(at91_port, pin); - return pdsr != 0; + return 0; } +#ifndef CONFIG_DM_GPIO /* Common GPIO API */ int gpio_request(unsigned gpio, const char *label) @@ -395,3 +440,91 @@ int gpio_set_value(unsigned gpio, int value) return 0; } +#endif + +#ifdef CONFIG_DM_GPIO + +struct at91_port_priv { + struct at91_port *regs; +}; + +/* set GPIO pin 'gpio' as an input */ +static int at91_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_input(port->regs, offset, 0); + + return 0; +} + +/* set GPIO pin 'gpio' as an output, with polarity 'value' */ +static int at91_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_output(port->regs, offset, value); + + return 0; +} + +/* read GPIO IN value of pin 'gpio' */ +static int at91_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + return at91_get_port_value(port->regs, offset); +} + +/* write GPIO OUT value to pin 'gpio' */ +static int at91_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_value(port->regs, offset, value); + + return 0; +} + +static int at91_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + /* GPIOF_FUNC is not implemented yet */ + if (at91_get_port_output(port->regs, offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_at91_ops = { + .direction_input = at91_gpio_direction_input, + .direction_output = at91_gpio_direction_output, + .get_value = at91_gpio_get_value, + .set_value = at91_gpio_set_value, + .get_function = at91_gpio_get_function, +}; + +static int at91_gpio_probe(struct udevice *dev) +{ + struct at91_port_priv *port = dev_get_priv(dev); + struct at91_port_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + uc_priv->bank_name = plat->bank_name; + uc_priv->gpio_count = GPIO_PER_BANK; + port->regs = (struct at91_port *)plat->base_addr; + + return 0; +} + +U_BOOT_DRIVER(gpio_at91) = { + .name = "gpio_at91", + .id = UCLASS_GPIO, + .ops = &gpio_at91_ops, + .probe = at91_gpio_probe, + .priv_auto_alloc_size = sizeof(struct at91_port_priv), +}; +#endif |