From 9570ff4af6920c5992eb91141d71fc94127d864b Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 7 Jan 2009 23:14:38 +0800 Subject: Blackfin arch: Allow a gpio pin be requested both as gpio and irq. [Mike Frysinger : - use KERN_NOTICE when using gpios as both irq and non rather than KERN_ERR - embedded newlines in printk() does not fly] Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/gpio.h | 2 + arch/blackfin/kernel/bfin_gpio.c | 82 ++++++++++++++++++++++++++++--- arch/blackfin/mach-common/ints-priority.c | 25 +++++----- 3 files changed, 91 insertions(+), 18 deletions(-) diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h index ec2ab465709..4ee687f34fe 100644 --- a/arch/blackfin/include/asm/gpio.h +++ b/arch/blackfin/include/asm/gpio.h @@ -548,6 +548,8 @@ struct gpio_port_s { int bfin_gpio_request(unsigned gpio, const char *label); void bfin_gpio_free(unsigned gpio); +int bfin_gpio_irq_request(unsigned gpio, const char *label); +void bfin_gpio_irq_free(unsigned gpio); int bfin_gpio_direction_input(unsigned gpio); int bfin_gpio_direction_output(unsigned gpio, int value); int bfin_gpio_get_value(unsigned gpio); diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index de235b8f37a..2c72b15b71b 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -179,6 +179,7 @@ static struct gpio_port_t *gpio_array[] = { static unsigned short reserved_gpio_map[GPIO_BANK_NUM]; static unsigned short reserved_peri_map[gpio_bank(MAX_RESOURCES)]; +static unsigned short reserved_gpio_irq_map[GPIO_BANK_NUM]; #define RESOURCE_LABEL_SIZE 16 @@ -1043,7 +1044,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", - gpio, get_label(gpio)); + gpio, get_label(gpio)); local_irq_restore(flags); return -EBUSY; } @@ -1055,13 +1056,16 @@ int bfin_gpio_request(unsigned gpio, const char *label) local_irq_restore(flags); return -EBUSY; } + if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) + printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved as gpio-irq!" + " (Documentation/blackfin/bfin-gpio-notes.txt)\n", gpio); reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); + set_label(gpio, label); local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); - set_label(gpio, label); return 0; } @@ -1091,6 +1095,69 @@ void bfin_gpio_free(unsigned gpio) } EXPORT_SYMBOL(bfin_gpio_free); +int bfin_gpio_irq_request(unsigned gpio, const char *label) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return -EINVAL; + + local_irq_save(flags); + + if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + dump_stack(); + printk(KERN_ERR + "bfin-gpio: GPIO %d is already reserved as gpio-irq !\n", + gpio); + local_irq_restore(flags); + return -EBUSY; + } + if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + dump_stack(); + printk(KERN_ERR + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + local_irq_restore(flags); + return -EBUSY; + } + if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) + printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved by %s! " + "(Documentation/blackfin/bfin-gpio-notes.txt)\n", + gpio, get_label(gpio)); + + reserved_gpio_irq_map[gpio_bank(gpio)] |= gpio_bit(gpio); + set_label(gpio, label); + + local_irq_restore(flags); + + port_setup(gpio, GPIO_USAGE); + + return 0; +} + +void bfin_gpio_irq_free(unsigned gpio) +{ + unsigned long flags; + + if (check_gpio(gpio) < 0) + return; + + local_irq_save(flags); + + if (unlikely(!(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { + dump_stack(); + gpio_error(gpio); + local_irq_restore(flags); + return; + } + + reserved_gpio_irq_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + + set_label(gpio, "free"); + + local_irq_restore(flags); +} + #ifdef BF548_FAMILY int bfin_gpio_direction_input(unsigned gpio) @@ -1253,12 +1320,15 @@ void bfin_gpio_irq_prepare(unsigned gpio) static int gpio_proc_read(char *buf, char **start, off_t offset, int len, int *unused_i, void *unused_v) { - int c, outlen = 0; + int c, irq, gpio, outlen = 0; for (c = 0; c < MAX_RESOURCES; c++) { - if (!check_gpio(c) && (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c))) - len = sprintf(buf, "GPIO_%d: \t%s \t\tGPIO %s\n", c, - get_label(c), get_gpio_dir(c) ? "OUTPUT" : "INPUT"); + irq = reserved_gpio_irq_map[gpio_bank(c)] & gpio_bit(c); + gpio = reserved_gpio_map[gpio_bank(c)] & gpio_bit(c); + if (!check_gpio(c) && (gpio || irq)) + len = sprintf(buf, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c, + get_label(c), (gpio && irq) ? " *" : "", + get_gpio_dir(c) ? "OUTPUT" : "INPUT"); else if (reserved_peri_map[gpio_bank(c)] & gpio_bit(c)) len = sprintf(buf, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c)); else diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index a0bfca92171..7c1db775751 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -432,7 +432,7 @@ static void bfin_gpio_irq_shutdown(unsigned int irq) bfin_gpio_mask_irq(irq); __clear_bit(gpionr, gpio_enabled); - bfin_gpio_free(gpionr); + bfin_gpio_irq_free(gpionr); } static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) @@ -441,11 +441,6 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) char buf[16]; u32 gpionr = irq_to_gpio(irq); - snprintf(buf, 16, "gpio-irq%d", irq); - ret = bfin_gpio_request(gpionr, buf); - if (ret) - return ret; - if (type == IRQ_TYPE_PROBE) { /* only probe unenabled GPIO interrupt lines */ if (__test_bit(gpionr, gpio_enabled)) @@ -456,6 +451,11 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + snprintf(buf, 16, "gpio-irq%d", irq); + ret = bfin_gpio_irq_request(gpionr, buf); + if (ret) + return ret; + if (__test_and_set_bit(gpionr, gpio_enabled)) bfin_gpio_irq_prepare(gpionr); @@ -740,7 +740,7 @@ static void bfin_gpio_irq_shutdown(unsigned int irq) bfin_gpio_mask_irq(irq); __clear_bit(gpionr, gpio_enabled); - bfin_gpio_free(gpionr); + bfin_gpio_irq_free(gpionr); } static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) @@ -755,11 +755,6 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) if (pint_val == IRQ_NOT_AVAIL) return -ENODEV; - snprintf(buf, 16, "gpio-irq%d", irq); - ret = bfin_gpio_request(gpionr, buf); - if (ret) - return ret; - if (type == IRQ_TYPE_PROBE) { /* only probe unenabled GPIO interrupt lines */ if (__test_bit(gpionr, gpio_enabled)) @@ -769,6 +764,12 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + + snprintf(buf, 16, "gpio-irq%d", irq); + ret = bfin_gpio_irq_request(gpionr, buf); + if (ret) + return ret; + if (__test_and_set_bit(gpionr, gpio_enabled)) bfin_gpio_irq_prepare(gpionr); -- cgit v1.2.3