diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2006-12-07 02:13:53 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-05-05 11:54:23 +0200 |
commit | b9772a220a0d1b1d83b770ed131fa8b090af3681 (patch) | |
tree | 0411d07d9d054e81bc5e56856293ddada02b448e /arch | |
parent | ARM: OMAP: Implement workaround for GPIO wakeup bug in OMAP2420 silicon (diff) | |
download | linux-b9772a220a0d1b1d83b770ed131fa8b090af3681.tar.xz linux-b9772a220a0d1b1d83b770ed131fa8b090af3681.zip |
ARM: OMAP: /sys/kernel/debug/omap_gpio
Add some GPIO debug support: /sys/kernel/debug/omap_gpio dumps the state
of all GPIOs that have been claimed, including basic IRQ info if relevant.
Tested on 24xx, 16xx.
Includes minor bugfixes: recording IRQ trigger mode (this should probably
be a genirq patch), adding missing space to non-wakeup warning
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/plat-omap/gpio.c | 130 |
1 files changed, 129 insertions, 1 deletions
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index ec0e2f18fdea..0059f19185a7 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -535,6 +535,10 @@ static int gpio_irq_type(unsigned irq, unsigned type) bank = get_gpio_bank(gpio); spin_lock(&bank->lock); retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); + if (retval == 0) { + irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; + irq_desc[irq].status |= type; + } spin_unlock(&bank->lock); return retval; } @@ -701,7 +705,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_lock(&bank->lock); if (enable) { if (bank->non_wakeup_gpios & (1 << gpio)) { - printk(KERN_ERR "Unable to enable wakeup on" + printk(KERN_ERR "Unable to enable wakeup on " "non-wakeup GPIO%d\n", (bank - gpio_bank) * 32 + gpio); spin_unlock(&bank->lock); @@ -1359,3 +1363,127 @@ EXPORT_SYMBOL(omap_set_gpio_dataout); EXPORT_SYMBOL(omap_get_gpio_datain); arch_initcall(omap_gpio_sysinit); + + +#ifdef CONFIG_DEBUG_FS + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static int gpio_is_input(struct gpio_bank *bank, int mask) +{ + void __iomem *reg = bank->base; + + switch (bank->method) { + case METHOD_MPUIO: + reg += OMAP_MPUIO_IO_CNTL; + break; + case METHOD_GPIO_1510: + reg += OMAP1510_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_1610: + reg += OMAP1610_GPIO_DIRECTION; + break; + case METHOD_GPIO_730: + reg += OMAP730_GPIO_DIR_CONTROL; + break; + case METHOD_GPIO_24XX: + reg += OMAP24XX_GPIO_OE; + break; + } + return __raw_readl(reg) & mask; +} + + +static int dbg_gpio_show(struct seq_file *s, void *unused) +{ + unsigned i, j, gpio; + + for (i = 0, gpio = 0; i < gpio_bank_count; i++) { + struct gpio_bank *bank = gpio_bank + i; + unsigned bankwidth = 16; + u32 mask = 1; + + if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) + gpio = OMAP_MPUIO(0); + else if (cpu_is_omap24xx() || cpu_is_omap730()) + bankwidth = 32; + + for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { + unsigned irq, value, is_in, irqstat; + + if (!(bank->reserved_map & mask)) + continue; + + irq = bank->virtual_irq_start + j; + value = omap_get_gpio_datain(gpio); + is_in = gpio_is_input(bank, mask); + + if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) + seq_printf(s, "MPUIO %2d: ", j); + else + seq_printf(s, "GPIO %3d: ", gpio); + seq_printf(s, "%s %s", + is_in ? "in " : "out", + value ? "hi" : "lo"); + + irqstat = irq_desc[irq].status; + if (is_in && ((bank->suspend_wakeup & mask) + || irqstat & IRQ_TYPE_SENSE_MASK)) { + char *trigger = NULL; + + switch (irqstat & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_FALLING: + trigger = "falling"; + break; + case IRQ_TYPE_EDGE_RISING: + trigger = "rising"; + break; + case IRQ_TYPE_EDGE_BOTH: + trigger = "bothedge"; + break; + case IRQ_TYPE_LEVEL_LOW: + trigger = "low"; + break; + case IRQ_TYPE_LEVEL_HIGH: + trigger = "high"; + break; + case IRQ_TYPE_NONE: + trigger = "(unspecified)"; + break; + } + seq_printf(s, ", irq-%d %s%s", + irq, trigger, + (bank->suspend_wakeup & mask) + ? " wakeup" : ""); + } + seq_printf(s, "\n"); + } + + if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) { + seq_printf(s, "\n"); + gpio = 0; + } + } + return 0; +} + +static int dbg_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, dbg_gpio_show, inode->u.generic_ip/*i_private*/); +} + +static const struct file_operations debug_fops = { + .open = dbg_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init omap_gpio_debuginit(void) +{ + (void) debugfs_create_file("omap_gpio", S_IRUGO, NULL, NULL, &debug_fops); + return 0; +} +late_initcall(omap_gpio_debuginit); +#endif |