patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / cris / arch-v10 / drivers / gpio.c
index f3a5716..1672910 100644 (file)
@@ -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");
        }