X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fcris%2Farch-v10%2Fdrivers%2Fgpio.c;h=16729107351e96e0ba7c722c43a1d430ef2dc8d9;hb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;hp=f3a57162bde110214e26ac64f80ac01dc0a4c88f;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index f3a57162b..167291073 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.8 2003/07/04 08:27:37 starvik Exp $ +/* $Id: gpio.c,v 1.11 2004/05/14 07:58:03 starvik Exp $ * * Etrax general port I/O device * @@ -9,6 +9,12 @@ * Johan Adolfsson (read/set directions, write, port G) * * $Log: gpio.c,v $ + * Revision 1.11 2004/05/14 07:58:03 starvik + * Merge of changes from 2.4 + * + * Revision 1.9 2003/09/11 07:29:48 starvik + * Merge of Linux 2.6.0-test5 + * * Revision 1.8 2003/07/04 08:27:37 starvik * Merge of Linux 2.5.74 * @@ -183,6 +189,7 @@ struct gpio_private { static struct gpio_private *alarmlist = 0; static int gpio_some_alarms = 0; /* Set if someone uses alarm */ +static unsigned long gpio_pa_irq_enabled_mask = 0; /* Port A and B use 8 bit access, but Port G is 32 bit */ #define NUM_PORTS (GPIO_MINOR_B+1) @@ -252,13 +259,19 @@ gpio_poll(struct file *file, unsigned long data; poll_wait(file, &priv->alarm_wq, wait); if (priv->minor == GPIO_MINOR_A) { + unsigned long flags; unsigned long tmp; data = *R_PORT_PA_DATA; /* PA has support for high level interrupt - * lets activate for those low and with highalarm set */ tmp = ~data & priv->highalarm & 0xFF; - *R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); + tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); + save_flags(flags); cli(); + gpio_pa_irq_enabled_mask |= tmp; + *R_IRQ_MASK1_SET = tmp; + restore_flags(flags); + } else if (priv->minor == GPIO_MINOR_B) data = *R_PORT_PB_DATA; else if (priv->minor == GPIO_MINOR_G) @@ -312,12 +325,15 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long tmp; /* Find what PA interrupts are active */ - tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF; + tmp = (*R_IRQ_READ1); + + /* Find those that we have enabled */ + tmp &= gpio_pa_irq_enabled_mask; + /* Clear them.. */ - /* NOTE: Maybe we need to be more careful here if some other - * driver uses PA interrupt as well? - */ - *R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR); + *R_IRQ_MASK1_CLR = tmp; + gpio_pa_irq_enabled_mask &= ~tmp; + if (gpio_some_alarms) { return IRQ_RETVAL(etrax_gpio_wake_up_check()); } @@ -386,7 +402,7 @@ static int gpio_open(struct inode *inode, struct file *filp) { struct gpio_private *priv; - int p = iminor(inode); + int p = MINOR(inode->i_rdev); if (p > GPIO_MINOR_LAST) return -EINVAL; @@ -479,6 +495,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ } else if (priv->minor == GPIO_MINOR_G) { /* We must fiddle with R_GEN_CONFIG to change dir */ + save_flags(flags); cli(); if (((arg & dir_g_in_bits) != arg) && (arg & changeable_dir_g)) { arg &= changeable_dir_g; @@ -503,16 +520,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) dir_g_in_bits |= (1<<24); dir_g_out_bits &= ~(1<<24); } - printk("gpio: SETINPUT on port G set " - "genconfig to 0x%08lX " - "in_bits: 0x%08lX " - "out_bits: 0x%08lX\n", - (unsigned long)genconfig_shadow, - dir_g_in_bits, dir_g_out_bits); + D(printk(KERN_INFO "gpio: SETINPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits)); *R_GEN_CONFIG = genconfig_shadow; /* Must be a >120 ns delay before writing this again */ } + restore_flags(flags); return dir_g_in_bits; } return 0; @@ -529,6 +547,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) return *priv->dir_shadow; } else if (priv->minor == GPIO_MINOR_G) { /* We must fiddle with R_GEN_CONFIG to change dir */ + save_flags(flags); cli(); if (((arg & dir_g_out_bits) != arg) && (arg & changeable_dir_g)) { /* Set bits in genconfig to set to output */ @@ -552,15 +571,16 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) dir_g_out_bits |= (1<<24); dir_g_in_bits &= ~(1<<24); } - printk("gpio: SETOUTPUT on port G set " - "genconfig to 0x%08lX " - "in_bits: 0x%08lX " - "out_bits: 0x%08lX\n", - (unsigned long)genconfig_shadow, - dir_g_in_bits, dir_g_out_bits); + D(printk(KERN_INFO "gpio: SETOUTPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits)); *R_GEN_CONFIG = genconfig_shadow; /* Must be a >120 ns delay before writing this again */ } + restore_flags(flags); return dir_g_out_bits & 0x7FFFFFFF; } return 0; @@ -625,6 +645,20 @@ gpio_ioctl(struct inode *inode, struct file *file, // clear alarm for bits with 1 in arg priv->highalarm &= ~arg; priv->lowalarm &= ~arg; + { + /* Must update gpio_some_alarms */ + struct gpio_private *p = alarmlist; + int some_alarms; + some_alarms = 0; + while (p) { + if (p->highalarm | p->lowalarm) { + some_alarms = 1; + break; + } + p = p->next; + } + gpio_some_alarms = some_alarms; + } break; case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ /* Read direction 0=input 1=output */ @@ -844,9 +878,9 @@ static void __init gpio_init_port_g(void) dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); - printk("GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", + printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); - printk("GPIO port G: dir: %08lX changeable: %08lX\n", + printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n", dir_g_shadow, changeable_dir_g); } @@ -883,7 +917,7 @@ gpio_init(void) #endif gpio_init_port_g(); - printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); + printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); /* We call etrax_gpio_wake_up_check() from timer interrupt and * from cpu_idle() in kernel/process.c * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms @@ -891,11 +925,11 @@ gpio_init(void) */ if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) { - printk("err: timer0 irq for gpio\n"); + printk(KERN_CRIT "err: timer0 irq for gpio\n"); } if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt, SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) { - printk("err: PA irq for gpio\n"); + printk(KERN_CRIT "err: PA irq for gpio\n"); }