diff options
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/gpio.c | 107 | ||||
-rw-r--r-- | include/asm-arm/arch-omap/gpio.h | 57 |
3 files changed, 105 insertions, 60 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4039a133006e..992028f46bd1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -468,6 +468,7 @@ config ARCH_DAVINCI | |||
468 | config ARCH_OMAP | 468 | config ARCH_OMAP |
469 | bool "TI OMAP" | 469 | bool "TI OMAP" |
470 | select GENERIC_GPIO | 470 | select GENERIC_GPIO |
471 | select HAVE_GPIO_LIB | ||
471 | select GENERIC_TIME | 472 | select GENERIC_TIME |
472 | select GENERIC_CLOCKEVENTS | 473 | select GENERIC_CLOCKEVENTS |
473 | help | 474 | help |
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 8c78e4e57b5c..56889fdb0740 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c | |||
@@ -136,7 +136,6 @@ struct gpio_bank { | |||
136 | u16 irq; | 136 | u16 irq; |
137 | u16 virtual_irq_start; | 137 | u16 virtual_irq_start; |
138 | int method; | 138 | int method; |
139 | u32 reserved_map; | ||
140 | #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) | 139 | #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) |
141 | u32 suspend_wakeup; | 140 | u32 suspend_wakeup; |
142 | u32 saved_wakeup; | 141 | u32 saved_wakeup; |
@@ -150,6 +149,7 @@ struct gpio_bank { | |||
150 | u32 saved_risingdetect; | 149 | u32 saved_risingdetect; |
151 | #endif | 150 | #endif |
152 | spinlock_t lock; | 151 | spinlock_t lock; |
152 | struct gpio_chip chip; | ||
153 | }; | 153 | }; |
154 | 154 | ||
155 | #define METHOD_MPUIO 0 | 155 | #define METHOD_MPUIO 0 |
@@ -903,19 +903,17 @@ int omap_request_gpio(int gpio) | |||
903 | { | 903 | { |
904 | struct gpio_bank *bank; | 904 | struct gpio_bank *bank; |
905 | unsigned long flags; | 905 | unsigned long flags; |
906 | int status; | ||
906 | 907 | ||
907 | if (check_gpio(gpio) < 0) | 908 | if (check_gpio(gpio) < 0) |
908 | return -EINVAL; | 909 | return -EINVAL; |
909 | 910 | ||
911 | status = gpio_request(gpio, NULL); | ||
912 | if (status < 0) | ||
913 | return status; | ||
914 | |||
910 | bank = get_gpio_bank(gpio); | 915 | bank = get_gpio_bank(gpio); |
911 | spin_lock_irqsave(&bank->lock, flags); | 916 | spin_lock_irqsave(&bank->lock, flags); |
912 | if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) { | ||
913 | printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio); | ||
914 | dump_stack(); | ||
915 | spin_unlock_irqrestore(&bank->lock, flags); | ||
916 | return -1; | ||
917 | } | ||
918 | bank->reserved_map |= (1 << get_gpio_index(gpio)); | ||
919 | 917 | ||
920 | /* Set trigger to none. You need to enable the desired trigger with | 918 | /* Set trigger to none. You need to enable the desired trigger with |
921 | * request_irq() or set_irq_type(). | 919 | * request_irq() or set_irq_type(). |
@@ -945,10 +943,11 @@ void omap_free_gpio(int gpio) | |||
945 | return; | 943 | return; |
946 | bank = get_gpio_bank(gpio); | 944 | bank = get_gpio_bank(gpio); |
947 | spin_lock_irqsave(&bank->lock, flags); | 945 | spin_lock_irqsave(&bank->lock, flags); |
948 | if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) { | 946 | if (unlikely(!gpiochip_is_requested(&bank->chip, |
947 | get_gpio_index(gpio)))) { | ||
948 | spin_unlock_irqrestore(&bank->lock, flags); | ||
949 | printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio); | 949 | printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio); |
950 | dump_stack(); | 950 | dump_stack(); |
951 | spin_unlock_irqrestore(&bank->lock, flags); | ||
952 | return; | 951 | return; |
953 | } | 952 | } |
954 | #ifdef CONFIG_ARCH_OMAP16XX | 953 | #ifdef CONFIG_ARCH_OMAP16XX |
@@ -965,9 +964,9 @@ void omap_free_gpio(int gpio) | |||
965 | __raw_writel(1 << get_gpio_index(gpio), reg); | 964 | __raw_writel(1 << get_gpio_index(gpio), reg); |
966 | } | 965 | } |
967 | #endif | 966 | #endif |
968 | bank->reserved_map &= ~(1 << get_gpio_index(gpio)); | ||
969 | _reset_gpio(bank, gpio); | 967 | _reset_gpio(bank, gpio); |
970 | spin_unlock_irqrestore(&bank->lock, flags); | 968 | spin_unlock_irqrestore(&bank->lock, flags); |
969 | gpio_free(gpio); | ||
971 | } | 970 | } |
972 | 971 | ||
973 | /* | 972 | /* |
@@ -1266,6 +1265,53 @@ static inline void mpuio_init(void) {} | |||
1266 | 1265 | ||
1267 | /*---------------------------------------------------------------------*/ | 1266 | /*---------------------------------------------------------------------*/ |
1268 | 1267 | ||
1268 | /* REVISIT these are stupid implementations! replace by ones that | ||
1269 | * don't switch on METHOD_* and which mostly avoid spinlocks | ||
1270 | */ | ||
1271 | |||
1272 | static int gpio_input(struct gpio_chip *chip, unsigned offset) | ||
1273 | { | ||
1274 | struct gpio_bank *bank; | ||
1275 | unsigned long flags; | ||
1276 | |||
1277 | bank = container_of(chip, struct gpio_bank, chip); | ||
1278 | spin_lock_irqsave(&bank->lock, flags); | ||
1279 | _set_gpio_direction(bank, offset, 1); | ||
1280 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1281 | return 0; | ||
1282 | } | ||
1283 | |||
1284 | static int gpio_get(struct gpio_chip *chip, unsigned offset) | ||
1285 | { | ||
1286 | return omap_get_gpio_datain(chip->base + offset); | ||
1287 | } | ||
1288 | |||
1289 | static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) | ||
1290 | { | ||
1291 | struct gpio_bank *bank; | ||
1292 | unsigned long flags; | ||
1293 | |||
1294 | bank = container_of(chip, struct gpio_bank, chip); | ||
1295 | spin_lock_irqsave(&bank->lock, flags); | ||
1296 | _set_gpio_dataout(bank, offset, value); | ||
1297 | _set_gpio_direction(bank, offset, 0); | ||
1298 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
1303 | { | ||
1304 | struct gpio_bank *bank; | ||
1305 | unsigned long flags; | ||
1306 | |||
1307 | bank = container_of(chip, struct gpio_bank, chip); | ||
1308 | spin_lock_irqsave(&bank->lock, flags); | ||
1309 | _set_gpio_dataout(bank, offset, value); | ||
1310 | spin_unlock_irqrestore(&bank->lock, flags); | ||
1311 | } | ||
1312 | |||
1313 | /*---------------------------------------------------------------------*/ | ||
1314 | |||
1269 | static int initialized; | 1315 | static int initialized; |
1270 | #if !defined(CONFIG_ARCH_OMAP3) | 1316 | #if !defined(CONFIG_ARCH_OMAP3) |
1271 | static struct clk * gpio_ick; | 1317 | static struct clk * gpio_ick; |
@@ -1293,6 +1339,7 @@ static struct lock_class_key gpio_lock_class; | |||
1293 | static int __init _omap_gpio_init(void) | 1339 | static int __init _omap_gpio_init(void) |
1294 | { | 1340 | { |
1295 | int i; | 1341 | int i; |
1342 | int gpio = 0; | ||
1296 | struct gpio_bank *bank; | 1343 | struct gpio_bank *bank; |
1297 | #if defined(CONFIG_ARCH_OMAP3) | 1344 | #if defined(CONFIG_ARCH_OMAP3) |
1298 | char clk_name[11]; | 1345 | char clk_name[11]; |
@@ -1423,7 +1470,6 @@ static int __init _omap_gpio_init(void) | |||
1423 | int j, gpio_count = 16; | 1470 | int j, gpio_count = 16; |
1424 | 1471 | ||
1425 | bank = &gpio_bank[i]; | 1472 | bank = &gpio_bank[i]; |
1426 | bank->reserved_map = 0; | ||
1427 | bank->base = IO_ADDRESS(bank->base); | 1473 | bank->base = IO_ADDRESS(bank->base); |
1428 | spin_lock_init(&bank->lock); | 1474 | spin_lock_init(&bank->lock); |
1429 | if (bank_is_mpuio(bank)) | 1475 | if (bank_is_mpuio(bank)) |
@@ -1461,6 +1507,26 @@ static int __init _omap_gpio_init(void) | |||
1461 | gpio_count = 32; | 1507 | gpio_count = 32; |
1462 | } | 1508 | } |
1463 | #endif | 1509 | #endif |
1510 | |||
1511 | /* REVISIT eventually switch from OMAP-specific gpio structs | ||
1512 | * over to the generic ones | ||
1513 | */ | ||
1514 | bank->chip.direction_input = gpio_input; | ||
1515 | bank->chip.get = gpio_get; | ||
1516 | bank->chip.direction_output = gpio_output; | ||
1517 | bank->chip.set = gpio_set; | ||
1518 | if (bank_is_mpuio(bank)) { | ||
1519 | bank->chip.label = "mpuio"; | ||
1520 | bank->chip.base = OMAP_MPUIO(0); | ||
1521 | } else { | ||
1522 | bank->chip.label = "gpio"; | ||
1523 | bank->chip.base = gpio; | ||
1524 | gpio += gpio_count; | ||
1525 | } | ||
1526 | bank->chip.ngpio = gpio_count; | ||
1527 | |||
1528 | gpiochip_add(&bank->chip); | ||
1529 | |||
1464 | for (j = bank->virtual_irq_start; | 1530 | for (j = bank->virtual_irq_start; |
1465 | j < bank->virtual_irq_start + gpio_count; j++) { | 1531 | j < bank->virtual_irq_start + gpio_count; j++) { |
1466 | lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class); | 1532 | lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class); |
@@ -1757,8 +1823,10 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) | |||
1757 | 1823 | ||
1758 | for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { | 1824 | for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) { |
1759 | unsigned irq, value, is_in, irqstat; | 1825 | unsigned irq, value, is_in, irqstat; |
1826 | const char *label; | ||
1760 | 1827 | ||
1761 | if (!(bank->reserved_map & mask)) | 1828 | label = gpiochip_is_requested(&bank->chip, j); |
1829 | if (!label) | ||
1762 | continue; | 1830 | continue; |
1763 | 1831 | ||
1764 | irq = bank->virtual_irq_start + j; | 1832 | irq = bank->virtual_irq_start + j; |
@@ -1766,13 +1834,16 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) | |||
1766 | is_in = gpio_is_input(bank, mask); | 1834 | is_in = gpio_is_input(bank, mask); |
1767 | 1835 | ||
1768 | if (bank_is_mpuio(bank)) | 1836 | if (bank_is_mpuio(bank)) |
1769 | seq_printf(s, "MPUIO %2d: ", j); | 1837 | seq_printf(s, "MPUIO %2d ", j); |
1770 | else | 1838 | else |
1771 | seq_printf(s, "GPIO %3d: ", gpio); | 1839 | seq_printf(s, "GPIO %3d ", gpio); |
1772 | seq_printf(s, "%s %s", | 1840 | seq_printf(s, "(%10s): %s %s", |
1841 | label, | ||
1773 | is_in ? "in " : "out", | 1842 | is_in ? "in " : "out", |
1774 | value ? "hi" : "lo"); | 1843 | value ? "hi" : "lo"); |
1775 | 1844 | ||
1845 | /* FIXME for at least omap2, show pullup/pulldown state */ | ||
1846 | |||
1776 | irqstat = irq_desc[irq].status; | 1847 | irqstat = irq_desc[irq].status; |
1777 | if (is_in && ((bank->suspend_wakeup & mask) | 1848 | if (is_in && ((bank->suspend_wakeup & mask) |
1778 | || irqstat & IRQ_TYPE_SENSE_MASK)) { | 1849 | || irqstat & IRQ_TYPE_SENSE_MASK)) { |
@@ -1795,10 +1866,10 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) | |||
1795 | trigger = "high"; | 1866 | trigger = "high"; |
1796 | break; | 1867 | break; |
1797 | case IRQ_TYPE_NONE: | 1868 | case IRQ_TYPE_NONE: |
1798 | trigger = "(unspecified)"; | 1869 | trigger = "(?)"; |
1799 | break; | 1870 | break; |
1800 | } | 1871 | } |
1801 | seq_printf(s, ", irq-%d %s%s", | 1872 | seq_printf(s, ", irq-%d %-8s%s", |
1802 | irq, trigger, | 1873 | irq, trigger, |
1803 | (bank->suspend_wakeup & mask) | 1874 | (bank->suspend_wakeup & mask) |
1804 | ? " wakeup" : ""); | 1875 | ? " wakeup" : ""); |
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h index 164da09be095..86621a04cd8f 100644 --- a/include/asm-arm/arch-omap/gpio.h +++ b/include/asm-arm/arch-omap/gpio.h | |||
@@ -82,62 +82,35 @@ extern void omap_set_gpio_debounce_time(int gpio, int enable); | |||
82 | 82 | ||
83 | /*-------------------------------------------------------------------------*/ | 83 | /*-------------------------------------------------------------------------*/ |
84 | 84 | ||
85 | /* wrappers for "new style" GPIO calls. the old OMAP-specfic ones should | 85 | /* Wrappers for "new style" GPIO calls, using the new infrastructure |
86 | * eventually be removed (along with this errno.h inclusion), and maybe | 86 | * which lets us plug in FPGA, I2C, and other implementations. |
87 | * gpios should put MPUIOs last too. | 87 | * * |
88 | * The original OMAP-specfic calls should eventually be removed. | ||
88 | */ | 89 | */ |
89 | 90 | ||
90 | #include <asm/errno.h> | 91 | #include <linux/errno.h> |
91 | 92 | #include <asm-generic/gpio.h> | |
92 | static inline int gpio_request(unsigned gpio, const char *label) | ||
93 | { | ||
94 | return omap_request_gpio(gpio); | ||
95 | } | ||
96 | |||
97 | static inline void gpio_free(unsigned gpio) | ||
98 | { | ||
99 | omap_free_gpio(gpio); | ||
100 | } | ||
101 | |||
102 | static inline int __gpio_set_direction(unsigned gpio, int is_input) | ||
103 | { | ||
104 | if (cpu_class_is_omap2()) { | ||
105 | if (gpio > OMAP_MAX_GPIO_LINES) | ||
106 | return -EINVAL; | ||
107 | } else { | ||
108 | if (gpio > (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */)) | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | omap_set_gpio_direction(gpio, is_input); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static inline int gpio_direction_input(unsigned gpio) | ||
116 | { | ||
117 | return __gpio_set_direction(gpio, 1); | ||
118 | } | ||
119 | |||
120 | static inline int gpio_direction_output(unsigned gpio, int value) | ||
121 | { | ||
122 | omap_set_gpio_dataout(gpio, value); | ||
123 | return __gpio_set_direction(gpio, 0); | ||
124 | } | ||
125 | 93 | ||
126 | static inline int gpio_get_value(unsigned gpio) | 94 | static inline int gpio_get_value(unsigned gpio) |
127 | { | 95 | { |
128 | return omap_get_gpio_datain(gpio); | 96 | return __gpio_get_value(gpio); |
129 | } | 97 | } |
130 | 98 | ||
131 | static inline void gpio_set_value(unsigned gpio, int value) | 99 | static inline void gpio_set_value(unsigned gpio, int value) |
132 | { | 100 | { |
133 | omap_set_gpio_dataout(gpio, value); | 101 | __gpio_set_value(gpio, value); |
134 | } | 102 | } |
135 | 103 | ||
136 | #include <asm-generic/gpio.h> /* cansleep wrappers */ | 104 | static inline int gpio_cansleep(unsigned gpio) |
105 | { | ||
106 | return __gpio_cansleep(gpio); | ||
107 | } | ||
137 | 108 | ||
138 | static inline int gpio_to_irq(unsigned gpio) | 109 | static inline int gpio_to_irq(unsigned gpio) |
139 | { | 110 | { |
140 | return OMAP_GPIO_IRQ(gpio); | 111 | if (gpio < (OMAP_MAX_GPIO_LINES + 16)) |
112 | return OMAP_GPIO_IRQ(gpio); | ||
113 | return -EINVAL; | ||
141 | } | 114 | } |
142 | 115 | ||
143 | static inline int irq_to_gpio(unsigned irq) | 116 | static inline int irq_to_gpio(unsigned irq) |