diff options
| author | Linus Torvalds <[email protected]> | 2009-03-28 14:03:14 -0700 | 
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2009-03-28 14:03:14 -0700 | 
| commit | 0fe41b8982001cd14ee2c77cd776735a5024e98b (patch) | |
| tree | 83e65d595c413d55259ea14fb97748ce5efe5707 /arch/arm/mach-at91/gpio.c | |
| parent | eedf2c5296a8dfaaf9aec1a938c1d3bd73159a30 (diff) | |
| parent | 9759d22c8348343b0da4e25d6150c41712686c14 (diff) | |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (422 commits)
  [ARM] 5435/1: fix compile warning in sanity_check_meminfo()
  [ARM] 5434/1: ARM: OMAP: Fix mailbox compile for 24xx
  [ARM] pxa: fix the bad assumption that PCMCIA sockets always start with 0
  [ARM] pxa: fix Colibri PXA300 and PXA320 LCD backlight pins
  imxfb: Fix TFT mode
  i.MX21/27: remove ifdef CONFIG_FB_IMX
  imxfb: add clock support
  mxc: add arch_reset() function
  clkdev: add possibility to get a clock based on the device name
  i.MX1: remove fb support from mach-imx
  [ARM] pxa: build arch/arm/plat-pxa/mfp.c only when PXA3xx or ARCH_MMP defined
  Gemini: Add support for Teltonika RUT100
  Gemini: gpiolib based GPIO support v2
  MAINTAINERS: add myself as Gemini architecture maintainer
  ARM: Add Gemini architecture v3
  [ARM] OMAP: Fix compile for omap2_init_common_hw()
  MAINTAINERS: Add myself as Faraday ARM core variant maintainer
  ARM: Add support for FA526 v2
  [ARM] acorn,ebsa110,footbridge,integrator,sa1100: Convert asm/io.h to linux/io.h
  [ARM] collie: fix two minor formatting nits
  ...
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);  	}  } |