diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 74 | ||||
-rw-r--r-- | drivers/serial/8250_au1x00.c | 5 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart.h | 19 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 37 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm1.c | 2 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.c | 2 | ||||
-rw-r--r-- | drivers/serial/imx.c | 40 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 123 |
8 files changed, 191 insertions, 111 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 674b15c78f68..bbf78aaf9e01 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value) | |||
362 | #define serial_inp(up, offset) serial_in(up, offset) | 362 | #define serial_inp(up, offset) serial_in(up, offset) |
363 | #define serial_outp(up, offset, value) serial_out(up, offset, value) | 363 | #define serial_outp(up, offset, value) serial_out(up, offset, value) |
364 | 364 | ||
365 | /* Uart divisor latch read */ | ||
366 | static inline int _serial_dl_read(struct uart_8250_port *up) | ||
367 | { | ||
368 | return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8; | ||
369 | } | ||
370 | |||
371 | /* Uart divisor latch write */ | ||
372 | static inline void _serial_dl_write(struct uart_8250_port *up, int value) | ||
373 | { | ||
374 | serial_outp(up, UART_DLL, value & 0xff); | ||
375 | serial_outp(up, UART_DLM, value >> 8 & 0xff); | ||
376 | } | ||
377 | |||
378 | #ifdef CONFIG_SERIAL_8250_AU1X00 | ||
379 | /* Au1x00 haven't got a standard divisor latch */ | ||
380 | static int serial_dl_read(struct uart_8250_port *up) | ||
381 | { | ||
382 | if (up->port.iotype == UPIO_AU) | ||
383 | return __raw_readl(up->port.membase + 0x28); | ||
384 | else | ||
385 | return _serial_dl_read(up); | ||
386 | } | ||
387 | |||
388 | static void serial_dl_write(struct uart_8250_port *up, int value) | ||
389 | { | ||
390 | if (up->port.iotype == UPIO_AU) | ||
391 | __raw_writel(value, up->port.membase + 0x28); | ||
392 | else | ||
393 | _serial_dl_write(up, value); | ||
394 | } | ||
395 | #else | ||
396 | #define serial_dl_read(up) _serial_dl_read(up) | ||
397 | #define serial_dl_write(up, value) _serial_dl_write(up, value) | ||
398 | #endif | ||
365 | 399 | ||
366 | /* | 400 | /* |
367 | * For the 16C950 | 401 | * For the 16C950 |
@@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up) | |||
494 | */ | 528 | */ |
495 | static int size_fifo(struct uart_8250_port *up) | 529 | static int size_fifo(struct uart_8250_port *up) |
496 | { | 530 | { |
497 | unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr; | 531 | unsigned char old_fcr, old_mcr, old_lcr; |
532 | unsigned short old_dl; | ||
498 | int count; | 533 | int count; |
499 | 534 | ||
500 | old_lcr = serial_inp(up, UART_LCR); | 535 | old_lcr = serial_inp(up, UART_LCR); |
@@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up) | |||
505 | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); | 540 | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); |
506 | serial_outp(up, UART_MCR, UART_MCR_LOOP); | 541 | serial_outp(up, UART_MCR, UART_MCR_LOOP); |
507 | serial_outp(up, UART_LCR, UART_LCR_DLAB); | 542 | serial_outp(up, UART_LCR, UART_LCR_DLAB); |
508 | old_dll = serial_inp(up, UART_DLL); | 543 | old_dl = serial_dl_read(up); |
509 | old_dlm = serial_inp(up, UART_DLM); | 544 | serial_dl_write(up, 0x0001); |
510 | serial_outp(up, UART_DLL, 0x01); | ||
511 | serial_outp(up, UART_DLM, 0x00); | ||
512 | serial_outp(up, UART_LCR, 0x03); | 545 | serial_outp(up, UART_LCR, 0x03); |
513 | for (count = 0; count < 256; count++) | 546 | for (count = 0; count < 256; count++) |
514 | serial_outp(up, UART_TX, count); | 547 | serial_outp(up, UART_TX, count); |
@@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up) | |||
519 | serial_outp(up, UART_FCR, old_fcr); | 552 | serial_outp(up, UART_FCR, old_fcr); |
520 | serial_outp(up, UART_MCR, old_mcr); | 553 | serial_outp(up, UART_MCR, old_mcr); |
521 | serial_outp(up, UART_LCR, UART_LCR_DLAB); | 554 | serial_outp(up, UART_LCR, UART_LCR_DLAB); |
522 | serial_outp(up, UART_DLL, old_dll); | 555 | serial_dl_write(up, old_dl); |
523 | serial_outp(up, UART_DLM, old_dlm); | ||
524 | serial_outp(up, UART_LCR, old_lcr); | 556 | serial_outp(up, UART_LCR, old_lcr); |
525 | 557 | ||
526 | return count; | 558 | return count; |
@@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
750 | 782 | ||
751 | serial_outp(up, UART_LCR, 0xE0); | 783 | serial_outp(up, UART_LCR, 0xE0); |
752 | 784 | ||
753 | quot = serial_inp(up, UART_DLM) << 8; | 785 | quot = serial_dl_read(up); |
754 | quot += serial_inp(up, UART_DLL); | ||
755 | quot <<= 3; | 786 | quot <<= 3; |
756 | 787 | ||
757 | status1 = serial_in(up, 0x04); /* EXCR1 */ | 788 | status1 = serial_in(up, 0x04); /* EXCR1 */ |
@@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
759 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | 790 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ |
760 | serial_outp(up, 0x04, status1); | 791 | serial_outp(up, 0x04, status1); |
761 | 792 | ||
762 | serial_outp(up, UART_DLL, quot & 0xff); | 793 | serial_dl_write(up, quot); |
763 | serial_outp(up, UART_DLM, quot >> 8); | ||
764 | 794 | ||
765 | serial_outp(up, UART_LCR, 0); | 795 | serial_outp(up, UART_LCR, 0); |
766 | 796 | ||
@@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios, | |||
1862 | serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ | 1892 | serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ |
1863 | } | 1893 | } |
1864 | 1894 | ||
1865 | serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ | 1895 | serial_dl_write(up, quot); |
1866 | serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ | ||
1867 | 1896 | ||
1868 | /* | 1897 | /* |
1869 | * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR | 1898 | * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR |
@@ -1906,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) | |||
1906 | int ret = 0; | 1935 | int ret = 0; |
1907 | 1936 | ||
1908 | switch (up->port.iotype) { | 1937 | switch (up->port.iotype) { |
1938 | case UPIO_AU: | ||
1939 | size = 0x100000; | ||
1940 | /* fall thru */ | ||
1909 | case UPIO_MEM: | 1941 | case UPIO_MEM: |
1910 | if (!up->port.mapbase) | 1942 | if (!up->port.mapbase) |
1911 | break; | 1943 | break; |
@@ -1938,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) | |||
1938 | unsigned int size = 8 << up->port.regshift; | 1970 | unsigned int size = 8 << up->port.regshift; |
1939 | 1971 | ||
1940 | switch (up->port.iotype) { | 1972 | switch (up->port.iotype) { |
1973 | case UPIO_AU: | ||
1974 | size = 0x100000; | ||
1975 | /* fall thru */ | ||
1941 | case UPIO_MEM: | 1976 | case UPIO_MEM: |
1942 | if (!up->port.mapbase) | 1977 | if (!up->port.mapbase) |
1943 | break; | 1978 | break; |
@@ -2200,10 +2235,17 @@ static void | |||
2200 | serial8250_console_write(struct console *co, const char *s, unsigned int count) | 2235 | serial8250_console_write(struct console *co, const char *s, unsigned int count) |
2201 | { | 2236 | { |
2202 | struct uart_8250_port *up = &serial8250_ports[co->index]; | 2237 | struct uart_8250_port *up = &serial8250_ports[co->index]; |
2238 | unsigned long flags; | ||
2203 | unsigned int ier; | 2239 | unsigned int ier; |
2240 | int locked = 1; | ||
2204 | 2241 | ||
2205 | touch_nmi_watchdog(); | 2242 | touch_nmi_watchdog(); |
2206 | 2243 | ||
2244 | if (oops_in_progress) { | ||
2245 | locked = spin_trylock_irqsave(&up->port.lock, flags); | ||
2246 | } else | ||
2247 | spin_lock_irqsave(&up->port.lock, flags); | ||
2248 | |||
2207 | /* | 2249 | /* |
2208 | * First save the IER then disable the interrupts | 2250 | * First save the IER then disable the interrupts |
2209 | */ | 2251 | */ |
@@ -2221,8 +2263,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) | |||
2221 | * and restore the IER | 2263 | * and restore the IER |
2222 | */ | 2264 | */ |
2223 | wait_for_xmitr(up, BOTH_EMPTY); | 2265 | wait_for_xmitr(up, BOTH_EMPTY); |
2224 | up->ier |= UART_IER_THRI; | 2266 | serial_out(up, UART_IER, ier); |
2225 | serial_out(up, UART_IER, ier | UART_IER_THRI); | 2267 | |
2268 | if (locked) | ||
2269 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
2226 | } | 2270 | } |
2227 | 2271 | ||
2228 | static int serial8250_console_setup(struct console *co, char *options) | 2272 | static int serial8250_console_setup(struct console *co, char *options) |
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c index 3d1bfd07208d..58015fd14be9 100644 --- a/drivers/serial/8250_au1x00.c +++ b/drivers/serial/8250_au1x00.c | |||
@@ -30,13 +30,12 @@ | |||
30 | { \ | 30 | { \ |
31 | .iobase = _base, \ | 31 | .iobase = _base, \ |
32 | .membase = (void __iomem *)_base,\ | 32 | .membase = (void __iomem *)_base,\ |
33 | .mapbase = _base, \ | 33 | .mapbase = CPHYSADDR(_base), \ |
34 | .irq = _irq, \ | 34 | .irq = _irq, \ |
35 | .uartclk = 0, /* filled */ \ | 35 | .uartclk = 0, /* filled */ \ |
36 | .regshift = 2, \ | 36 | .regshift = 2, \ |
37 | .iotype = UPIO_AU, \ | 37 | .iotype = UPIO_AU, \ |
38 | .flags = UPF_SKIP_TEST | \ | 38 | .flags = UPF_SKIP_TEST \ |
39 | UPF_IOREMAP, \ | ||
40 | } | 39 | } |
41 | 40 | ||
42 | static struct plat_serial8250_port au1x00_data[] = { | 41 | static struct plat_serial8250_port au1x00_data[] = { |
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index aa5eb7ddeda9..3b35cb779539 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h | |||
@@ -5,6 +5,13 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | 6 | * Copyright (C) 2004 Freescale Semiconductor, Inc. |
7 | * | 7 | * |
8 | * 2006 (c) MontaVista Software, Inc. | ||
9 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public License | ||
12 | * version 2. This program is licensed "as is" without any warranty of any | ||
13 | * kind, whether express or implied. | ||
14 | * | ||
8 | */ | 15 | */ |
9 | #ifndef CPM_UART_H | 16 | #ifndef CPM_UART_H |
10 | #define CPM_UART_H | 17 | #define CPM_UART_H |
@@ -101,12 +108,13 @@ static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo | |||
101 | int offset; | 108 | int offset; |
102 | u32 val = (u32)addr; | 109 | u32 val = (u32)addr; |
103 | /* sane check */ | 110 | /* sane check */ |
104 | if ((val >= (u32)pinfo->mem_addr) && | 111 | if (likely((val >= (u32)pinfo->mem_addr)) && |
105 | (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { | 112 | (val<((u32)pinfo->mem_addr + pinfo->mem_size))) { |
106 | offset = val - (u32)pinfo->mem_addr; | 113 | offset = val - (u32)pinfo->mem_addr; |
107 | return pinfo->dma_addr+offset; | 114 | return pinfo->dma_addr+offset; |
108 | } | 115 | } |
109 | printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); | 116 | /* something nasty happened */ |
117 | BUG(); | ||
110 | return 0; | 118 | return 0; |
111 | } | 119 | } |
112 | 120 | ||
@@ -115,12 +123,13 @@ static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo | |||
115 | int offset; | 123 | int offset; |
116 | u32 val = addr; | 124 | u32 val = addr; |
117 | /* sane check */ | 125 | /* sane check */ |
118 | if ((val >= pinfo->dma_addr) && | 126 | if (likely((val >= pinfo->dma_addr) && |
119 | (val<(pinfo->dma_addr + pinfo->mem_size))) { | 127 | (val<(pinfo->dma_addr + pinfo->mem_size)))) { |
120 | offset = val - (u32)pinfo->dma_addr; | 128 | offset = val - (u32)pinfo->dma_addr; |
121 | return (void*)(pinfo->mem_addr+offset); | 129 | return (void*)(pinfo->mem_addr+offset); |
122 | } | 130 | } |
123 | printk("%s(): address %x to translate out of range!\n", __FUNCTION__, val); | 131 | /* something nasty happened */ |
132 | BUG(); | ||
124 | return 0; | 133 | return 0; |
125 | } | 134 | } |
126 | 135 | ||
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index ced193bf9e1e..969f94900431 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c | |||
@@ -12,7 +12,8 @@ | |||
12 | * | 12 | * |
13 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | 13 | * Copyright (C) 2004 Freescale Semiconductor, Inc. |
14 | * (C) 2004 Intracom, S.A. | 14 | * (C) 2004 Intracom, S.A. |
15 | * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com> | 15 | * (C) 2005-2006 MontaVista Software, Inc. |
16 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
16 | * | 17 | * |
17 | * This program is free software; you can redistribute it and/or modify | 18 | * This program is free software; you can redistribute it and/or modify |
18 | * it under the terms of the GNU General Public License as published by | 19 | * it under the terms of the GNU General Public License as published by |
@@ -81,7 +82,7 @@ early_uart_get_pdev(int index) | |||
81 | } | 82 | } |
82 | 83 | ||
83 | 84 | ||
84 | void cpm_uart_count(void) | 85 | static void cpm_uart_count(void) |
85 | { | 86 | { |
86 | cpm_uart_nr = 0; | 87 | cpm_uart_nr = 0; |
87 | #ifdef CONFIG_SERIAL_CPM_SMC1 | 88 | #ifdef CONFIG_SERIAL_CPM_SMC1 |
@@ -104,6 +105,21 @@ void cpm_uart_count(void) | |||
104 | #endif | 105 | #endif |
105 | } | 106 | } |
106 | 107 | ||
108 | /* Get UART number by its id */ | ||
109 | static int cpm_uart_id2nr(int id) | ||
110 | { | ||
111 | int i; | ||
112 | if (id < UART_NR) { | ||
113 | for (i=0; i<UART_NR; i++) { | ||
114 | if (cpm_uart_port_map[i] == id) | ||
115 | return i; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* not found or invalid argument */ | ||
120 | return -1; | ||
121 | } | ||
122 | |||
107 | /* | 123 | /* |
108 | * Check, if transmit buffers are processed | 124 | * Check, if transmit buffers are processed |
109 | */ | 125 | */ |
@@ -457,7 +473,11 @@ static void cpm_uart_shutdown(struct uart_port *port) | |||
457 | } | 473 | } |
458 | 474 | ||
459 | /* Shut them really down and reinit buffer descriptors */ | 475 | /* Shut them really down and reinit buffer descriptors */ |
460 | cpm_line_cr_cmd(line, CPM_CR_STOP_TX); | 476 | if (IS_SMC(pinfo)) |
477 | cpm_line_cr_cmd(line, CPM_CR_STOP_TX); | ||
478 | else | ||
479 | cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX); | ||
480 | |||
461 | cpm_uart_initbd(pinfo); | 481 | cpm_uart_initbd(pinfo); |
462 | } | 482 | } |
463 | } | 483 | } |
@@ -1008,7 +1028,11 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) | |||
1008 | int line; | 1028 | int line; |
1009 | u32 mem, pram; | 1029 | u32 mem, pram; |
1010 | 1030 | ||
1011 | for (line=0; line<UART_NR && cpm_uart_port_map[line]!=pdata->fs_no; line++); | 1031 | line = cpm_uart_id2nr(idx); |
1032 | if(line < 0) { | ||
1033 | printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); | ||
1034 | return -1; | ||
1035 | } | ||
1012 | 1036 | ||
1013 | pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; | 1037 | pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx]; |
1014 | 1038 | ||
@@ -1241,8 +1265,7 @@ static int cpm_uart_drv_probe(struct device *dev) | |||
1241 | } | 1265 | } |
1242 | 1266 | ||
1243 | pdata = pdev->dev.platform_data; | 1267 | pdata = pdev->dev.platform_data; |
1244 | pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", | 1268 | pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no)); |
1245 | cpm_uart_port_map[pdata->fs_no]); | ||
1246 | 1269 | ||
1247 | if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) | 1270 | if ((ret = cpm_uart_drv_get_platform_data(pdev, 0))) |
1248 | return ret; | 1271 | return ret; |
@@ -1261,7 +1284,7 @@ static int cpm_uart_drv_remove(struct device *dev) | |||
1261 | struct fs_uart_platform_info *pdata = pdev->dev.platform_data; | 1284 | struct fs_uart_platform_info *pdata = pdev->dev.platform_data; |
1262 | 1285 | ||
1263 | pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", | 1286 | pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n", |
1264 | cpm_uart_port_map[pdata->fs_no]); | 1287 | cpm_uart_id2nr(pdata->fs_no)); |
1265 | 1288 | ||
1266 | uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); | 1289 | uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port); |
1267 | return 0; | 1290 | return 0; |
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index a5a30622637a..17406a05ce1f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c | |||
@@ -8,6 +8,8 @@ | |||
8 | * | 8 | * |
9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | 9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. |
10 | * (C) 2004 Intracom, S.A. | 10 | * (C) 2004 Intracom, S.A. |
11 | * (C) 2006 MontaVista Software, Inc. | ||
12 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
11 | * | 13 | * |
12 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index 7c6b07aeea92..4b2de08f46d0 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c | |||
@@ -8,6 +8,8 @@ | |||
8 | * | 8 | * |
9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. | 9 | * Copyright (C) 2004 Freescale Semiconductor, Inc. |
10 | * (C) 2004 Intracom, S.A. | 10 | * (C) 2004 Intracom, S.A. |
11 | * (C) 2006 MontaVista Software, Inc. | ||
12 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
11 | * | 13 | * |
12 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index c3b7a6673e9c..d202eb4f3848 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/io.h> | 45 | #include <asm/io.h> |
46 | #include <asm/irq.h> | 46 | #include <asm/irq.h> |
47 | #include <asm/hardware.h> | 47 | #include <asm/hardware.h> |
48 | #include <asm/arch/imx-uart.h> | ||
48 | 49 | ||
49 | /* We've been assigned a range on the "Low-density serial ports" major */ | 50 | /* We've been assigned a range on the "Low-density serial ports" major */ |
50 | #define SERIAL_IMX_MAJOR 204 | 51 | #define SERIAL_IMX_MAJOR 204 |
@@ -73,7 +74,8 @@ struct imx_port { | |||
73 | struct uart_port port; | 74 | struct uart_port port; |
74 | struct timer_list timer; | 75 | struct timer_list timer; |
75 | unsigned int old_status; | 76 | unsigned int old_status; |
76 | int txirq,rxirq,rtsirq; | 77 | int txirq,rxirq,rtsirq; |
78 | int have_rtscts:1; | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | /* | 81 | /* |
@@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios, | |||
491 | ucr2 = UCR2_SRST | UCR2_IRTS; | 493 | ucr2 = UCR2_SRST | UCR2_IRTS; |
492 | 494 | ||
493 | if (termios->c_cflag & CRTSCTS) { | 495 | if (termios->c_cflag & CRTSCTS) { |
494 | ucr2 &= ~UCR2_IRTS; | 496 | if( sport->have_rtscts ) { |
495 | ucr2 |= UCR2_CTSC; | 497 | ucr2 &= ~UCR2_IRTS; |
498 | ucr2 |= UCR2_CTSC; | ||
499 | } else { | ||
500 | termios->c_cflag &= ~CRTSCTS; | ||
501 | } | ||
496 | } | 502 | } |
497 | 503 | ||
498 | if (termios->c_cflag & CSTOPB) | 504 | if (termios->c_cflag & CSTOPB) |
@@ -719,27 +725,6 @@ static void __init imx_init_ports(void) | |||
719 | imx_ports[i].timer.function = imx_timeout; | 725 | imx_ports[i].timer.function = imx_timeout; |
720 | imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; | 726 | imx_ports[i].timer.data = (unsigned long)&imx_ports[i]; |
721 | } | 727 | } |
722 | |||
723 | imx_gpio_mode(PC9_PF_UART1_CTS); | ||
724 | imx_gpio_mode(PC10_PF_UART1_RTS); | ||
725 | imx_gpio_mode(PC11_PF_UART1_TXD); | ||
726 | imx_gpio_mode(PC12_PF_UART1_RXD); | ||
727 | imx_gpio_mode(PB28_PF_UART2_CTS); | ||
728 | imx_gpio_mode(PB29_PF_UART2_RTS); | ||
729 | |||
730 | imx_gpio_mode(PB30_PF_UART2_TXD); | ||
731 | imx_gpio_mode(PB31_PF_UART2_RXD); | ||
732 | |||
733 | #if 0 /* We don't need these, on the mx1 the _modem_ side of the uart | ||
734 | * is implemented. | ||
735 | */ | ||
736 | imx_gpio_mode(PD7_AF_UART2_DTR); | ||
737 | imx_gpio_mode(PD8_AF_UART2_DCD); | ||
738 | imx_gpio_mode(PD9_AF_UART2_RI); | ||
739 | imx_gpio_mode(PD10_AF_UART2_DSR); | ||
740 | #endif | ||
741 | |||
742 | |||
743 | } | 728 | } |
744 | 729 | ||
745 | #ifdef CONFIG_SERIAL_IMX_CONSOLE | 730 | #ifdef CONFIG_SERIAL_IMX_CONSOLE |
@@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev) | |||
932 | 917 | ||
933 | static int serial_imx_probe(struct platform_device *dev) | 918 | static int serial_imx_probe(struct platform_device *dev) |
934 | { | 919 | { |
920 | struct imxuart_platform_data *pdata; | ||
921 | |||
935 | imx_ports[dev->id].port.dev = &dev->dev; | 922 | imx_ports[dev->id].port.dev = &dev->dev; |
923 | |||
924 | pdata = (struct imxuart_platform_data *)dev->dev.platform_data; | ||
925 | if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) | ||
926 | imx_ports[dev->id].have_rtscts = 1; | ||
927 | |||
936 | uart_add_one_port(&imx_reg, &imx_ports[dev->id].port); | 928 | uart_add_one_port(&imx_reg, &imx_ports[dev->id].port); |
937 | platform_set_drvdata(dev, &imx_ports[dev->id]); | 929 | platform_set_drvdata(dev, &imx_ports[dev->id]); |
938 | return 0; | 930 | return 0; |
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index fcd7744c4253..17839e753e4c 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) | |||
1500 | static struct uart_state *uart_get(struct uart_driver *drv, int line) | 1500 | static struct uart_state *uart_get(struct uart_driver *drv, int line) |
1501 | { | 1501 | { |
1502 | struct uart_state *state; | 1502 | struct uart_state *state; |
1503 | int ret = 0; | ||
1503 | 1504 | ||
1504 | mutex_lock(&port_mutex); | ||
1505 | state = drv->state + line; | 1505 | state = drv->state + line; |
1506 | if (mutex_lock_interruptible(&state->mutex)) { | 1506 | if (mutex_lock_interruptible(&state->mutex)) { |
1507 | state = ERR_PTR(-ERESTARTSYS); | 1507 | ret = -ERESTARTSYS; |
1508 | goto out; | 1508 | goto err; |
1509 | } | 1509 | } |
1510 | 1510 | ||
1511 | state->count++; | 1511 | state->count++; |
1512 | if (!state->port) { | 1512 | if (!state->port || state->port->flags & UPF_DEAD) { |
1513 | state->count--; | 1513 | ret = -ENXIO; |
1514 | mutex_unlock(&state->mutex); | 1514 | goto err_unlock; |
1515 | state = ERR_PTR(-ENXIO); | ||
1516 | goto out; | ||
1517 | } | 1515 | } |
1518 | 1516 | ||
1519 | if (!state->info) { | 1517 | if (!state->info) { |
@@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) | |||
1531 | tasklet_init(&state->info->tlet, uart_tasklet_action, | 1529 | tasklet_init(&state->info->tlet, uart_tasklet_action, |
1532 | (unsigned long)state); | 1530 | (unsigned long)state); |
1533 | } else { | 1531 | } else { |
1534 | state->count--; | 1532 | ret = -ENOMEM; |
1535 | mutex_unlock(&state->mutex); | 1533 | goto err_unlock; |
1536 | state = ERR_PTR(-ENOMEM); | ||
1537 | } | 1534 | } |
1538 | } | 1535 | } |
1539 | |||
1540 | out: | ||
1541 | mutex_unlock(&port_mutex); | ||
1542 | return state; | 1536 | return state; |
1537 | |||
1538 | err_unlock: | ||
1539 | state->count--; | ||
1540 | mutex_unlock(&state->mutex); | ||
1541 | err: | ||
1542 | return ERR_PTR(ret); | ||
1543 | } | 1543 | } |
1544 | 1544 | ||
1545 | /* | 1545 | /* |
@@ -1907,9 +1907,12 @@ uart_set_options(struct uart_port *port, struct console *co, | |||
1907 | static void uart_change_pm(struct uart_state *state, int pm_state) | 1907 | static void uart_change_pm(struct uart_state *state, int pm_state) |
1908 | { | 1908 | { |
1909 | struct uart_port *port = state->port; | 1909 | struct uart_port *port = state->port; |
1910 | if (port->ops->pm) | 1910 | |
1911 | port->ops->pm(port, pm_state, state->pm_state); | 1911 | if (state->pm_state != pm_state) { |
1912 | state->pm_state = pm_state; | 1912 | if (port->ops->pm) |
1913 | port->ops->pm(port, pm_state, state->pm_state); | ||
1914 | state->pm_state = pm_state; | ||
1915 | } | ||
1913 | } | 1916 | } |
1914 | 1917 | ||
1915 | int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) | 1918 | int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) |
@@ -2085,45 +2088,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, | |||
2085 | } | 2088 | } |
2086 | } | 2089 | } |
2087 | 2090 | ||
2088 | /* | ||
2089 | * This reverses the effects of uart_configure_port, hanging up the | ||
2090 | * port before removal. | ||
2091 | */ | ||
2092 | static void | ||
2093 | uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state) | ||
2094 | { | ||
2095 | struct uart_port *port = state->port; | ||
2096 | struct uart_info *info = state->info; | ||
2097 | |||
2098 | if (info && info->tty) | ||
2099 | tty_vhangup(info->tty); | ||
2100 | |||
2101 | mutex_lock(&state->mutex); | ||
2102 | |||
2103 | state->info = NULL; | ||
2104 | |||
2105 | /* | ||
2106 | * Free the port IO and memory resources, if any. | ||
2107 | */ | ||
2108 | if (port->type != PORT_UNKNOWN) | ||
2109 | port->ops->release_port(port); | ||
2110 | |||
2111 | /* | ||
2112 | * Indicate that there isn't a port here anymore. | ||
2113 | */ | ||
2114 | port->type = PORT_UNKNOWN; | ||
2115 | |||
2116 | /* | ||
2117 | * Kill the tasklet, and free resources. | ||
2118 | */ | ||
2119 | if (info) { | ||
2120 | tasklet_kill(&info->tlet); | ||
2121 | kfree(info); | ||
2122 | } | ||
2123 | |||
2124 | mutex_unlock(&state->mutex); | ||
2125 | } | ||
2126 | |||
2127 | static struct tty_operations uart_ops = { | 2091 | static struct tty_operations uart_ops = { |
2128 | .open = uart_open, | 2092 | .open = uart_open, |
2129 | .close = uart_close, | 2093 | .close = uart_close, |
@@ -2270,6 +2234,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2270 | state = drv->state + port->line; | 2234 | state = drv->state + port->line; |
2271 | 2235 | ||
2272 | mutex_lock(&port_mutex); | 2236 | mutex_lock(&port_mutex); |
2237 | mutex_lock(&state->mutex); | ||
2273 | if (state->port) { | 2238 | if (state->port) { |
2274 | ret = -EINVAL; | 2239 | ret = -EINVAL; |
2275 | goto out; | 2240 | goto out; |
@@ -2304,7 +2269,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2304 | port->cons && !(port->cons->flags & CON_ENABLED)) | 2269 | port->cons && !(port->cons->flags & CON_ENABLED)) |
2305 | register_console(port->cons); | 2270 | register_console(port->cons); |
2306 | 2271 | ||
2272 | /* | ||
2273 | * Ensure UPF_DEAD is not set. | ||
2274 | */ | ||
2275 | port->flags &= ~UPF_DEAD; | ||
2276 | |||
2307 | out: | 2277 | out: |
2278 | mutex_unlock(&state->mutex); | ||
2308 | mutex_unlock(&port_mutex); | 2279 | mutex_unlock(&port_mutex); |
2309 | 2280 | ||
2310 | return ret; | 2281 | return ret; |
@@ -2322,6 +2293,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2322 | int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) | 2293 | int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) |
2323 | { | 2294 | { |
2324 | struct uart_state *state = drv->state + port->line; | 2295 | struct uart_state *state = drv->state + port->line; |
2296 | struct uart_info *info; | ||
2325 | 2297 | ||
2326 | BUG_ON(in_interrupt()); | 2298 | BUG_ON(in_interrupt()); |
2327 | 2299 | ||
@@ -2332,11 +2304,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) | |||
2332 | mutex_lock(&port_mutex); | 2304 | mutex_lock(&port_mutex); |
2333 | 2305 | ||
2334 | /* | 2306 | /* |
2307 | * Mark the port "dead" - this prevents any opens from | ||
2308 | * succeeding while we shut down the port. | ||
2309 | */ | ||
2310 | mutex_lock(&state->mutex); | ||
2311 | port->flags |= UPF_DEAD; | ||
2312 | mutex_unlock(&state->mutex); | ||
2313 | |||
2314 | /* | ||
2335 | * Remove the devices from devfs | 2315 | * Remove the devices from devfs |
2336 | */ | 2316 | */ |
2337 | tty_unregister_device(drv->tty_driver, port->line); | 2317 | tty_unregister_device(drv->tty_driver, port->line); |
2338 | 2318 | ||
2339 | uart_unconfigure_port(drv, state); | 2319 | info = state->info; |
2320 | if (info && info->tty) | ||
2321 | tty_vhangup(info->tty); | ||
2322 | |||
2323 | /* | ||
2324 | * All users of this port should now be disconnected from | ||
2325 | * this driver, and the port shut down. We should be the | ||
2326 | * only thread fiddling with this port from now on. | ||
2327 | */ | ||
2328 | state->info = NULL; | ||
2329 | |||
2330 | /* | ||
2331 | * Free the port IO and memory resources, if any. | ||
2332 | */ | ||
2333 | if (port->type != PORT_UNKNOWN) | ||
2334 | port->ops->release_port(port); | ||
2335 | |||
2336 | /* | ||
2337 | * Indicate that there isn't a port here anymore. | ||
2338 | */ | ||
2339 | port->type = PORT_UNKNOWN; | ||
2340 | |||
2341 | /* | ||
2342 | * Kill the tasklet, and free resources. | ||
2343 | */ | ||
2344 | if (info) { | ||
2345 | tasklet_kill(&info->tlet); | ||
2346 | kfree(info); | ||
2347 | } | ||
2348 | |||
2340 | state->port = NULL; | 2349 | state->port = NULL; |
2341 | mutex_unlock(&port_mutex); | 2350 | mutex_unlock(&port_mutex); |
2342 | 2351 | ||