diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2006-12-06 20:13:53 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-05-05 05:54:23 -0400 |
commit | b9772a220a0d1b1d83b770ed131fa8b090af3681 (patch) | |
tree | 0411d07d9d054e81bc5e56856293ddada02b448e /arch/arm/plat-omap/gpio.c | |
parent | 3ac4fa99291a60329e9c9424ac3e67bb4f9564f5 (diff) |
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/arm/plat-omap/gpio.c')
-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) | |||
535 | bank = get_gpio_bank(gpio); | 535 | bank = get_gpio_bank(gpio); |
536 | spin_lock(&bank->lock); | 536 | spin_lock(&bank->lock); |
537 | retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); | 537 | retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type); |
538 | if (retval == 0) { | ||
539 | irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; | ||
540 | irq_desc[irq].status |= type; | ||
541 | } | ||
538 | spin_unlock(&bank->lock); | 542 | spin_unlock(&bank->lock); |
539 | return retval; | 543 | return retval; |
540 | } | 544 | } |
@@ -701,7 +705,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) | |||
701 | spin_lock(&bank->lock); | 705 | spin_lock(&bank->lock); |
702 | if (enable) { | 706 | if (enable) { |
703 | if (bank->non_wakeup_gpios & (1 << gpio)) { | 707 | if (bank->non_wakeup_gpios & (1 << gpio)) { |
704 | printk(KERN_ERR "Unable to enable wakeup on" | 708 | printk(KERN_ERR "Unable to enable wakeup on " |
705 | "non-wakeup GPIO%d\n", | 709 | "non-wakeup GPIO%d\n", |
706 | (bank - gpio_bank) * 32 + gpio); | 710 | (bank - gpio_bank) * 32 + gpio); |
707 | spin_unlock(&bank->lock); | 711 | spin_unlock(&bank->lock); |
@@ -1359,3 +1363,127 @@ EXPORT_SYMBOL(omap_set_gpio_dataout); | |||
1359 | EXPORT_SYMBOL(omap_get_gpio_datain); | 1363 | EXPORT_SYMBOL(omap_get_gpio_datain); |
1360 | 1364 | ||
1361 | arch_initcall(omap_gpio_sysinit); | 1365 | arch_initcall(omap_gpio_sysinit); |
1366 | |||
1367 | |||
1368 | #ifdef CONFIG_DEBUG_FS | ||
1369 | |||
1370 | #include <linux/debugfs.h> | ||
1371 | #include <linux/seq_file.h> | ||
1372 | |||
1373 | static int gpio_is_input(struct gpio_bank *bank, int mask) | ||
1374 | { | ||
1375 | void __iomem *reg = bank->base; | ||
1376 | |||
1377 | switch (bank->method) { | ||
1378 | case METHOD_MPUIO: | ||
1379 | reg += OMAP_MPUIO_IO_CNTL; | ||
1380 | break; | ||
1381 | case METHOD_GPIO_1510: | ||
1382 | reg += OMAP1510_GPIO_DIR_CONTROL; | ||
1383 | break; | ||
1384 | case METHOD_GPIO_1610: | ||
1385 | reg += OMAP1610_GPIO_DIRECTION; | ||
1386 | break; | ||
1387 | case METHOD_GPIO_730: | ||
1388 | reg += OMAP730_GPIO_DIR_CONTROL; | ||
1389 | break; | ||
1390 | case METHOD_GPIO_24XX: | ||
1391 | reg += OMAP24XX_GPIO_OE; | ||
1392 | break; | ||
1393 | } | ||
1394 | return __raw_readl(reg) & mask; | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | static int dbg_gpio_show(struct seq_file *s, void *unused) | ||
1399 | { | ||
1400 | unsigned i, j, gpio; | ||
1401 | |||
1402 | for (i = 0, gpio = 0; i < gpio_bank_count; i++) { | ||
1403 | struct gpio_bank *bank = gpio_bank + i; | ||
1404 | unsigned bankwidth = 16; | ||
1405 | u32 mask = 1; | ||
1406 | |||
1407 | if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) | ||
1408 | gpio = OMAP_MPUIO(0); | ||
1409 | else if (cpu_is_omap24xx() || cpu_is_omap730()) | ||
1410 | bankwidth = 32; | ||
1411 | |||
1412 | for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { | ||
1413 | unsigned irq, value, is_in, irqstat; | ||
1414 | |||
1415 | if (!(bank->reserved_map & mask)) | ||
1416 | continue; | ||
1417 | |||
1418 | irq = bank->virtual_irq_start + j; | ||
1419 | value = omap_get_gpio_datain(gpio); | ||
1420 | is_in = gpio_is_input(bank, mask); | ||
1421 | |||
1422 | if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) | ||
1423 | seq_printf(s, "MPUIO %2d: ", j); | ||
1424 | else | ||
1425 | seq_printf(s, "GPIO %3d: ", gpio); | ||
1426 | seq_printf(s, "%s %s", | ||
1427 | is_in ? "in " : "out", | ||
1428 | value ? "hi" : "lo"); | ||
1429 | |||
1430 | irqstat = irq_desc[irq].status; | ||
1431 | if (is_in && ((bank->suspend_wakeup & mask) | ||
1432 | || irqstat & IRQ_TYPE_SENSE_MASK)) { | ||
1433 | char *trigger = NULL; | ||
1434 | |||
1435 | switch (irqstat & IRQ_TYPE_SENSE_MASK) { | ||
1436 | case IRQ_TYPE_EDGE_FALLING: | ||
1437 | trigger = "falling"; | ||
1438 | break; | ||
1439 | case IRQ_TYPE_EDGE_RISING: | ||
1440 | trigger = "rising"; | ||
1441 | break; | ||
1442 | case IRQ_TYPE_EDGE_BOTH: | ||
1443 | trigger = "bothedge"; | ||
1444 | break; | ||
1445 | case IRQ_TYPE_LEVEL_LOW: | ||
1446 | trigger = "low"; | ||
1447 | break; | ||
1448 | case IRQ_TYPE_LEVEL_HIGH: | ||
1449 | trigger = "high"; | ||
1450 | break; | ||
1451 | case IRQ_TYPE_NONE: | ||
1452 | trigger = "(unspecified)"; | ||
1453 | break; | ||
1454 | } | ||
1455 | seq_printf(s, ", irq-%d %s%s", | ||
1456 | irq, trigger, | ||
1457 | (bank->suspend_wakeup & mask) | ||
1458 | ? " wakeup" : ""); | ||
1459 | } | ||
1460 | seq_printf(s, "\n"); | ||
1461 | } | ||
1462 | |||
1463 | if (!cpu_is_omap24xx() && bank->method == METHOD_MPUIO) { | ||
1464 | seq_printf(s, "\n"); | ||
1465 | gpio = 0; | ||
1466 | } | ||
1467 | } | ||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static int dbg_gpio_open(struct inode *inode, struct file *file) | ||
1472 | { | ||
1473 | return single_open(file, dbg_gpio_show, inode->u.generic_ip/*i_private*/); | ||
1474 | } | ||
1475 | |||
1476 | static const struct file_operations debug_fops = { | ||
1477 | .open = dbg_gpio_open, | ||
1478 | .read = seq_read, | ||
1479 | .llseek = seq_lseek, | ||
1480 | .release = single_release, | ||
1481 | }; | ||
1482 | |||
1483 | static int __init omap_gpio_debuginit(void) | ||
1484 | { | ||
1485 | (void) debugfs_create_file("omap_gpio", S_IRUGO, NULL, NULL, &debug_fops); | ||
1486 | return 0; | ||
1487 | } | ||
1488 | late_initcall(omap_gpio_debuginit); | ||
1489 | #endif | ||