Prepare for 2.6.22.1 kernel
[openwrt/svn-archive/archive.git] / target / linux / at91-2.6 / patches-2.6.21 / 008-fdl-serial.patch
diff --git a/target/linux/at91-2.6/patches-2.6.21/008-fdl-serial.patch b/target/linux/at91-2.6/patches-2.6.21/008-fdl-serial.patch
new file mode 100644 (file)
index 0000000..4258919
--- /dev/null
@@ -0,0 +1,160 @@
+--- linux-2.6.21.1.orig/drivers/serial/atmel_serial.c  2007-05-28 12:22:29.000000000 +0200
++++ linux-2.6.21.1/drivers/serial/atmel_serial.c       2007-05-28 16:39:09.000000000 +0200
+@@ -174,7 +174,35 @@
+                               at91_set_gpio_value(AT91_PIN_PA21, 0);
+                       else
+                               at91_set_gpio_value(AT91_PIN_PA21, 1);
++
++      /*
++       * FDL VersaLink adds GPIOS to provide full modem control on
++       * USART 0 - Drive DTR and RI pins manually
++       */
++      if (mctrl & TIOCM_DTR)
++        at91_set_gpio_value(AT91_PIN_PB6, 0);
++      else
++        at91_set_gpio_value(AT91_PIN_PB6, 1);
++      if (mctrl & TIOCM_RI)
++        at91_set_gpio_value(AT91_PIN_PB7, 0);
++      else
++        at91_set_gpio_value(AT91_PIN_PB7, 1);
+               }
++
++    /*
++     * FDL VersaLink adds GPIOS to provide full modem control on
++     * USART 3 - Drive DTR and RI pins manually
++     */
++    if (port->mapbase == AT91RM9200_BASE_US3) {
++      if (mctrl & TIOCM_DTR)
++        at91_set_gpio_value(AT91_PIN_PB29, 0);
++      else
++        at91_set_gpio_value(AT91_PIN_PB29, 1);
++      if (mctrl & TIOCM_RI)
++        at91_set_gpio_value(AT91_PIN_PB2, 0);
++      else
++        at91_set_gpio_value(AT91_PIN_PB2, 1);
++    }
+       }
+ #endif
+@@ -211,8 +239,10 @@
+       /*
+        * The control signals are active low.
+        */
+-      if (!(status & ATMEL_US_DCD))
+-              ret |= TIOCM_CD;
++
++  if (!(port->mapbase == AT91RM9200_BASE_US0 || port->mapbase == AT91RM9200_BASE_US3))
++              if (!(status & ATMEL_US_DCD))
++                      ret |= TIOCM_CD;
+       if (!(status & ATMEL_US_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & ATMEL_US_DSR))
+@@ -220,6 +250,16 @@
+       if (!(status & ATMEL_US_RI))
+               ret |= TIOCM_RI;
++  /*
++   * Read the GPIO's for the FDL VersaLink special case
++   */
++  if (port->mapbase == AT91RM9200_BASE_US0)
++    if (!(at91_get_gpio_value(AT91_PIN_PA19)))
++      ret |= TIOCM_CD;
++  if (port->mapbase == AT91RM9200_BASE_US3)
++    if (!(at91_get_gpio_value(AT91_PIN_PA24)))
++      ret |= TIOCM_CD;
++
+       return ret;
+ }
+@@ -511,6 +551,34 @@
+ }
+ /*
++ * USART0 DCD Interrupt handler
++ */
++
++static irqreturn_t atmel_u0_DCD_interrupt(int irq, void *dev_id)
++{
++  struct uart_port *port = dev_id;
++  int status = at91_get_gpio_value(irq);
++
++  uart_handle_dcd_change(port, !(status));
++
++  return IRQ_HANDLED;
++}
++
++/*
++ * USART3 DCD Interrupt handler
++ */
++
++static irqreturn_t atmel_u3_DCD_interrupt(int irq, void *dev_id)
++{
++  struct uart_port *port = dev_id;
++  int status = at91_get_gpio_value(irq);
++
++  uart_handle_dcd_change(port, !(status));
++
++  return IRQ_HANDLED;
++}
++
++/*
+  * Interrupt handler
+  */
+ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+@@ -587,6 +655,23 @@
+               return retval;
+       }
++      if (port->mapbase == AT91RM9200_BASE_US0) {
++              retval = request_irq(AT91_PIN_PA19, atmel_u0_DCD_interrupt, 0, "atmel_serial", port);
++              if (retval) {
++                      printk("atmel_serial: atmel_startup - Can't get u0DCD irq\n");
++                      free_irq(port->irq, port);
++                      return retval;
++              }
++      }
++      if (port->mapbase == AT91RM9200_BASE_US3) {
++              retval = request_irq(AT91_PIN_PA24, atmel_u3_DCD_interrupt, 0, "atmel_serial", port);
++              if (retval) {
++                      printk("atmel_serial: atmel_startup - Can't get u3DCD irq\n");
++                      free_irq(port->irq, port);
++                      return retval;
++              }
++      }
++
+       /*
+        * Initialize DMA (if necessary)
+        */
+@@ -603,6 +688,10 @@
+                                       kfree(atmel_port->pdc_rx[0].buf);
+                               }
+                               free_irq(port->irq, port);
++        if (port->mapbase == AT91RM9200_BASE_US0)
++          free_irq(AT91_PIN_PA19, port);
++        if (port->mapbase == AT91RM9200_BASE_US3)
++          free_irq(AT91_PIN_PA24, port);
+                               return -ENOMEM;
+                       }
+                       pdc->dma_addr = dma_map_single(port->dev, pdc->buf, PDC_BUFFER_SIZE, DMA_FROM_DEVICE);
+@@ -636,6 +725,10 @@
+               retval = atmel_open_hook(port);
+               if (retval) {
+                       free_irq(port->irq, port);
++      if (port->mapbase == AT91RM9200_BASE_US0)
++        free_irq(AT91_PIN_PA19, port);
++      if (port->mapbase == AT91RM9200_BASE_US3)
++        free_irq(AT91_PIN_PA24, port);
+                       return retval;
+               }
+       }
+@@ -701,6 +794,10 @@
+        * Free the interrupt
+        */
+       free_irq(port->irq, port);
++  if (port->mapbase == AT91RM9200_BASE_US0)
++    free_irq(AT91_PIN_PA19, port);
++  if (port->mapbase == AT91RM9200_BASE_US3)
++    free_irq(AT91_PIN_PA24, port);
+       /*
+        * If there is a specific "close" function (to unregister