Midified UART init, added interrupt handlers for DCD lines
[openwrt-10.03/.git] / target / linux / at91-2.6 / patches / 008-fdl-serial.patch
1 --- linux-2.6.19.2.old/drivers/serial/atmel_serial.c    2007-05-01 13:08:03.000000000 +0200
2 +++ linux-2.6.19.2/drivers/serial/atmel_serial.c        2007-05-09 17:13:34.000000000 +0200
3 @@ -173,6 +173,34 @@
4                                 at91_set_gpio_value(AT91_PIN_PA21, 0);
5                         else
6                                 at91_set_gpio_value(AT91_PIN_PA21, 1);
7 +
8 +                       /* 
9 +                        * FDL VersaLink adds GPIOS to provide full modem control on
10 +                        * USART 0 - Drive DTR and RI pins manually
11 +                        */
12 +                       if (mctrl & TIOCM_DTR)
13 +                               at91_set_gpio_value(AT91_PIN_PB6, 0);
14 +                       else
15 +                               at91_set_gpio_value(AT91_PIN_PB6, 1);
16 +                       if (mctrl & TIOCM_RI)
17 +                               at91_set_gpio_value(AT91_PIN_PB7, 0);
18 +                       else
19 +                               at91_set_gpio_value(AT91_PIN_PB7, 1);
20 +               }
21 +
22 +               /* 
23 +                * FDL VersaLink adds GPIOS to provide full modem control on
24 +                * USART 3 - Drive DTR and RI pins manually
25 +                */
26 +               if (port->mapbase == AT91RM9200_BASE_US3) {
27 +                       if (mctrl & TIOCM_DTR)
28 +                               at91_set_gpio_value(AT91_PIN_PB29, 0);
29 +                       else
30 +                               at91_set_gpio_value(AT91_PIN_PB29, 1);
31 +                       if (mctrl & TIOCM_RI)
32 +                               at91_set_gpio_value(AT91_PIN_PB2, 0);
33 +                       else
34 +                               at91_set_gpio_value(AT91_PIN_PB2, 1);
35                 }
36         }
37  #endif
38 @@ -210,8 +238,14 @@
39         /*
40          * The control signals are active low.
41          */
42 -       if (!(status & ATMEL_US_DCD))
43 -               ret |= TIOCM_CD;
44 +
45 +       /* 
46 +        * Ignore DCD reister for USARTS 0 and 3 as FDL Versalink uses
47 +        * GPIO's for these signals
48 +        */
49 +       if (!(port->mapbase == AT91RM9200_BASE_US0 || port->mapbase == AT91RM9200_BASE_US3))
50 +               if (!(status & ATMEL_US_DCD))
51 +                       ret |= TIOCM_CD;
52         if (!(status & ATMEL_US_CTS))
53                 ret |= TIOCM_CTS;
54         if (!(status & ATMEL_US_DSR))
55 @@ -219,6 +253,16 @@
56         if (!(status & ATMEL_US_RI))
57                 ret |= TIOCM_RI;
58  
59 +       /*
60 +        * Read the GPIO's for the FDL VersaLink special case
61 +        */
62 +       if (port->mapbase == AT91RM9200_BASE_US0)
63 +               if (!(at91_get_gpio_value(AT91_PIN_PA19)))
64 +                       ret |= TIOCM_CD;
65 +       if (port->mapbase == AT91RM9200_BASE_US3)
66 +               if (!(at91_get_gpio_value(AT91_PIN_PA24)))
67 +                       ret |= TIOCM_CD;
68 +
69         return ret;
70  }
71  
72 @@ -510,6 +554,34 @@
73  }
74  
75  /*
76 + * USART0 DCD Interrupt handler
77 + */
78 +
79 +static irqreturn_t atmel_u0_DCD_interrupt(int irq, void *dev_id)
80 +{
81 +       struct uart_port *port = dev_id;
82 +       int status = at91_get_gpio_value(irq);
83 +       
84 +       uart_handle_dcd_change(port, !(status));
85 +
86 +       return IRQ_HANDLED;
87 +}
88 +
89 +/*
90 + * USART3 DCD Interrupt handler
91 + */
92 +
93 +static irqreturn_t atmel_u3_DCD_interrupt(int irq, void *dev_id)
94 +{
95 +       struct uart_port *port = dev_id;
96 +       int status = at91_get_gpio_value(irq);
97 +       
98 +       uart_handle_dcd_change(port, !(status));
99 +
100 +       return IRQ_HANDLED;
101 +}
102 +
103 +/*
104   * Interrupt handler
105   */
106  static irqreturn_t atmel_interrupt(int irq, void *dev_id)
107 @@ -586,6 +658,24 @@
108                 return retval;
109         }
110  
111 +       if (port->mapbase == AT91RM9200_BASE_US0) {
112 +               retval = request_irq(AT91_PIN_PA19, atmel_u0_DCD_interrupt, 0, "atmel_serial", port);
113 +               if (retval) {
114 +                       printk("atmel_serial: atmel_startup - Can't get u0DCD irq\n");
115 +                       free_irq(port->irq, port);
116 +                       return retval;
117 +               }
118 +       }
119 +       if (port->mapbase == AT91RM9200_BASE_US3) {
120 +               retval = request_irq(AT91_PIN_PA24, atmel_u3_DCD_interrupt, 0, "atmel_serial", port);
121 +               if (retval) {
122 +                       printk("atmel_serial: atmel_startup - Can't get u3DCD irq\n");
123 +                       free_irq(port->irq, port);
124 +                       return retval;
125 +               }
126 +       }
127 +
128 +
129         /*
130          * Initialize DMA (if necessary)
131          */
132 @@ -602,6 +692,10 @@
133                                         kfree(atmel_port->pdc_rx[0].buf);
134                                 }
135                                 free_irq(port->irq, port);
136 +                               if (port->mapbase == AT91RM9200_BASE_US0)
137 +                                       free_irq(AT91_PIN_PA19, port);
138 +                               if (port->mapbase == AT91RM9200_BASE_US3)
139 +                                       free_irq(AT91_PIN_PA24, port);
140                                 return -ENOMEM;
141                         }
142                         pdc->dma_addr = dma_map_single(port->dev, pdc->buf, PDC_BUFFER_SIZE, DMA_FROM_DEVICE);
143 @@ -635,6 +729,10 @@
144                 retval = atmel_open_hook(port);
145                 if (retval) {
146                         free_irq(port->irq, port);
147 +                       if (port->mapbase == AT91RM9200_BASE_US0)
148 +                               free_irq(AT91_PIN_PA19, port);
149 +                       if (port->mapbase == AT91RM9200_BASE_US3)
150 +                               free_irq(AT91_PIN_PA24, port);
151                         return retval;
152                 }
153         }
154 @@ -694,6 +792,10 @@
155          * Free the interrupt
156          */
157         free_irq(port->irq, port);
158 +       if (port->mapbase == AT91RM9200_BASE_US0)
159 +               free_irq(AT91_PIN_PA19, port);
160 +       if (port->mapbase == AT91RM9200_BASE_US3)
161 +               free_irq(AT91_PIN_PA24, port);
162  
163         /*
164          * If there is a specific "close" function (to unregister