diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-30 07:04:53 +0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-30 07:04:53 +0400 |
commit | 9ff9a26b786c35ee8d2a66222924a807ec851a9f (patch) | |
tree | db432a17bccca1ca2c16907f0ee83ac449ed4012 /arch/arm/mach-at91/gpio.c | |
parent | 0a3108beea9143225119d5e7c72a8e2c64f3eb7d (diff) | |
parent | 0d34fb8e93ceba7b6dad0062dbb4a0813bacd75b (diff) | |
download | linux-9ff9a26b786c35ee8d2a66222924a807ec851a9f.tar.xz |
Merge commit 'origin/master' into next
Manual merge of:
arch/powerpc/include/asm/elf.h
drivers/i2c/busses/i2c-mpc.c
Diffstat (limited to 'arch/arm/mach-at91/gpio.c')
-rw-r--r-- | arch/arm/mach-at91/gpio.c | 222 |
1 files changed, 157 insertions, 65 deletions
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 2f7d4977dce9..f2236f0e101f 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -24,19 +24,59 @@ #include <mach/at91_pio.h> #include <mach/gpio.h> +#include <asm/gpio.h> + #include "generic.h" +struct at91_gpio_chip { + struct gpio_chip chip; + struct at91_gpio_chip *next; /* Bank sharing same clock */ + struct at91_gpio_bank *bank; /* Bank definition */ + void __iomem *regbase; /* Base of register bank */ +}; -static struct at91_gpio_bank *gpio; -static int gpio_banks; +#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip) + +static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip); +static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val); +static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset); +static int at91_gpiolib_direction_output(struct gpio_chip *chip, + unsigned offset, int val); +static int at91_gpiolib_direction_input(struct gpio_chip *chip, + unsigned offset); +static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset); + +#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio) \ + { \ + .chip = { \ + .label = name, \ + .request = at91_gpiolib_request, \ + .direction_input = at91_gpiolib_direction_input, \ + .direction_output = at91_gpiolib_direction_output, \ + .get = at91_gpiolib_get, \ + .set = at91_gpiolib_set, \ + .dbg_show = at91_gpiolib_dbg_show, \ + .base = base_gpio, \ + .ngpio = nr_gpio, \ + }, \ + } + +static struct at91_gpio_chip gpio_chip[] = { + AT91_GPIO_CHIP("A", 0x00 + PIN_BASE, 32), + AT91_GPIO_CHIP("B", 0x20 + PIN_BASE, 32), + AT91_GPIO_CHIP("C", 0x40 + PIN_BASE, 32), + AT91_GPIO_CHIP("D", 0x60 + PIN_BASE, 32), + AT91_GPIO_CHIP("E", 0x80 + PIN_BASE, 32), +}; +static int gpio_banks; static inline void __iomem *pin_to_controller(unsigned pin) { pin -= PIN_BASE; pin /= 32; if (likely(pin < gpio_banks)) - return gpio[pin].regbase; + return gpio_chip[pin].regbase; return NULL; } @@ -197,39 +237,6 @@ int __init_or_module at91_set_multi_drive(unsigned pin, int is_on) } EXPORT_SYMBOL(at91_set_multi_drive); -/*--------------------------------------------------------------------------*/ - -/* new-style GPIO calls; these expect at91_set_GPIO_periph to have been - * called, and maybe at91_set_multi_drive() for putout pins. - */ - -int gpio_direction_input(unsigned pin) -{ - void __iomem *pio = pin_to_controller(pin); - unsigned mask = pin_to_mask(pin); - - if (!pio || !(__raw_readl(pio + PIO_PSR) & mask)) - return -EINVAL; - __raw_writel(mask, pio + PIO_ODR); - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned pin, int value) -{ - void __iomem *pio = pin_to_controller(pin); - unsigned mask = pin_to_mask(pin); - - if (!pio || !(__raw_readl(pio + PIO_PSR) & mask)) - return -EINVAL; - __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR)); - __raw_writel(mask, pio + PIO_OER); - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); - -/*--------------------------------------------------------------------------*/ - /* * assuming the pin is muxed as a gpio output, set its value. */ @@ -282,7 +289,7 @@ static int gpio_irq_set_wake(unsigned pin, unsigned state) else wakeups[bank] &= ~mask; - set_irq_wake(gpio[bank].id, state); + set_irq_wake(gpio_chip[bank].bank->id, state); return 0; } @@ -292,14 +299,14 @@ void at91_gpio_suspend(void) int i; for (i = 0; i < gpio_banks; i++) { - void __iomem *pio = gpio[i].regbase; + void __iomem *pio = gpio_chip[i].regbase; backups[i] = __raw_readl(pio + PIO_IMR); __raw_writel(backups[i], pio + PIO_IDR); __raw_writel(wakeups[i], pio + PIO_IER); if (!wakeups[i]) - clk_disable(gpio[i].clock); + clk_disable(gpio_chip[i].bank->clock); else { #ifdef CONFIG_PM_DEBUG printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]); @@ -313,10 +320,10 @@ void at91_gpio_resume(void) int i; for (i = 0; i < gpio_banks; i++) { - void __iomem *pio = gpio[i].regbase; + void __iomem *pio = gpio_chip[i].regbase; if (!wakeups[i]) - clk_enable(gpio[i].clock); + clk_enable(gpio_chip[i].bank->clock); __raw_writel(wakeups[i], pio + PIO_IDR); __raw_writel(backups[i], pio + PIO_IER); @@ -380,12 +387,12 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { unsigned pin; struct irq_desc *gpio; - struct at91_gpio_bank *bank; + struct at91_gpio_chip *at91_gpio; void __iomem *pio; u32 isr; - bank = get_irq_chip_data(irq); - pio = bank->regbase; + at91_gpio = get_irq_chip_data(irq); + pio = at91_gpio->regbase; /* temporarily mask (level sensitive) parent IRQ */ desc->chip->ack(irq); @@ -396,14 +403,14 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) */ isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR); if (!isr) { - if (!bank->next) + if (!at91_gpio->next) break; - bank = bank->next; - pio = bank->regbase; + at91_gpio = at91_gpio->next; + pio = at91_gpio->regbase; continue; } - pin = bank->chipbase; + pin = at91_gpio->chip.base; gpio = &irq_desc[pin]; while (isr) { @@ -502,17 +509,17 @@ static struct lock_class_key gpio_lock_class; void __init at91_gpio_irq_setup(void) { unsigned pioc, pin; - struct at91_gpio_bank *this, *prev; + struct at91_gpio_chip *this, *prev; - for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL; + for (pioc = 0, pin = PIN_BASE, this = gpio_chip, prev = NULL; pioc++ < gpio_banks; prev = this, this++) { - unsigned id = this->id; + unsigned id = this->bank->id; unsigned i; __raw_writel(~0, this->regbase + PIO_IDR); - for (i = 0, pin = this->chipbase; i < 32; i++, pin++) { + for (i = 0, pin = this->chip.base; i < 32; i++, pin++) { lockdep_set_class(&irq_desc[pin].lock, &gpio_lock_class); /* @@ -537,32 +544,117 @@ void __init at91_gpio_irq_setup(void) pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks); } +/* gpiolib support */ +static int at91_gpiolib_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + __raw_writel(mask, pio + PIO_ODR); + return 0; +} + +static int at91_gpiolib_direction_output(struct gpio_chip *chip, + unsigned offset, int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + __raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR)); + __raw_writel(mask, pio + PIO_OER); + return 0; +} + +static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + u32 pdsr; + + pdsr = __raw_readl(pio + PIO_PDSR); + return (pdsr & mask) != 0; +} + +static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + __raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR)); +} + +static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset) +{ + unsigned pin = chip->base + offset; + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + /* Cannot request GPIOs that are in alternate function mode */ + if (!(__raw_readl(pio + PIO_PSR) & mask)) + return -EPERM; + + return 0; +} + +static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + int i; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + const char *gpio_label; + + gpio_label = gpiochip_is_requested(chip, i); + if (gpio_label) { + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + if (__raw_readl(pio + PIO_PSR) & mask) + seq_printf(s, "[gpio] %s\n", + at91_get_gpio_value(pin) ? + "set" : "clear"); + else + seq_printf(s, "[periph %s]\n", + __raw_readl(pio + PIO_ABSR) & + mask ? "B" : "A"); + } + } +} + /* * Called from the processor-specific init to enable GPIO pin support. */ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) { unsigned i; - struct at91_gpio_bank *last; + struct at91_gpio_chip *at91_gpio, *last = NULL; BUG_ON(nr_banks > MAX_GPIO_BANKS); - gpio = data; gpio_banks = nr_banks; - for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) { - data->chipbase = PIN_BASE + i * 32; - data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS; + for (i = 0; i < nr_banks; i++) { + at91_gpio = &gpio_chip[i]; + + at91_gpio->bank = &data[i]; + at91_gpio->chip.base = PIN_BASE + i * 32; + at91_gpio->regbase = at91_gpio->bank->offset + + (void __iomem *)AT91_VA_BASE_SYS; /* enable PIO controller's clock */ - clk_enable(data->clock); + clk_enable(at91_gpio->bank->clock); - /* - * Some processors share peripheral ID between multiple GPIO banks. - * SAM9263 (PIOC, PIOD, PIOE) - * CAP9 (PIOA, PIOB, PIOC, PIOD) - */ - if (last && last->id == data->id) - last->next = data; + /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ + if (last && last->bank->id == at91_gpio->bank->id) + last->next = at91_gpio; + last = at91_gpio; + + gpiochip_add(&at91_gpio->chip); } } |