aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2009-01-07 23:14:38 +0800
committerBryan Wu <cooloney@kernel.org>2009-01-07 23:14:38 +0800
commit9570ff4af6920c5992eb91141d71fc94127d864b (patch)
tree8ab0887035ab00a655eb8f78b39ed0acbb0b3bed
parent94106e0fb6b863348a566617ca6bf431c37ddc5e (diff)
Blackfin arch: Allow a gpio pin be requested both as gpio and irq.
[Mike Frysinger <vapier.adi@gmail.com>: - 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 <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier.adi@gmail.com> Signed-off-by: Bryan Wu <cooloney@kernel.org>
-rw-r--r--arch/blackfin/include/asm/gpio.h2
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c82
-rw-r--r--arch/blackfin/mach-common/ints-priority.c25
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);