diff options
| author | Andres Salomon <dilinger@queued.net> | 2011-01-12 17:00:10 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 08:03:13 -0800 | 
| commit | 1b912c1bca5c162e611384fe7d39c916e081701a (patch) | |
| tree | ae3a1c48954cec0a7f9d0b16207e9bfe6c4d22e6 | |
| parent | 5f003feba2a8761d2ee7b367df5a0fe6b729dc8f (diff) | |
| download | olio-linux-3.10-1b912c1bca5c162e611384fe7d39c916e081701a.tar.xz olio-linux-3.10-1b912c1bca5c162e611384fe7d39c916e081701a.zip  | |
drivers/gpio/cs5535-gpio.c: add some additional cs5535-specific GPIO functionality
This adds (well, re-adds actually) handling for events/IRQs through cs5535
GPIOs.  In the wild and wooly world of CS5535, setup_event() is for
assigning an IRQ to a GPIO filter/event pair, and set_irq() sets up the
pair to trigger IRQs.
These should really only be used in highly platform-specific drivers (such
as OLPC's DCON driver).  Sadly, because set_irq() uses MSRs, this causes
the driver to become X86-specific.
Signed-off-by: Andres Salomon <dilinger@queued.net>
Signed-off-by: Daniel Drake <dsd@laptop.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpio/cs5535-gpio.c | 52 | ||||
| -rw-r--r-- | include/linux/cs5535.h | 2 | 
3 files changed, 55 insertions, 1 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 082495bb08a..bfa276a9541 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -295,7 +295,7 @@ comment "PCI GPIO expanders:"  config GPIO_CS5535  	tristate "AMD CS5535/CS5536 GPIO support" -	depends on PCI && !CS5535_GPIO +	depends on PCI && X86 && !CS5535_GPIO  	help  	  The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that  	  can be used for quite a number of things.  The CS5535/6 is found on diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index d3e55a0ae92..815d98b2c1b 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -15,6 +15,7 @@  #include <linux/gpio.h>  #include <linux/io.h>  #include <linux/cs5535.h> +#include <asm/msr.h>  #define DRV_NAME "cs5535-gpio"  #define GPIO_BAR 1 @@ -144,6 +145,57 @@ int cs5535_gpio_isset(unsigned offset, unsigned int reg)  }  EXPORT_SYMBOL_GPL(cs5535_gpio_isset); +int cs5535_gpio_set_irq(unsigned group, unsigned irq) +{ +	uint32_t lo, hi; + +	if (group > 7 || irq > 15) +		return -EINVAL; + +	rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); + +	lo &= ~(0xF << (group * 4)); +	lo |= (irq & 0xF) << (group * 4); + +	wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); +	return 0; +} +EXPORT_SYMBOL_GPL(cs5535_gpio_set_irq); + +void cs5535_gpio_setup_event(unsigned offset, int pair, int pme) +{ +	struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; +	uint32_t shift = (offset % 8) * 4; +	unsigned long flags; +	uint32_t val; + +	if (offset >= 24) +		offset = GPIO_MAP_W; +	else if (offset >= 16) +		offset = GPIO_MAP_Z; +	else if (offset >= 8) +		offset = GPIO_MAP_Y; +	else +		offset = GPIO_MAP_X; + +	spin_lock_irqsave(&chip->lock, flags); +	val = inl(chip->base + offset); + +	/* Clear whatever was there before */ +	val &= ~(0xF << shift); + +	/* Set the new value */ +	val |= ((pair & 7) << shift); + +	/* Set the PME bit if this is a PME event */ +	if (pme) +		val |= (1 << (shift + 3)); + +	outl(val, chip->base + offset); +	spin_unlock_irqrestore(&chip->lock, flags); +} +EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event); +  /*   * Generic gpio_chip API support.   */ diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h index d5a1d4810b8..213cc50b580 100644 --- a/include/linux/cs5535.h +++ b/include/linux/cs5535.h @@ -111,6 +111,8 @@ static inline int cs5535_has_vsa2(void)  void cs5535_gpio_set(unsigned offset, unsigned int reg);  void cs5535_gpio_clear(unsigned offset, unsigned int reg);  int cs5535_gpio_isset(unsigned offset, unsigned int reg); +int cs5535_gpio_set_irq(unsigned group, unsigned irq); +void cs5535_gpio_setup_event(unsigned offset, int pair, int pme);  /* MFGPTs */  |