diff options
-rw-r--r-- | drivers/net/irda/Kconfig | 45 | ||||
-rw-r--r-- | drivers/net/irda/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/irda/bfin_sir.c | 820 | ||||
-rw-r--r-- | drivers/net/irda/bfin_sir.h | 148 |
4 files changed, 1014 insertions, 0 deletions
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index e6317557a531..f76384221422 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig | |||
@@ -17,6 +17,51 @@ config IRTTY_SIR | |||
17 | 17 | ||
18 | If unsure, say Y. | 18 | If unsure, say Y. |
19 | 19 | ||
20 | config BFIN_SIR | ||
21 | tristate "Blackfin SIR on UART" | ||
22 | depends on BLACKFIN && IRDA | ||
23 | default n | ||
24 | help | ||
25 | Say Y here if your want to enable SIR function on Blackfin UART | ||
26 | devices. | ||
27 | |||
28 | To activate this driver you can start irattach like: | ||
29 | "irattach irda0 -s" | ||
30 | |||
31 | Saying M, it will be built as a module named bfin_sir. | ||
32 | |||
33 | Note that you need to turn off one of the serial drivers for SIR | ||
34 | to use that UART. | ||
35 | |||
36 | config BFIN_SIR0 | ||
37 | bool "Blackfin SIR on UART0" | ||
38 | depends on BFIN_SIR && !SERIAL_BFIN_UART0 | ||
39 | |||
40 | config BFIN_SIR1 | ||
41 | bool "Blackfin SIR on UART1" | ||
42 | depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) | ||
43 | |||
44 | config BFIN_SIR2 | ||
45 | bool "Blackfin SIR on UART2" | ||
46 | depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) | ||
47 | |||
48 | config BFIN_SIR3 | ||
49 | bool "Blackfin SIR on UART3" | ||
50 | depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) | ||
51 | |||
52 | choice | ||
53 | prompt "SIR Mode" | ||
54 | depends on BFIN_SIR | ||
55 | default SIR_BFIN_DMA | ||
56 | |||
57 | config SIR_BFIN_DMA | ||
58 | bool "DMA mode" | ||
59 | depends on !DMA_UNCACHED_NONE | ||
60 | |||
61 | config SIR_BFIN_PIO | ||
62 | bool "PIO mode" | ||
63 | endchoice | ||
64 | |||
20 | comment "Dongle support" | 65 | comment "Dongle support" |
21 | 66 | ||
22 | config DONGLE | 67 | config DONGLE |
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 5d20fde32a24..d82e1e3bd8c8 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_MCS_FIR) += mcs7780.o | |||
21 | obj-$(CONFIG_AU1000_FIR) += au1k_ir.o | 21 | obj-$(CONFIG_AU1000_FIR) += au1k_ir.o |
22 | # SIR drivers | 22 | # SIR drivers |
23 | obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o | 23 | obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o |
24 | obj-$(CONFIG_BFIN_SIR) += bfin_sir.o | ||
24 | # dongle drivers for SIR drivers | 25 | # dongle drivers for SIR drivers |
25 | obj-$(CONFIG_ESI_DONGLE) += esi-sir.o | 26 | obj-$(CONFIG_ESI_DONGLE) += esi-sir.o |
26 | obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o | 27 | obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o |
diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c new file mode 100644 index 000000000000..f3eed6a8fba5 --- /dev/null +++ b/drivers/net/irda/bfin_sir.c | |||
@@ -0,0 +1,820 @@ | |||
1 | /* | ||
2 | * Blackfin Infra-red Driver | ||
3 | * | ||
4 | * Copyright 2006-2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Enter bugs at http://blackfin.uclinux.org/ | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | * | ||
10 | */ | ||
11 | #include "bfin_sir.h" | ||
12 | |||
13 | #ifdef CONFIG_SIR_BFIN_DMA | ||
14 | #define DMA_SIR_RX_XCNT 10 | ||
15 | #define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) | ||
16 | #define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) | ||
17 | #endif | ||
18 | |||
19 | #if ANOMALY_05000447 | ||
20 | static int max_rate = 57600; | ||
21 | #else | ||
22 | static int max_rate = 115200; | ||
23 | #endif | ||
24 | |||
25 | static void turnaround_delay(unsigned long last_jif, int mtt) | ||
26 | { | ||
27 | long ticks; | ||
28 | |||
29 | mtt = mtt < 10000 ? 10000 : mtt; | ||
30 | ticks = 1 + mtt / (USEC_PER_SEC / HZ); | ||
31 | schedule_timeout_uninterruptible(ticks); | ||
32 | } | ||
33 | |||
34 | static void __devinit bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) | ||
35 | { | ||
36 | int i; | ||
37 | struct resource *res; | ||
38 | |||
39 | for (i = 0; i < pdev->num_resources; i++) { | ||
40 | res = &pdev->resource[i]; | ||
41 | switch (res->flags) { | ||
42 | case IORESOURCE_MEM: | ||
43 | sp->membase = (void __iomem *)res->start; | ||
44 | break; | ||
45 | case IORESOURCE_IRQ: | ||
46 | sp->irq = res->start; | ||
47 | break; | ||
48 | case IORESOURCE_DMA: | ||
49 | sp->rx_dma_channel = res->start; | ||
50 | sp->tx_dma_channel = res->end; | ||
51 | break; | ||
52 | default: | ||
53 | break; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | sp->clk = get_sclk(); | ||
58 | #ifdef CONFIG_SIR_BFIN_DMA | ||
59 | sp->tx_done = 1; | ||
60 | init_timer(&(sp->rx_dma_timer)); | ||
61 | #endif | ||
62 | } | ||
63 | |||
64 | static void bfin_sir_stop_tx(struct bfin_sir_port *port) | ||
65 | { | ||
66 | #ifdef CONFIG_SIR_BFIN_DMA | ||
67 | disable_dma(port->tx_dma_channel); | ||
68 | #endif | ||
69 | |||
70 | while (!(SIR_UART_GET_LSR(port) & THRE)) { | ||
71 | cpu_relax(); | ||
72 | continue; | ||
73 | } | ||
74 | |||
75 | SIR_UART_STOP_TX(port); | ||
76 | } | ||
77 | |||
78 | static void bfin_sir_enable_tx(struct bfin_sir_port *port) | ||
79 | { | ||
80 | SIR_UART_ENABLE_TX(port); | ||
81 | } | ||
82 | |||
83 | static void bfin_sir_stop_rx(struct bfin_sir_port *port) | ||
84 | { | ||
85 | SIR_UART_STOP_RX(port); | ||
86 | } | ||
87 | |||
88 | static void bfin_sir_enable_rx(struct bfin_sir_port *port) | ||
89 | { | ||
90 | SIR_UART_ENABLE_RX(port); | ||
91 | } | ||
92 | |||
93 | static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) | ||
94 | { | ||
95 | int ret = -EINVAL; | ||
96 | unsigned int quot; | ||
97 | unsigned short val, lsr, lcr; | ||
98 | static int utime; | ||
99 | int count = 10; | ||
100 | |||
101 | lcr = WLS(8); | ||
102 | |||
103 | switch (speed) { | ||
104 | case 9600: | ||
105 | case 19200: | ||
106 | case 38400: | ||
107 | case 57600: | ||
108 | case 115200: | ||
109 | |||
110 | quot = (port->clk + (8 * speed)) / (16 * speed)\ | ||
111 | - ANOMALY_05000230; | ||
112 | |||
113 | do { | ||
114 | udelay(utime); | ||
115 | lsr = SIR_UART_GET_LSR(port); | ||
116 | } while (!(lsr & TEMT) && count--); | ||
117 | |||
118 | /* The useconds for 1 bits to transmit */ | ||
119 | utime = 1000000 / speed + 1; | ||
120 | |||
121 | /* Clear UCEN bit to reset the UART state machine | ||
122 | * and control registers | ||
123 | */ | ||
124 | val = SIR_UART_GET_GCTL(port); | ||
125 | val &= ~UCEN; | ||
126 | SIR_UART_PUT_GCTL(port, val); | ||
127 | |||
128 | /* Set DLAB in LCR to Access THR RBR IER */ | ||
129 | SIR_UART_SET_DLAB(port); | ||
130 | SSYNC(); | ||
131 | |||
132 | SIR_UART_PUT_DLL(port, quot & 0xFF); | ||
133 | SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF); | ||
134 | SSYNC(); | ||
135 | |||
136 | /* Clear DLAB in LCR */ | ||
137 | SIR_UART_CLEAR_DLAB(port); | ||
138 | SSYNC(); | ||
139 | |||
140 | SIR_UART_PUT_LCR(port, lcr); | ||
141 | |||
142 | val = SIR_UART_GET_GCTL(port); | ||
143 | val |= UCEN; | ||
144 | SIR_UART_PUT_GCTL(port, val); | ||
145 | |||
146 | ret = 0; | ||
147 | break; | ||
148 | default: | ||
149 | printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | val = SIR_UART_GET_GCTL(port); | ||
154 | /* If not add the 'RPOLC', we can't catch the receive interrupt. | ||
155 | * It's related with the HW layout and the IR transiver. | ||
156 | */ | ||
157 | val |= IREN | RPOLC; | ||
158 | SIR_UART_PUT_GCTL(port, val); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | static int bfin_sir_is_receiving(struct net_device *dev) | ||
163 | { | ||
164 | struct bfin_sir_self *self = netdev_priv(dev); | ||
165 | struct bfin_sir_port *port = self->sir_port; | ||
166 | |||
167 | if (!(SIR_UART_GET_IER(port) & ERBFI)) | ||
168 | return 0; | ||
169 | return self->rx_buff.state != OUTSIDE_FRAME; | ||
170 | } | ||
171 | |||
172 | #ifdef CONFIG_SIR_BFIN_PIO | ||
173 | static void bfin_sir_tx_chars(struct net_device *dev) | ||
174 | { | ||
175 | unsigned int chr; | ||
176 | struct bfin_sir_self *self = netdev_priv(dev); | ||
177 | struct bfin_sir_port *port = self->sir_port; | ||
178 | |||
179 | if (self->tx_buff.len != 0) { | ||
180 | chr = *(self->tx_buff.data); | ||
181 | SIR_UART_PUT_CHAR(port, chr); | ||
182 | self->tx_buff.data++; | ||
183 | self->tx_buff.len--; | ||
184 | } else { | ||
185 | self->stats.tx_packets++; | ||
186 | self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; | ||
187 | if (self->newspeed) { | ||
188 | bfin_sir_set_speed(port, self->newspeed); | ||
189 | self->speed = self->newspeed; | ||
190 | self->newspeed = 0; | ||
191 | } | ||
192 | bfin_sir_stop_tx(port); | ||
193 | bfin_sir_enable_rx(port); | ||
194 | /* I'm hungry! */ | ||
195 | netif_wake_queue(dev); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static void bfin_sir_rx_chars(struct net_device *dev) | ||
200 | { | ||
201 | struct bfin_sir_self *self = netdev_priv(dev); | ||
202 | struct bfin_sir_port *port = self->sir_port; | ||
203 | unsigned char ch; | ||
204 | |||
205 | SIR_UART_CLEAR_LSR(port); | ||
206 | ch = SIR_UART_GET_CHAR(port); | ||
207 | async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); | ||
208 | dev->last_rx = jiffies; | ||
209 | } | ||
210 | |||
211 | static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) | ||
212 | { | ||
213 | struct net_device *dev = dev_id; | ||
214 | struct bfin_sir_self *self = netdev_priv(dev); | ||
215 | struct bfin_sir_port *port = self->sir_port; | ||
216 | |||
217 | spin_lock(&self->lock); | ||
218 | while ((SIR_UART_GET_LSR(port) & DR)) | ||
219 | bfin_sir_rx_chars(dev); | ||
220 | spin_unlock(&self->lock); | ||
221 | |||
222 | return IRQ_HANDLED; | ||
223 | } | ||
224 | |||
225 | static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) | ||
226 | { | ||
227 | struct net_device *dev = dev_id; | ||
228 | struct bfin_sir_self *self = netdev_priv(dev); | ||
229 | struct bfin_sir_port *port = self->sir_port; | ||
230 | |||
231 | spin_lock(&self->lock); | ||
232 | if (SIR_UART_GET_LSR(port) & THRE) | ||
233 | bfin_sir_tx_chars(dev); | ||
234 | spin_unlock(&self->lock); | ||
235 | |||
236 | return IRQ_HANDLED; | ||
237 | } | ||
238 | #endif /* CONFIG_SIR_BFIN_PIO */ | ||
239 | |||
240 | #ifdef CONFIG_SIR_BFIN_DMA | ||
241 | static void bfin_sir_dma_tx_chars(struct net_device *dev) | ||
242 | { | ||
243 | struct bfin_sir_self *self = netdev_priv(dev); | ||
244 | struct bfin_sir_port *port = self->sir_port; | ||
245 | |||
246 | if (!port->tx_done) | ||
247 | return; | ||
248 | port->tx_done = 0; | ||
249 | |||
250 | if (self->tx_buff.len == 0) { | ||
251 | self->stats.tx_packets++; | ||
252 | if (self->newspeed) { | ||
253 | bfin_sir_set_speed(port, self->newspeed); | ||
254 | self->speed = self->newspeed; | ||
255 | self->newspeed = 0; | ||
256 | } | ||
257 | bfin_sir_enable_rx(port); | ||
258 | port->tx_done = 1; | ||
259 | netif_wake_queue(dev); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), | ||
264 | (unsigned long)(self->tx_buff.data+self->tx_buff.len)); | ||
265 | set_dma_config(port->tx_dma_channel, | ||
266 | set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, | ||
267 | INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, | ||
268 | DMA_SYNC_RESTART)); | ||
269 | set_dma_start_addr(port->tx_dma_channel, | ||
270 | (unsigned long)(self->tx_buff.data)); | ||
271 | set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); | ||
272 | set_dma_x_modify(port->tx_dma_channel, 1); | ||
273 | enable_dma(port->tx_dma_channel); | ||
274 | } | ||
275 | |||
276 | static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) | ||
277 | { | ||
278 | struct net_device *dev = dev_id; | ||
279 | struct bfin_sir_self *self = netdev_priv(dev); | ||
280 | struct bfin_sir_port *port = self->sir_port; | ||
281 | |||
282 | spin_lock(&self->lock); | ||
283 | if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { | ||
284 | clear_dma_irqstat(port->tx_dma_channel); | ||
285 | bfin_sir_stop_tx(port); | ||
286 | |||
287 | self->stats.tx_packets++; | ||
288 | self->stats.tx_bytes += self->tx_buff.len; | ||
289 | self->tx_buff.len = 0; | ||
290 | if (self->newspeed) { | ||
291 | bfin_sir_set_speed(port, self->newspeed); | ||
292 | self->speed = self->newspeed; | ||
293 | self->newspeed = 0; | ||
294 | } | ||
295 | bfin_sir_enable_rx(port); | ||
296 | /* I'm hungry! */ | ||
297 | netif_wake_queue(dev); | ||
298 | port->tx_done = 1; | ||
299 | } | ||
300 | spin_unlock(&self->lock); | ||
301 | |||
302 | return IRQ_HANDLED; | ||
303 | } | ||
304 | |||
305 | static void bfin_sir_dma_rx_chars(struct net_device *dev) | ||
306 | { | ||
307 | struct bfin_sir_self *self = netdev_priv(dev); | ||
308 | struct bfin_sir_port *port = self->sir_port; | ||
309 | int i; | ||
310 | |||
311 | SIR_UART_CLEAR_LSR(port); | ||
312 | |||
313 | for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) | ||
314 | async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); | ||
315 | } | ||
316 | |||
317 | void bfin_sir_rx_dma_timeout(struct net_device *dev) | ||
318 | { | ||
319 | struct bfin_sir_self *self = netdev_priv(dev); | ||
320 | struct bfin_sir_port *port = self->sir_port; | ||
321 | int x_pos, pos; | ||
322 | unsigned long flags; | ||
323 | |||
324 | spin_lock_irqsave(&self->lock, flags); | ||
325 | x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); | ||
326 | if (x_pos == DMA_SIR_RX_XCNT) | ||
327 | x_pos = 0; | ||
328 | |||
329 | pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; | ||
330 | |||
331 | if (pos > port->rx_dma_buf.tail) { | ||
332 | port->rx_dma_buf.tail = pos; | ||
333 | bfin_sir_dma_rx_chars(dev); | ||
334 | port->rx_dma_buf.head = port->rx_dma_buf.tail; | ||
335 | } | ||
336 | spin_unlock_irqrestore(&self->lock, flags); | ||
337 | } | ||
338 | |||
339 | static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) | ||
340 | { | ||
341 | struct net_device *dev = dev_id; | ||
342 | struct bfin_sir_self *self = netdev_priv(dev); | ||
343 | struct bfin_sir_port *port = self->sir_port; | ||
344 | unsigned short irqstat; | ||
345 | |||
346 | spin_lock(&self->lock); | ||
347 | |||
348 | port->rx_dma_nrows++; | ||
349 | port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; | ||
350 | bfin_sir_dma_rx_chars(dev); | ||
351 | if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { | ||
352 | port->rx_dma_nrows = 0; | ||
353 | port->rx_dma_buf.tail = 0; | ||
354 | } | ||
355 | port->rx_dma_buf.head = port->rx_dma_buf.tail; | ||
356 | |||
357 | irqstat = get_dma_curr_irqstat(port->rx_dma_channel); | ||
358 | clear_dma_irqstat(port->rx_dma_channel); | ||
359 | spin_unlock(&self->lock); | ||
360 | |||
361 | mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); | ||
362 | return IRQ_HANDLED; | ||
363 | } | ||
364 | #endif /* CONFIG_SIR_BFIN_DMA */ | ||
365 | |||
366 | static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) | ||
367 | { | ||
368 | #ifdef CONFIG_SIR_BFIN_DMA | ||
369 | dma_addr_t dma_handle; | ||
370 | #endif /* CONFIG_SIR_BFIN_DMA */ | ||
371 | |||
372 | if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { | ||
373 | dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); | ||
374 | return -EBUSY; | ||
375 | } | ||
376 | |||
377 | if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { | ||
378 | dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); | ||
379 | free_dma(port->rx_dma_channel); | ||
380 | return -EBUSY; | ||
381 | } | ||
382 | |||
383 | #ifdef CONFIG_SIR_BFIN_DMA | ||
384 | |||
385 | set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); | ||
386 | set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); | ||
387 | |||
388 | port->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); | ||
389 | port->rx_dma_buf.head = 0; | ||
390 | port->rx_dma_buf.tail = 0; | ||
391 | port->rx_dma_nrows = 0; | ||
392 | |||
393 | set_dma_config(port->rx_dma_channel, | ||
394 | set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, | ||
395 | INTR_ON_ROW, DIMENSION_2D, | ||
396 | DATA_SIZE_8, DMA_SYNC_RESTART)); | ||
397 | set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); | ||
398 | set_dma_x_modify(port->rx_dma_channel, 1); | ||
399 | set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); | ||
400 | set_dma_y_modify(port->rx_dma_channel, 1); | ||
401 | set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); | ||
402 | enable_dma(port->rx_dma_channel); | ||
403 | |||
404 | port->rx_dma_timer.data = (unsigned long)(dev); | ||
405 | port->rx_dma_timer.function = (void *)bfin_sir_rx_dma_timeout; | ||
406 | |||
407 | #else | ||
408 | |||
409 | if (request_irq(port->irq, bfin_sir_rx_int, IRQF_DISABLED, "BFIN_SIR_RX", dev)) { | ||
410 | dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); | ||
411 | return -EBUSY; | ||
412 | } | ||
413 | |||
414 | if (request_irq(port->irq+1, bfin_sir_tx_int, IRQF_DISABLED, "BFIN_SIR_TX", dev)) { | ||
415 | dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); | ||
416 | free_irq(port->irq, dev); | ||
417 | return -EBUSY; | ||
418 | } | ||
419 | #endif | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) | ||
425 | { | ||
426 | unsigned short val; | ||
427 | |||
428 | bfin_sir_stop_rx(port); | ||
429 | SIR_UART_DISABLE_INTS(port); | ||
430 | |||
431 | val = SIR_UART_GET_GCTL(port); | ||
432 | val &= ~(UCEN | IREN | RPOLC); | ||
433 | SIR_UART_PUT_GCTL(port, val); | ||
434 | |||
435 | #ifdef CONFIG_SIR_BFIN_DMA | ||
436 | disable_dma(port->tx_dma_channel); | ||
437 | disable_dma(port->rx_dma_channel); | ||
438 | del_timer(&(port->rx_dma_timer)); | ||
439 | dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); | ||
440 | #else | ||
441 | free_irq(port->irq+1, dev); | ||
442 | free_irq(port->irq, dev); | ||
443 | #endif | ||
444 | free_dma(port->tx_dma_channel); | ||
445 | free_dma(port->rx_dma_channel); | ||
446 | } | ||
447 | |||
448 | #ifdef CONFIG_PM | ||
449 | static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) | ||
450 | { | ||
451 | struct bfin_sir_port *sir_port; | ||
452 | struct net_device *dev; | ||
453 | struct bfin_sir_self *self; | ||
454 | |||
455 | sir_port = platform_get_drvdata(pdev); | ||
456 | if (!sir_port) | ||
457 | return 0; | ||
458 | |||
459 | dev = sir_port->dev; | ||
460 | self = netdev_priv(dev); | ||
461 | if (self->open) { | ||
462 | flush_work(&self->work); | ||
463 | bfin_sir_shutdown(self->sir_port, dev); | ||
464 | netif_device_detach(dev); | ||
465 | } | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | static int bfin_sir_resume(struct platform_device *pdev) | ||
470 | { | ||
471 | struct bfin_sir_port *sir_port; | ||
472 | struct net_device *dev; | ||
473 | struct bfin_sir_self *self; | ||
474 | struct bfin_sir_port *port; | ||
475 | |||
476 | sir_port = platform_get_drvdata(pdev); | ||
477 | if (!sir_port) | ||
478 | return 0; | ||
479 | |||
480 | dev = sir_port->dev; | ||
481 | self = netdev_priv(dev); | ||
482 | port = self->sir_port; | ||
483 | if (self->open) { | ||
484 | if (self->newspeed) { | ||
485 | self->speed = self->newspeed; | ||
486 | self->newspeed = 0; | ||
487 | } | ||
488 | bfin_sir_startup(port, dev); | ||
489 | bfin_sir_set_speed(port, 9600); | ||
490 | bfin_sir_enable_rx(port); | ||
491 | netif_device_attach(dev); | ||
492 | } | ||
493 | return 0; | ||
494 | } | ||
495 | #else | ||
496 | #define bfin_sir_suspend NULL | ||
497 | #define bfin_sir_resume NULL | ||
498 | #endif | ||
499 | |||
500 | static void bfin_sir_send_work(struct work_struct *work) | ||
501 | { | ||
502 | struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); | ||
503 | struct net_device *dev = self->sir_port->dev; | ||
504 | struct bfin_sir_port *port = self->sir_port; | ||
505 | unsigned short val; | ||
506 | int tx_cnt = 10; | ||
507 | |||
508 | while (bfin_sir_is_receiving(dev) && --tx_cnt) | ||
509 | turnaround_delay(dev->last_rx, self->mtt); | ||
510 | |||
511 | bfin_sir_stop_rx(port); | ||
512 | |||
513 | /* To avoid losting RX interrupt, we reset IR function before | ||
514 | * sending data. We also can set the speed, which will | ||
515 | * reset all the UART. | ||
516 | */ | ||
517 | val = SIR_UART_GET_GCTL(port); | ||
518 | val &= ~(IREN | RPOLC); | ||
519 | SIR_UART_PUT_GCTL(port, val); | ||
520 | SSYNC(); | ||
521 | val |= IREN | RPOLC; | ||
522 | SIR_UART_PUT_GCTL(port, val); | ||
523 | SSYNC(); | ||
524 | /* bfin_sir_set_speed(port, self->speed); */ | ||
525 | |||
526 | #ifdef CONFIG_SIR_BFIN_DMA | ||
527 | bfin_sir_dma_tx_chars(dev); | ||
528 | #endif | ||
529 | bfin_sir_enable_tx(port); | ||
530 | dev->trans_start = jiffies; | ||
531 | } | ||
532 | |||
533 | static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) | ||
534 | { | ||
535 | struct bfin_sir_self *self = netdev_priv(dev); | ||
536 | int speed = irda_get_next_speed(skb); | ||
537 | |||
538 | netif_stop_queue(dev); | ||
539 | |||
540 | self->mtt = irda_get_mtt(skb); | ||
541 | |||
542 | if (speed != self->speed && speed != -1) | ||
543 | self->newspeed = speed; | ||
544 | |||
545 | self->tx_buff.data = self->tx_buff.head; | ||
546 | if (skb->len == 0) | ||
547 | self->tx_buff.len = 0; | ||
548 | else | ||
549 | self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); | ||
550 | |||
551 | schedule_work(&self->work); | ||
552 | dev_kfree_skb(skb); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) | ||
558 | { | ||
559 | struct if_irda_req *rq = (struct if_irda_req *)ifreq; | ||
560 | struct bfin_sir_self *self = netdev_priv(dev); | ||
561 | struct bfin_sir_port *port = self->sir_port; | ||
562 | int ret = 0; | ||
563 | |||
564 | switch (cmd) { | ||
565 | case SIOCSBANDWIDTH: | ||
566 | if (capable(CAP_NET_ADMIN)) { | ||
567 | if (self->open) { | ||
568 | ret = bfin_sir_set_speed(port, rq->ifr_baudrate); | ||
569 | bfin_sir_enable_rx(port); | ||
570 | } else { | ||
571 | dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); | ||
572 | ret = 0; | ||
573 | } | ||
574 | } | ||
575 | break; | ||
576 | |||
577 | case SIOCSMEDIABUSY: | ||
578 | ret = -EPERM; | ||
579 | if (capable(CAP_NET_ADMIN)) { | ||
580 | irda_device_set_media_busy(dev, TRUE); | ||
581 | ret = 0; | ||
582 | } | ||
583 | break; | ||
584 | |||
585 | case SIOCGRECEIVING: | ||
586 | rq->ifr_receiving = bfin_sir_is_receiving(dev); | ||
587 | break; | ||
588 | |||
589 | default: | ||
590 | ret = -EOPNOTSUPP; | ||
591 | break; | ||
592 | } | ||
593 | |||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | static struct net_device_stats *bfin_sir_stats(struct net_device *dev) | ||
598 | { | ||
599 | struct bfin_sir_self *self = netdev_priv(dev); | ||
600 | |||
601 | return &self->stats; | ||
602 | } | ||
603 | |||
604 | static int bfin_sir_open(struct net_device *dev) | ||
605 | { | ||
606 | struct bfin_sir_self *self = netdev_priv(dev); | ||
607 | struct bfin_sir_port *port = self->sir_port; | ||
608 | int err = -ENOMEM; | ||
609 | |||
610 | self->newspeed = 0; | ||
611 | self->speed = 9600; | ||
612 | |||
613 | spin_lock_init(&self->lock); | ||
614 | |||
615 | err = bfin_sir_startup(port, dev); | ||
616 | if (err) | ||
617 | goto err_startup; | ||
618 | |||
619 | bfin_sir_set_speed(port, 9600); | ||
620 | |||
621 | self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); | ||
622 | if (!self->irlap) | ||
623 | goto err_irlap; | ||
624 | |||
625 | INIT_WORK(&self->work, bfin_sir_send_work); | ||
626 | |||
627 | /* | ||
628 | * Now enable the interrupt then start the queue | ||
629 | */ | ||
630 | self->open = 1; | ||
631 | bfin_sir_enable_rx(port); | ||
632 | |||
633 | netif_start_queue(dev); | ||
634 | |||
635 | return 0; | ||
636 | |||
637 | err_irlap: | ||
638 | self->open = 0; | ||
639 | bfin_sir_shutdown(port, dev); | ||
640 | err_startup: | ||
641 | return err; | ||
642 | } | ||
643 | |||
644 | static int bfin_sir_stop(struct net_device *dev) | ||
645 | { | ||
646 | struct bfin_sir_self *self = netdev_priv(dev); | ||
647 | |||
648 | flush_work(&self->work); | ||
649 | bfin_sir_shutdown(self->sir_port, dev); | ||
650 | |||
651 | if (self->rxskb) { | ||
652 | dev_kfree_skb(self->rxskb); | ||
653 | self->rxskb = NULL; | ||
654 | } | ||
655 | |||
656 | /* Stop IrLAP */ | ||
657 | if (self->irlap) { | ||
658 | irlap_close(self->irlap); | ||
659 | self->irlap = NULL; | ||
660 | } | ||
661 | |||
662 | netif_stop_queue(dev); | ||
663 | self->open = 0; | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int bfin_sir_init_iobuf(iobuff_t *io, int size) | ||
669 | { | ||
670 | io->head = kmalloc(size, GFP_KERNEL); | ||
671 | if (!io->head) | ||
672 | return -ENOMEM; | ||
673 | io->truesize = size; | ||
674 | io->in_frame = FALSE; | ||
675 | io->state = OUTSIDE_FRAME; | ||
676 | io->data = io->head; | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int __devinit bfin_sir_probe(struct platform_device *pdev) | ||
681 | { | ||
682 | struct net_device *dev; | ||
683 | struct bfin_sir_self *self; | ||
684 | unsigned int baudrate_mask; | ||
685 | struct bfin_sir_port *sir_port; | ||
686 | int err; | ||
687 | |||
688 | if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ | ||
689 | per[pdev->id][3] == pdev->id) { | ||
690 | err = peripheral_request_list(per[pdev->id], DRIVER_NAME); | ||
691 | if (err) | ||
692 | return err; | ||
693 | } else { | ||
694 | dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); | ||
695 | return -ENODEV; | ||
696 | } | ||
697 | |||
698 | err = -ENOMEM; | ||
699 | sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); | ||
700 | if (!sir_port) | ||
701 | goto err_mem_0; | ||
702 | |||
703 | bfin_sir_init_ports(sir_port, pdev); | ||
704 | |||
705 | dev = alloc_irdadev(sizeof(*self)); | ||
706 | if (!dev) | ||
707 | goto err_mem_1; | ||
708 | |||
709 | self = netdev_priv(dev); | ||
710 | self->dev = &pdev->dev; | ||
711 | self->sir_port = sir_port; | ||
712 | sir_port->dev = dev; | ||
713 | |||
714 | err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); | ||
715 | if (err) | ||
716 | goto err_mem_2; | ||
717 | err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); | ||
718 | if (err) | ||
719 | goto err_mem_3; | ||
720 | |||
721 | dev->hard_start_xmit = bfin_sir_hard_xmit; | ||
722 | dev->open = bfin_sir_open; | ||
723 | dev->stop = bfin_sir_stop; | ||
724 | dev->do_ioctl = bfin_sir_ioctl; | ||
725 | dev->get_stats = bfin_sir_stats; | ||
726 | dev->irq = sir_port->irq; | ||
727 | |||
728 | irda_init_max_qos_capabilies(&self->qos); | ||
729 | |||
730 | baudrate_mask = IR_9600; | ||
731 | |||
732 | switch (max_rate) { | ||
733 | case 115200: | ||
734 | baudrate_mask |= IR_115200; | ||
735 | case 57600: | ||
736 | baudrate_mask |= IR_57600; | ||
737 | case 38400: | ||
738 | baudrate_mask |= IR_38400; | ||
739 | case 19200: | ||
740 | baudrate_mask |= IR_19200; | ||
741 | case 9600: | ||
742 | break; | ||
743 | default: | ||
744 | dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); | ||
745 | } | ||
746 | |||
747 | self->qos.baud_rate.bits &= baudrate_mask; | ||
748 | |||
749 | self->qos.min_turn_time.bits = 1; /* 10 ms or more */ | ||
750 | |||
751 | irda_qos_bits_to_value(&self->qos); | ||
752 | |||
753 | err = register_netdev(dev); | ||
754 | |||
755 | if (err) { | ||
756 | kfree(self->tx_buff.head); | ||
757 | err_mem_3: | ||
758 | kfree(self->rx_buff.head); | ||
759 | err_mem_2: | ||
760 | free_netdev(dev); | ||
761 | err_mem_1: | ||
762 | kfree(sir_port); | ||
763 | err_mem_0: | ||
764 | peripheral_free_list(per[pdev->id]); | ||
765 | } else | ||
766 | platform_set_drvdata(pdev, sir_port); | ||
767 | |||
768 | return err; | ||
769 | } | ||
770 | |||
771 | static int __devexit bfin_sir_remove(struct platform_device *pdev) | ||
772 | { | ||
773 | struct bfin_sir_port *sir_port; | ||
774 | struct net_device *dev = NULL; | ||
775 | struct bfin_sir_self *self; | ||
776 | |||
777 | sir_port = platform_get_drvdata(pdev); | ||
778 | if (!sir_port) | ||
779 | return 0; | ||
780 | dev = sir_port->dev; | ||
781 | self = netdev_priv(dev); | ||
782 | unregister_netdev(dev); | ||
783 | kfree(self->tx_buff.head); | ||
784 | kfree(self->rx_buff.head); | ||
785 | free_netdev(dev); | ||
786 | kfree(sir_port); | ||
787 | platform_set_drvdata(pdev, NULL); | ||
788 | |||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static struct platform_driver bfin_ir_driver = { | ||
793 | .probe = bfin_sir_probe, | ||
794 | .remove = __devexit_p(bfin_sir_remove), | ||
795 | .suspend = bfin_sir_suspend, | ||
796 | .resume = bfin_sir_resume, | ||
797 | .driver = { | ||
798 | .name = DRIVER_NAME, | ||
799 | }, | ||
800 | }; | ||
801 | |||
802 | static int __init bfin_sir_init(void) | ||
803 | { | ||
804 | return platform_driver_register(&bfin_ir_driver); | ||
805 | } | ||
806 | |||
807 | static void __exit bfin_sir_exit(void) | ||
808 | { | ||
809 | platform_driver_unregister(&bfin_ir_driver); | ||
810 | } | ||
811 | |||
812 | module_init(bfin_sir_init); | ||
813 | module_exit(bfin_sir_exit); | ||
814 | |||
815 | module_param(max_rate, int, 0); | ||
816 | MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); | ||
817 | |||
818 | MODULE_AUTHOR("Graf Yang <graf.yang@analog.com>"); | ||
819 | MODULE_DESCRIPTION("Blackfin IrDA driver"); | ||
820 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h new file mode 100644 index 000000000000..dac71b1f4f9b --- /dev/null +++ b/drivers/net/irda/bfin_sir.h | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * Blackfin Infra-red Driver | ||
3 | * | ||
4 | * Copyright 2006-2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Enter bugs at http://blackfin.uclinux.org/ | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/serial.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/netdevice.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | |||
20 | #include <net/irda/irda.h> | ||
21 | #include <net/irda/wrapper.h> | ||
22 | #include <net/irda/irda_device.h> | ||
23 | |||
24 | #include <asm/irq.h> | ||
25 | #include <asm/cacheflush.h> | ||
26 | #include <asm/dma.h> | ||
27 | #include <asm/portmux.h> | ||
28 | |||
29 | #ifdef CONFIG_SIR_BFIN_DMA | ||
30 | struct dma_rx_buf { | ||
31 | char *buf; | ||
32 | int head; | ||
33 | int tail; | ||
34 | }; | ||
35 | #endif | ||
36 | |||
37 | struct bfin_sir_port { | ||
38 | unsigned char __iomem *membase; | ||
39 | unsigned int irq; | ||
40 | unsigned int lsr; | ||
41 | unsigned long clk; | ||
42 | struct net_device *dev; | ||
43 | #ifdef CONFIG_SIR_BFIN_DMA | ||
44 | int tx_done; | ||
45 | struct dma_rx_buf rx_dma_buf; | ||
46 | struct timer_list rx_dma_timer; | ||
47 | int rx_dma_nrows; | ||
48 | #endif | ||
49 | unsigned int tx_dma_channel; | ||
50 | unsigned int rx_dma_channel; | ||
51 | }; | ||
52 | |||
53 | struct bfin_sir_port_res { | ||
54 | unsigned long base_addr; | ||
55 | int irq; | ||
56 | unsigned int rx_dma_channel; | ||
57 | unsigned int tx_dma_channel; | ||
58 | }; | ||
59 | |||
60 | struct bfin_sir_self { | ||
61 | struct bfin_sir_port *sir_port; | ||
62 | spinlock_t lock; | ||
63 | unsigned int open; | ||
64 | int speed; | ||
65 | int newspeed; | ||
66 | |||
67 | struct sk_buff *txskb; | ||
68 | struct sk_buff *rxskb; | ||
69 | struct net_device_stats stats; | ||
70 | struct device *dev; | ||
71 | struct irlap_cb *irlap; | ||
72 | struct qos_info qos; | ||
73 | |||
74 | iobuff_t tx_buff; | ||
75 | iobuff_t rx_buff; | ||
76 | |||
77 | struct work_struct work; | ||
78 | int mtt; | ||
79 | }; | ||
80 | |||
81 | #define DRIVER_NAME "bfin_sir" | ||
82 | |||
83 | #define SIR_UART_GET_CHAR(port) bfin_read16((port)->membase + OFFSET_RBR) | ||
84 | #define SIR_UART_GET_DLL(port) bfin_read16((port)->membase + OFFSET_DLL) | ||
85 | #define SIR_UART_GET_DLH(port) bfin_read16((port)->membase + OFFSET_DLH) | ||
86 | #define SIR_UART_GET_LCR(port) bfin_read16((port)->membase + OFFSET_LCR) | ||
87 | #define SIR_UART_GET_GCTL(port) bfin_read16((port)->membase + OFFSET_GCTL) | ||
88 | |||
89 | #define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v) | ||
90 | #define SIR_UART_PUT_DLL(port, v) bfin_write16(((port)->membase + OFFSET_DLL), v) | ||
91 | #define SIR_UART_PUT_DLH(port, v) bfin_write16(((port)->membase + OFFSET_DLH), v) | ||
92 | #define SIR_UART_PUT_LCR(port, v) bfin_write16(((port)->membase + OFFSET_LCR), v) | ||
93 | #define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v) | ||
94 | |||
95 | #ifdef CONFIG_BF54x | ||
96 | #define SIR_UART_GET_LSR(port) bfin_read16((port)->membase + OFFSET_LSR) | ||
97 | #define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER_SET) | ||
98 | #define SIR_UART_SET_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_SET), v) | ||
99 | #define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v) | ||
100 | #define SIR_UART_PUT_LSR(port, v) bfin_write16(((port)->membase + OFFSET_LSR), v) | ||
101 | #define SIR_UART_CLEAR_LSR(port) bfin_write16(((port)->membase + OFFSET_LSR), -1) | ||
102 | |||
103 | #define SIR_UART_SET_DLAB(port) | ||
104 | #define SIR_UART_CLEAR_DLAB(port) | ||
105 | |||
106 | #define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v) | ||
107 | #define SIR_UART_DISABLE_INTS(port) SIR_UART_CLEAR_IER(port, 0xF) | ||
108 | #define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0) | ||
109 | #define SIR_UART_ENABLE_TX(port) do { SIR_UART_SET_IER(port, ETBEI); } while (0) | ||
110 | #define SIR_UART_STOP_RX(port) do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0) | ||
111 | #define SIR_UART_ENABLE_RX(port) do { SIR_UART_SET_IER(port, ERBFI); } while (0) | ||
112 | #else | ||
113 | |||
114 | #define SIR_UART_GET_IIR(port) bfin_read16((port)->membase + OFFSET_IIR) | ||
115 | #define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER) | ||
116 | #define SIR_UART_PUT_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER), v) | ||
117 | |||
118 | #define SIR_UART_SET_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0) | ||
119 | #define SIR_UART_CLEAR_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0) | ||
120 | |||
121 | #define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v) | ||
122 | #define SIR_UART_DISABLE_INTS(port) SIR_UART_PUT_IER(port, 0) | ||
123 | #define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0) | ||
124 | #define SIR_UART_ENABLE_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0) | ||
125 | #define SIR_UART_STOP_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0) | ||
126 | #define SIR_UART_ENABLE_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0) | ||
127 | |||
128 | static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port) | ||
129 | { | ||
130 | unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR); | ||
131 | port->lsr |= (lsr & (BI|FE|PE|OE)); | ||
132 | return lsr | port->lsr; | ||
133 | } | ||
134 | |||
135 | static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port) | ||
136 | { | ||
137 | port->lsr = 0; | ||
138 | bfin_read16(port->membase + OFFSET_LSR); | ||
139 | } | ||
140 | #endif | ||
141 | |||
142 | static const unsigned short per[][4] = { | ||
143 | /* rx pin tx pin NULL uart_number */ | ||
144 | {P_UART0_RX, P_UART0_TX, 0, 0}, | ||
145 | {P_UART1_RX, P_UART1_TX, 0, 1}, | ||
146 | {P_UART2_RX, P_UART2_TX, 0, 2}, | ||
147 | {P_UART3_RX, P_UART3_TX, 0, 3}, | ||
148 | }; | ||