diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 7 | ||||
-rw-r--r-- | drivers/serial/8250_pci.c | 3 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 8 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 77 | ||||
-rw-r--r-- | drivers/serial/bfin_sport_uart.c | 58 | ||||
-rw-r--r-- | drivers/serial/icom.c | 20 | ||||
-rw-r--r-- | drivers/serial/imx.c | 294 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm.h | 1 | ||||
-rw-r--r-- | drivers/serial/jsm/jsm_tty.c | 14 | ||||
-rw-r--r-- | drivers/serial/timbuart.c | 526 | ||||
-rw-r--r-- | drivers/serial/timbuart.h | 58 |
12 files changed, 951 insertions, 116 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index a0127e93ade0..fb867a9f55e9 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = { | |||
287 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, | 287 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, |
288 | .flags = UART_CAP_FIFO, | 288 | .flags = UART_CAP_FIFO, |
289 | }, | 289 | }, |
290 | [PORT_AR7] = { | ||
291 | .name = "AR7", | ||
292 | .fifo_size = 16, | ||
293 | .tx_loadsz = 16, | ||
294 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, | ||
295 | .flags = UART_CAP_FIFO | UART_CAP_AFE, | ||
296 | }, | ||
290 | }; | 297 | }; |
291 | 298 | ||
292 | #if defined (CONFIG_SERIAL_8250_AU1X00) | 299 | #if defined (CONFIG_SERIAL_8250_AU1X00) |
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 938bc1b6c3fa..e371a9c15341 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c | |||
@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
2776 | { PCI_VENDOR_ID_OXSEMI, 0x950a, | 2776 | { PCI_VENDOR_ID_OXSEMI, 0x950a, |
2777 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 2777 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
2778 | pbn_b0_2_1130000 }, | 2778 | pbn_b0_2_1130000 }, |
2779 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950, | ||
2780 | PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0, | ||
2781 | pbn_b0_1_921600 }, | ||
2779 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, | 2782 | { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, |
2780 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 2783 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
2781 | pbn_b0_4_115200 }, | 2784 | pbn_b0_4_115200 }, |
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 343e3a35b6a3..641e800ed693 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -833,6 +833,7 @@ config SERIAL_IMX | |||
833 | bool "IMX serial port support" | 833 | bool "IMX serial port support" |
834 | depends on ARM && (ARCH_IMX || ARCH_MXC) | 834 | depends on ARM && (ARCH_IMX || ARCH_MXC) |
835 | select SERIAL_CORE | 835 | select SERIAL_CORE |
836 | select RATIONAL | ||
836 | help | 837 | help |
837 | If you have a machine based on a Motorola IMX CPU you | 838 | If you have a machine based on a Motorola IMX CPU you |
838 | can enable its onboard serial port by enabling this option. | 839 | can enable its onboard serial port by enabling this option. |
@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE | |||
1433 | default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) | 1434 | default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) |
1434 | default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) | 1435 | default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) |
1435 | 1436 | ||
1437 | config SERIAL_TIMBERDALE | ||
1438 | tristate "Support for timberdale UART" | ||
1439 | depends on MFD_TIMBERDALE | ||
1440 | select SERIAL_CORE | ||
1441 | ---help--- | ||
1442 | Add support for UART controller on timberdale. | ||
1443 | |||
1436 | endmenu | 1444 | endmenu |
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d438eb2a73de..45a8658f54d5 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile | |||
@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o | |||
77 | obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o | 77 | obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o |
78 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o | 78 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o |
79 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o | 79 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o |
80 | obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o | ||
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index d86123e03391..e2f6b1bfac98 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c | |||
@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) | |||
330 | /* Clear TFI bit */ | 330 | /* Clear TFI bit */ |
331 | UART_PUT_LSR(uart, TFI); | 331 | UART_PUT_LSR(uart, TFI); |
332 | #endif | 332 | #endif |
333 | /* Anomaly notes: | ||
334 | * 05000215 - we always clear ETBEI within last UART TX | ||
335 | * interrupt to end a string. It is always set | ||
336 | * when start a new tx. | ||
337 | */ | ||
333 | UART_CLEAR_IER(uart, ETBEI); | 338 | UART_CLEAR_IER(uart, ETBEI); |
334 | return; | 339 | return; |
335 | } | 340 | } |
@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) | |||
415 | set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); | 420 | set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); |
416 | set_dma_x_count(uart->tx_dma_channel, uart->tx_count); | 421 | set_dma_x_count(uart->tx_dma_channel, uart->tx_count); |
417 | set_dma_x_modify(uart->tx_dma_channel, 1); | 422 | set_dma_x_modify(uart->tx_dma_channel, 1); |
423 | SSYNC(); | ||
418 | enable_dma(uart->tx_dma_channel); | 424 | enable_dma(uart->tx_dma_channel); |
419 | 425 | ||
420 | UART_SET_IER(uart, ETBEI); | 426 | UART_SET_IER(uart, ETBEI); |
@@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) | |||
473 | void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) | 479 | void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) |
474 | { | 480 | { |
475 | int x_pos, pos; | 481 | int x_pos, pos; |
476 | unsigned long flags; | ||
477 | |||
478 | spin_lock_irqsave(&uart->port.lock, flags); | ||
479 | 482 | ||
483 | dma_disable_irq(uart->rx_dma_channel); | ||
484 | spin_lock_bh(&uart->port.lock); | ||
485 | |||
486 | /* 2D DMA RX buffer ring is used. Because curr_y_count and | ||
487 | * curr_x_count can't be read as an atomic operation, | ||
488 | * curr_y_count should be read before curr_x_count. When | ||
489 | * curr_x_count is read, curr_y_count may already indicate | ||
490 | * next buffer line. But, the position calculated here is | ||
491 | * still indicate the old line. The wrong position data may | ||
492 | * be smaller than current buffer tail, which cause garbages | ||
493 | * are received if it is not prohibit. | ||
494 | */ | ||
480 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | 495 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); |
481 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); | 496 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); |
482 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | 497 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; |
483 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT) | 498 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) |
484 | uart->rx_dma_nrows = 0; | 499 | uart->rx_dma_nrows = 0; |
485 | x_pos = DMA_RX_XCOUNT - x_pos; | 500 | x_pos = DMA_RX_XCOUNT - x_pos; |
486 | if (x_pos == DMA_RX_XCOUNT) | 501 | if (x_pos == DMA_RX_XCOUNT) |
487 | x_pos = 0; | 502 | x_pos = 0; |
488 | 503 | ||
489 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; | 504 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; |
490 | if (pos != uart->rx_dma_buf.tail) { | 505 | /* Ignore receiving data if new position is in the same line of |
506 | * current buffer tail and small. | ||
507 | */ | ||
508 | if (pos > uart->rx_dma_buf.tail || | ||
509 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
491 | uart->rx_dma_buf.head = pos; | 510 | uart->rx_dma_buf.head = pos; |
492 | bfin_serial_dma_rx_chars(uart); | 511 | bfin_serial_dma_rx_chars(uart); |
493 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | 512 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; |
494 | } | 513 | } |
495 | 514 | ||
496 | spin_unlock_irqrestore(&uart->port.lock, flags); | 515 | spin_unlock_bh(&uart->port.lock); |
516 | dma_enable_irq(uart->rx_dma_channel); | ||
497 | 517 | ||
498 | mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); | 518 | mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); |
499 | } | 519 | } |
@@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) | |||
514 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { | 534 | if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { |
515 | disable_dma(uart->tx_dma_channel); | 535 | disable_dma(uart->tx_dma_channel); |
516 | clear_dma_irqstat(uart->tx_dma_channel); | 536 | clear_dma_irqstat(uart->tx_dma_channel); |
537 | /* Anomaly notes: | ||
538 | * 05000215 - we always clear ETBEI within last UART TX | ||
539 | * interrupt to end a string. It is always set | ||
540 | * when start a new tx. | ||
541 | */ | ||
517 | UART_CLEAR_IER(uart, ETBEI); | 542 | UART_CLEAR_IER(uart, ETBEI); |
518 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); | 543 | xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); |
519 | uart->port.icount.tx += uart->tx_count; | 544 | uart->port.icount.tx += uart->tx_count; |
@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) | |||
532 | { | 557 | { |
533 | struct bfin_serial_port *uart = dev_id; | 558 | struct bfin_serial_port *uart = dev_id; |
534 | unsigned short irqstat; | 559 | unsigned short irqstat; |
560 | int x_pos, pos; | ||
535 | 561 | ||
536 | spin_lock(&uart->port.lock); | 562 | spin_lock(&uart->port.lock); |
537 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); | 563 | irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); |
538 | clear_dma_irqstat(uart->rx_dma_channel); | 564 | clear_dma_irqstat(uart->rx_dma_channel); |
539 | bfin_serial_dma_rx_chars(uart); | 565 | |
566 | uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); | ||
567 | x_pos = get_dma_curr_xcount(uart->rx_dma_channel); | ||
568 | uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; | ||
569 | if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0) | ||
570 | uart->rx_dma_nrows = 0; | ||
571 | |||
572 | pos = uart->rx_dma_nrows * DMA_RX_XCOUNT; | ||
573 | if (pos > uart->rx_dma_buf.tail || | ||
574 | uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) { | ||
575 | uart->rx_dma_buf.head = pos; | ||
576 | bfin_serial_dma_rx_chars(uart); | ||
577 | uart->rx_dma_buf.tail = uart->rx_dma_buf.head; | ||
578 | } | ||
579 | |||
540 | spin_unlock(&uart->port.lock); | 580 | spin_unlock(&uart->port.lock); |
541 | 581 | ||
542 | return IRQ_HANDLED; | 582 | return IRQ_HANDLED; |
@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, | |||
789 | __func__); | 829 | __func__); |
790 | } | 830 | } |
791 | 831 | ||
792 | if (termios->c_cflag & CSTOPB) | 832 | /* Anomaly notes: |
793 | lcr |= STB; | 833 | * 05000231 - STOP bit is always set to 1 whatever the user is set. |
834 | */ | ||
835 | if (termios->c_cflag & CSTOPB) { | ||
836 | if (ANOMALY_05000231) | ||
837 | printk(KERN_WARNING "STOP bits other than 1 is not " | ||
838 | "supported in case of anomaly 05000231.\n"); | ||
839 | else | ||
840 | lcr |= STB; | ||
841 | } | ||
794 | if (termios->c_cflag & PARENB) | 842 | if (termios->c_cflag & PARENB) |
795 | lcr |= PEN; | 843 | lcr |= PEN; |
796 | if (!(termios->c_cflag & PARODD)) | 844 | if (!(termios->c_cflag & PARODD)) |
@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port) | |||
940 | } | 988 | } |
941 | 989 | ||
942 | #ifdef CONFIG_CONSOLE_POLL | 990 | #ifdef CONFIG_CONSOLE_POLL |
991 | /* Anomaly notes: | ||
992 | * 05000099 - Because we only use THRE in poll_put and DR in poll_get, | ||
993 | * losing other bits of UART_LSR is not a problem here. | ||
994 | */ | ||
943 | static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) | 995 | static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) |
944 | { | 996 | { |
945 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; | 997 | struct bfin_serial_port *uart = (struct bfin_serial_port *)port; |
@@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s, | |||
1245 | } | 1297 | } |
1246 | } | 1298 | } |
1247 | 1299 | ||
1300 | /* | ||
1301 | * This should have a .setup or .early_setup in it, but then things get called | ||
1302 | * without the command line options, and the baud rate gets messed up - so | ||
1303 | * don't let the common infrastructure play with things. (see calls to setup | ||
1304 | * & earlysetup in ./kernel/printk.c:register_console() | ||
1305 | */ | ||
1248 | static struct __initdata console bfin_early_serial_console = { | 1306 | static struct __initdata console bfin_early_serial_console = { |
1249 | .name = "early_BFuart", | 1307 | .name = "early_BFuart", |
1250 | .write = early_serial_write, | 1308 | .write = early_serial_write, |
1251 | .device = uart_console_device, | 1309 | .device = uart_console_device, |
1252 | .flags = CON_PRINTBUFFER, | 1310 | .flags = CON_PRINTBUFFER, |
1253 | .setup = bfin_serial_console_setup, | ||
1254 | .index = -1, | 1311 | .index = -1, |
1255 | .data = &bfin_serial_reg, | 1312 | .data = &bfin_serial_reg, |
1256 | }; | 1313 | }; |
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index 529c0ff7952c..34b4ae0fe760 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c | |||
@@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) | |||
101 | { | 101 | { |
102 | pr_debug("%s value:%x\n", __func__, value); | 102 | pr_debug("%s value:%x\n", __func__, value); |
103 | /* Place a Start and Stop bit */ | 103 | /* Place a Start and Stop bit */ |
104 | __asm__ volatile ( | 104 | __asm__ __volatile__ ( |
105 | "R2 = b#01111111100;\n\t" | 105 | "R2 = b#01111111100;" |
106 | "R3 = b#10000000001;\n\t" | 106 | "R3 = b#10000000001;" |
107 | "%0 <<= 2;\n\t" | 107 | "%0 <<= 2;" |
108 | "%0 = %0 & R2;\n\t" | 108 | "%0 = %0 & R2;" |
109 | "%0 = %0 | R3;\n\t" | 109 | "%0 = %0 | R3;" |
110 | :"=r"(value) | 110 | : "=d"(value) |
111 | :"0"(value) | 111 | : "d"(value) |
112 | :"R2", "R3"); | 112 | : "ASTAT", "R2", "R3" |
113 | ); | ||
113 | pr_debug("%s value:%x\n", __func__, value); | 114 | pr_debug("%s value:%x\n", __func__, value); |
114 | 115 | ||
115 | SPORT_PUT_TX(up, value); | 116 | SPORT_PUT_TX(up, value); |
@@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) | |||
118 | static inline unsigned int rx_one_byte(struct sport_uart_port *up) | 119 | static inline unsigned int rx_one_byte(struct sport_uart_port *up) |
119 | { | 120 | { |
120 | unsigned int value, extract; | 121 | unsigned int value, extract; |
122 | u32 tmp_mask1, tmp_mask2, tmp_shift, tmp; | ||
121 | 123 | ||
122 | value = SPORT_GET_RX32(up); | 124 | value = SPORT_GET_RX32(up); |
123 | pr_debug("%s value:%x\n", __func__, value); | 125 | pr_debug("%s value:%x\n", __func__, value); |
124 | 126 | ||
125 | /* Extract 8 bits data */ | 127 | /* Extract 8 bits data */ |
126 | __asm__ volatile ( | 128 | __asm__ __volatile__ ( |
127 | "R5 = 0;\n\t" | 129 | "%[extr] = 0;" |
128 | "P0 = 8;\n\t" | 130 | "%[mask1] = 0x1801(Z);" |
129 | "R1 = 0x1801(Z);\n\t" | 131 | "%[mask2] = 0x0300(Z);" |
130 | "R3 = 0x0300(Z);\n\t" | 132 | "%[shift] = 0;" |
131 | "R4 = 0;\n\t" | 133 | "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];" |
132 | "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" | 134 | ".Lloop_s:" |
133 | "R2 = extract(%1, R1.L)(Z);\n\t" | 135 | "%[tmp] = extract(%[val], %[mask1].L)(Z);" |
134 | "R2 <<= R4;\n\t" | 136 | "%[tmp] <<= %[shift];" |
135 | "R5 = R5 | R2;\n\t" | 137 | "%[extr] = %[extr] | %[tmp];" |
136 | "R1 = R1 - R3;\nloop_e:\t" | 138 | "%[mask1] = %[mask1] - %[mask2];" |
137 | "R4 += 1;\n\t" | 139 | ".Lloop_e:" |
138 | "%0 = R5;\n\t" | 140 | "%[shift] += 1;" |
139 | :"=r"(extract) | 141 | : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp), |
140 | :"r"(value) | 142 | [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2) |
141 | :"P0", "R1", "R2","R3","R4", "R5"); | 143 | : "d"(value), [lc]"a"(8) |
144 | : "ASTAT", "LB0", "LC0", "LT0" | ||
145 | ); | ||
142 | 146 | ||
143 | pr_debug(" extract:%x\n", extract); | 147 | pr_debug(" extract:%x\n", extract); |
144 | return extract; | 148 | return extract; |
@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) | |||
149 | int tclkdiv, tfsdiv, rclkdiv; | 153 | int tclkdiv, tfsdiv, rclkdiv; |
150 | 154 | ||
151 | /* Set TCR1 and TCR2 */ | 155 | /* Set TCR1 and TCR2 */ |
152 | SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); | 156 | SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); |
153 | SPORT_PUT_TCR2(up, 10); | 157 | SPORT_PUT_TCR2(up, 10); |
154 | pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); | 158 | pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); |
155 | 159 | ||
@@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port) | |||
419 | } | 423 | } |
420 | 424 | ||
421 | static void sport_set_termios(struct uart_port *port, | 425 | static void sport_set_termios(struct uart_port *port, |
422 | struct termios *termios, struct termios *old) | 426 | struct ktermios *termios, struct ktermios *old) |
423 | { | 427 | { |
424 | pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); | 428 | pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); |
425 | uart_update_timeout(port, CS8 ,port->uartclk); | 429 | uart_update_timeout(port, CS8 ,port->uartclk); |
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index a461b3b2c72d..9f2891c2c4a2 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head); | |||
137 | static spinlock_t icom_lock; | 137 | static spinlock_t icom_lock; |
138 | 138 | ||
139 | #ifdef ICOM_TRACE | 139 | #ifdef ICOM_TRACE |
140 | static inline void trace(struct icom_port *, char *, unsigned long) {}; | 140 | static inline void trace(struct icom_port *icom_port, char *trace_pt, |
141 | unsigned long trace_data) | ||
142 | { | ||
143 | dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", | ||
144 | icom_port->port, trace_pt, trace_data); | ||
145 | } | ||
141 | #else | 146 | #else |
142 | static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; | 147 | static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; |
143 | #endif | 148 | #endif |
@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port) | |||
408 | release_firmware(fw); | 413 | release_firmware(fw); |
409 | 414 | ||
410 | /* Set Hardware level */ | 415 | /* Set Hardware level */ |
411 | if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) | 416 | if (icom_port->adapter->version == ADAPTER_V2) |
412 | writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); | 417 | writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); |
413 | 418 | ||
414 | /* Start the processor in Adapter */ | 419 | /* Start the processor in Adapter */ |
@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) | |||
861 | /* find icom_port for this interrupt */ | 866 | /* find icom_port for this interrupt */ |
862 | icom_adapter = (struct icom_adapter *) dev_id; | 867 | icom_adapter = (struct icom_adapter *) dev_id; |
863 | 868 | ||
864 | if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { | 869 | if (icom_adapter->version == ADAPTER_V2) { |
865 | int_reg = icom_adapter->base_addr + 0x8024; | 870 | int_reg = icom_adapter->base_addr + 0x8024; |
866 | 871 | ||
867 | adapter_interrupts = readl(int_reg); | 872 | adapter_interrupts = readl(int_reg); |
@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void) | |||
1647 | module_init(icom_init); | 1652 | module_init(icom_init); |
1648 | module_exit(icom_exit); | 1653 | module_exit(icom_exit); |
1649 | 1654 | ||
1650 | #ifdef ICOM_TRACE | ||
1651 | static inline void trace(struct icom_port *icom_port, char *trace_pt, | ||
1652 | unsigned long trace_data) | ||
1653 | { | ||
1654 | dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", | ||
1655 | icom_port->port, trace_pt, trace_data); | ||
1656 | } | ||
1657 | #endif | ||
1658 | |||
1659 | MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); | 1655 | MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); |
1660 | MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); | 1656 | MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); |
1661 | MODULE_SUPPORTED_DEVICE | 1657 | MODULE_SUPPORTED_DEVICE |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5f0be40dfdab..7b5d1de9cfe3 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -8,6 +8,9 @@ | |||
8 | * Author: Sascha Hauer <sascha@saschahauer.de> | 8 | * Author: Sascha Hauer <sascha@saschahauer.de> |
9 | * Copyright (C) 2004 Pengutronix | 9 | * Copyright (C) 2004 Pengutronix |
10 | * | 10 | * |
11 | * Copyright (C) 2009 emlix GmbH | ||
12 | * Author: Fabian Godehardt (added IrDA support for iMX) | ||
13 | * | ||
11 | * 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 |
12 | * 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 |
13 | * the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
@@ -41,6 +44,8 @@ | |||
41 | #include <linux/serial_core.h> | 44 | #include <linux/serial_core.h> |
42 | #include <linux/serial.h> | 45 | #include <linux/serial.h> |
43 | #include <linux/clk.h> | 46 | #include <linux/clk.h> |
47 | #include <linux/delay.h> | ||
48 | #include <linux/rational.h> | ||
44 | 49 | ||
45 | #include <asm/io.h> | 50 | #include <asm/io.h> |
46 | #include <asm/irq.h> | 51 | #include <asm/irq.h> |
@@ -148,6 +153,7 @@ | |||
148 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ | 153 | #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ |
149 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ | 154 | #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ |
150 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ | 155 | #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ |
156 | #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) | ||
151 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ | 157 | #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ |
152 | #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ | 158 | #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ |
153 | #define USR1_RTSS (1<<14) /* RTS pin status */ | 159 | #define USR1_RTSS (1<<14) /* RTS pin status */ |
@@ -211,10 +217,20 @@ struct imx_port { | |||
211 | struct timer_list timer; | 217 | struct timer_list timer; |
212 | unsigned int old_status; | 218 | unsigned int old_status; |
213 | int txirq,rxirq,rtsirq; | 219 | int txirq,rxirq,rtsirq; |
214 | int have_rtscts:1; | 220 | unsigned int have_rtscts:1; |
221 | unsigned int use_irda:1; | ||
222 | unsigned int irda_inv_rx:1; | ||
223 | unsigned int irda_inv_tx:1; | ||
224 | unsigned short trcv_delay; /* transceiver delay */ | ||
215 | struct clk *clk; | 225 | struct clk *clk; |
216 | }; | 226 | }; |
217 | 227 | ||
228 | #ifdef CONFIG_IRDA | ||
229 | #define USE_IRDA(sport) ((sport)->use_irda) | ||
230 | #else | ||
231 | #define USE_IRDA(sport) (0) | ||
232 | #endif | ||
233 | |||
218 | /* | 234 | /* |
219 | * Handle any change of modem status signal since we were last called. | 235 | * Handle any change of modem status signal since we were last called. |
220 | */ | 236 | */ |
@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port) | |||
268 | struct imx_port *sport = (struct imx_port *)port; | 284 | struct imx_port *sport = (struct imx_port *)port; |
269 | unsigned long temp; | 285 | unsigned long temp; |
270 | 286 | ||
287 | if (USE_IRDA(sport)) { | ||
288 | /* half duplex - wait for end of transmission */ | ||
289 | int n = 256; | ||
290 | while ((--n > 0) && | ||
291 | !(readl(sport->port.membase + USR2) & USR2_TXDC)) { | ||
292 | udelay(5); | ||
293 | barrier(); | ||
294 | } | ||
295 | /* | ||
296 | * irda transceiver - wait a bit more to avoid | ||
297 | * cutoff, hardware dependent | ||
298 | */ | ||
299 | udelay(sport->trcv_delay); | ||
300 | |||
301 | /* | ||
302 | * half duplex - reactivate receive mode, | ||
303 | * flush receive pipe echo crap | ||
304 | */ | ||
305 | if (readl(sport->port.membase + USR2) & USR2_TXDC) { | ||
306 | temp = readl(sport->port.membase + UCR1); | ||
307 | temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); | ||
308 | writel(temp, sport->port.membase + UCR1); | ||
309 | |||
310 | temp = readl(sport->port.membase + UCR4); | ||
311 | temp &= ~(UCR4_TCEN); | ||
312 | writel(temp, sport->port.membase + UCR4); | ||
313 | |||
314 | while (readl(sport->port.membase + URXD0) & | ||
315 | URXD_CHARRDY) | ||
316 | barrier(); | ||
317 | |||
318 | temp = readl(sport->port.membase + UCR1); | ||
319 | temp |= UCR1_RRDYEN; | ||
320 | writel(temp, sport->port.membase + UCR1); | ||
321 | |||
322 | temp = readl(sport->port.membase + UCR4); | ||
323 | temp |= UCR4_DREN; | ||
324 | writel(temp, sport->port.membase + UCR4); | ||
325 | } | ||
326 | return; | ||
327 | } | ||
328 | |||
271 | temp = readl(sport->port.membase + UCR1); | 329 | temp = readl(sport->port.membase + UCR1); |
272 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); | 330 | writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); |
273 | } | 331 | } |
@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport) | |||
302 | /* send xmit->buf[xmit->tail] | 360 | /* send xmit->buf[xmit->tail] |
303 | * out the port here */ | 361 | * out the port here */ |
304 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); | 362 | writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); |
305 | xmit->tail = (xmit->tail + 1) & | 363 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
306 | (UART_XMIT_SIZE - 1); | ||
307 | sport->port.icount.tx++; | 364 | sport->port.icount.tx++; |
308 | if (uart_circ_empty(xmit)) | 365 | if (uart_circ_empty(xmit)) |
309 | break; | 366 | break; |
310 | } | 367 | } |
311 | 368 | ||
369 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
370 | uart_write_wakeup(&sport->port); | ||
371 | |||
312 | if (uart_circ_empty(xmit)) | 372 | if (uart_circ_empty(xmit)) |
313 | imx_stop_tx(&sport->port); | 373 | imx_stop_tx(&sport->port); |
314 | } | 374 | } |
@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port) | |||
321 | struct imx_port *sport = (struct imx_port *)port; | 381 | struct imx_port *sport = (struct imx_port *)port; |
322 | unsigned long temp; | 382 | unsigned long temp; |
323 | 383 | ||
384 | if (USE_IRDA(sport)) { | ||
385 | /* half duplex in IrDA mode; have to disable receive mode */ | ||
386 | temp = readl(sport->port.membase + UCR4); | ||
387 | temp &= ~(UCR4_DREN); | ||
388 | writel(temp, sport->port.membase + UCR4); | ||
389 | |||
390 | temp = readl(sport->port.membase + UCR1); | ||
391 | temp &= ~(UCR1_RRDYEN); | ||
392 | writel(temp, sport->port.membase + UCR1); | ||
393 | } | ||
394 | |||
324 | temp = readl(sport->port.membase + UCR1); | 395 | temp = readl(sport->port.membase + UCR1); |
325 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); | 396 | writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); |
326 | 397 | ||
398 | if (USE_IRDA(sport)) { | ||
399 | temp = readl(sport->port.membase + UCR1); | ||
400 | temp |= UCR1_TRDYEN; | ||
401 | writel(temp, sport->port.membase + UCR1); | ||
402 | |||
403 | temp = readl(sport->port.membase + UCR4); | ||
404 | temp |= UCR4_TCEN; | ||
405 | writel(temp, sport->port.membase + UCR4); | ||
406 | } | ||
407 | |||
327 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) | 408 | if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) |
328 | imx_transmit_buffer(sport); | 409 | imx_transmit_buffer(sport); |
329 | } | 410 | } |
@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) | |||
395 | continue; | 476 | continue; |
396 | } | 477 | } |
397 | 478 | ||
398 | if (uart_handle_sysrq_char | 479 | if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) |
399 | (&sport->port, (unsigned char)rx)) | ||
400 | continue; | 480 | continue; |
401 | 481 | ||
402 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { | 482 | if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { |
@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) | |||
471 | */ | 551 | */ |
472 | static unsigned int imx_get_mctrl(struct uart_port *port) | 552 | static unsigned int imx_get_mctrl(struct uart_port *port) |
473 | { | 553 | { |
474 | struct imx_port *sport = (struct imx_port *)port; | 554 | struct imx_port *sport = (struct imx_port *)port; |
475 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; | 555 | unsigned int tmp = TIOCM_DSR | TIOCM_CAR; |
476 | 556 | ||
477 | if (readl(sport->port.membase + USR1) & USR1_RTSS) | 557 | if (readl(sport->port.membase + USR1) & USR1_RTSS) |
478 | tmp |= TIOCM_CTS; | 558 | tmp |= TIOCM_CTS; |
479 | 559 | ||
480 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) | 560 | if (readl(sport->port.membase + UCR2) & UCR2_CTS) |
481 | tmp |= TIOCM_RTS; | 561 | tmp |= TIOCM_RTS; |
482 | 562 | ||
483 | return tmp; | 563 | return tmp; |
484 | } | 564 | } |
485 | 565 | ||
486 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) | 566 | static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) |
487 | { | 567 | { |
488 | struct imx_port *sport = (struct imx_port *)port; | 568 | struct imx_port *sport = (struct imx_port *)port; |
489 | unsigned long temp; | 569 | unsigned long temp; |
490 | 570 | ||
491 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; | 571 | temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; |
492 | 572 | ||
493 | if (mctrl & TIOCM_RTS) | 573 | if (mctrl & TIOCM_RTS) |
494 | temp |= UCR2_CTS; | 574 | temp |= UCR2_CTS; |
495 | 575 | ||
496 | writel(temp, sport->port.membase + UCR2); | 576 | writel(temp, sport->port.membase + UCR2); |
@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) | |||
534 | if(!ufcr_rfdiv) | 614 | if(!ufcr_rfdiv) |
535 | ufcr_rfdiv = 1; | 615 | ufcr_rfdiv = 1; |
536 | 616 | ||
537 | if(ufcr_rfdiv >= 7) | 617 | val |= UFCR_RFDIV_REG(ufcr_rfdiv); |
538 | ufcr_rfdiv = 6; | ||
539 | else | ||
540 | ufcr_rfdiv = 6 - ufcr_rfdiv; | ||
541 | |||
542 | val |= UFCR_RFDIV & (ufcr_rfdiv << 7); | ||
543 | 618 | ||
544 | writel(val, sport->port.membase + UFCR); | 619 | writel(val, sport->port.membase + UFCR); |
545 | 620 | ||
@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port) | |||
558 | * requesting IRQs | 633 | * requesting IRQs |
559 | */ | 634 | */ |
560 | temp = readl(sport->port.membase + UCR4); | 635 | temp = readl(sport->port.membase + UCR4); |
636 | |||
637 | if (USE_IRDA(sport)) | ||
638 | temp |= UCR4_IRSC; | ||
639 | |||
561 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); | 640 | writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); |
562 | 641 | ||
642 | if (USE_IRDA(sport)) { | ||
643 | /* reset fifo's and state machines */ | ||
644 | int i = 100; | ||
645 | temp = readl(sport->port.membase + UCR2); | ||
646 | temp &= ~UCR2_SRST; | ||
647 | writel(temp, sport->port.membase + UCR2); | ||
648 | while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && | ||
649 | (--i > 0)) { | ||
650 | udelay(1); | ||
651 | } | ||
652 | } | ||
653 | |||
563 | /* | 654 | /* |
564 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later | 655 | * Allocate the IRQ(s) i.MX1 has three interrupts whereas later |
565 | * chips only have one interrupt. | 656 | * chips only have one interrupt. |
@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port) | |||
575 | if (retval) | 666 | if (retval) |
576 | goto error_out2; | 667 | goto error_out2; |
577 | 668 | ||
578 | retval = request_irq(sport->rtsirq, imx_rtsint, | 669 | /* do not use RTS IRQ on IrDA */ |
579 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : | 670 | if (!USE_IRDA(sport)) { |
580 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 671 | retval = request_irq(sport->rtsirq, imx_rtsint, |
581 | DRIVER_NAME, sport); | 672 | (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : |
582 | if (retval) | 673 | IRQF_TRIGGER_FALLING | |
583 | goto error_out3; | 674 | IRQF_TRIGGER_RISING, |
675 | DRIVER_NAME, sport); | ||
676 | if (retval) | ||
677 | goto error_out3; | ||
678 | } | ||
584 | } else { | 679 | } else { |
585 | retval = request_irq(sport->port.irq, imx_int, 0, | 680 | retval = request_irq(sport->port.irq, imx_int, 0, |
586 | DRIVER_NAME, sport); | 681 | DRIVER_NAME, sport); |
@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port) | |||
597 | 692 | ||
598 | temp = readl(sport->port.membase + UCR1); | 693 | temp = readl(sport->port.membase + UCR1); |
599 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; | 694 | temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; |
695 | |||
696 | if (USE_IRDA(sport)) { | ||
697 | temp |= UCR1_IREN; | ||
698 | temp &= ~(UCR1_RTSDEN); | ||
699 | } | ||
700 | |||
600 | writel(temp, sport->port.membase + UCR1); | 701 | writel(temp, sport->port.membase + UCR1); |
601 | 702 | ||
602 | temp = readl(sport->port.membase + UCR2); | 703 | temp = readl(sport->port.membase + UCR2); |
603 | temp |= (UCR2_RXEN | UCR2_TXEN); | 704 | temp |= (UCR2_RXEN | UCR2_TXEN); |
604 | writel(temp, sport->port.membase + UCR2); | 705 | writel(temp, sport->port.membase + UCR2); |
605 | 706 | ||
707 | if (USE_IRDA(sport)) { | ||
708 | /* clear RX-FIFO */ | ||
709 | int i = 64; | ||
710 | while ((--i > 0) && | ||
711 | (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { | ||
712 | barrier(); | ||
713 | } | ||
714 | } | ||
715 | |||
606 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 | 716 | #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 |
607 | temp = readl(sport->port.membase + UCR3); | 717 | temp = readl(sport->port.membase + UCR3); |
608 | temp |= UCR3_RXDMUXSEL; | 718 | temp |= UCR3_RXDMUXSEL; |
609 | writel(temp, sport->port.membase + UCR3); | 719 | writel(temp, sport->port.membase + UCR3); |
610 | #endif | 720 | #endif |
611 | 721 | ||
722 | if (USE_IRDA(sport)) { | ||
723 | temp = readl(sport->port.membase + UCR4); | ||
724 | if (sport->irda_inv_rx) | ||
725 | temp |= UCR4_INVR; | ||
726 | else | ||
727 | temp &= ~(UCR4_INVR); | ||
728 | writel(temp | UCR4_DREN, sport->port.membase + UCR4); | ||
729 | |||
730 | temp = readl(sport->port.membase + UCR3); | ||
731 | if (sport->irda_inv_tx) | ||
732 | temp |= UCR3_INVT; | ||
733 | else | ||
734 | temp &= ~(UCR3_INVT); | ||
735 | writel(temp, sport->port.membase + UCR3); | ||
736 | } | ||
737 | |||
612 | /* | 738 | /* |
613 | * Enable modem status interrupts | 739 | * Enable modem status interrupts |
614 | */ | 740 | */ |
@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port) | |||
616 | imx_enable_ms(&sport->port); | 742 | imx_enable_ms(&sport->port); |
617 | spin_unlock_irqrestore(&sport->port.lock,flags); | 743 | spin_unlock_irqrestore(&sport->port.lock,flags); |
618 | 744 | ||
745 | if (USE_IRDA(sport)) { | ||
746 | struct imxuart_platform_data *pdata; | ||
747 | pdata = sport->port.dev->platform_data; | ||
748 | sport->irda_inv_rx = pdata->irda_inv_rx; | ||
749 | sport->irda_inv_tx = pdata->irda_inv_tx; | ||
750 | sport->trcv_delay = pdata->transceiver_delay; | ||
751 | if (pdata->irda_enable) | ||
752 | pdata->irda_enable(1); | ||
753 | } | ||
754 | |||
619 | return 0; | 755 | return 0; |
620 | 756 | ||
621 | error_out3: | 757 | error_out3: |
@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port) | |||
633 | struct imx_port *sport = (struct imx_port *)port; | 769 | struct imx_port *sport = (struct imx_port *)port; |
634 | unsigned long temp; | 770 | unsigned long temp; |
635 | 771 | ||
772 | temp = readl(sport->port.membase + UCR2); | ||
773 | temp &= ~(UCR2_TXEN); | ||
774 | writel(temp, sport->port.membase + UCR2); | ||
775 | |||
776 | if (USE_IRDA(sport)) { | ||
777 | struct imxuart_platform_data *pdata; | ||
778 | pdata = sport->port.dev->platform_data; | ||
779 | if (pdata->irda_enable) | ||
780 | pdata->irda_enable(0); | ||
781 | } | ||
782 | |||
636 | /* | 783 | /* |
637 | * Stop our timer. | 784 | * Stop our timer. |
638 | */ | 785 | */ |
@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port) | |||
642 | * Free the interrupts | 789 | * Free the interrupts |
643 | */ | 790 | */ |
644 | if (sport->txirq > 0) { | 791 | if (sport->txirq > 0) { |
645 | free_irq(sport->rtsirq, sport); | 792 | if (!USE_IRDA(sport)) |
793 | free_irq(sport->rtsirq, sport); | ||
646 | free_irq(sport->txirq, sport); | 794 | free_irq(sport->txirq, sport); |
647 | free_irq(sport->rxirq, sport); | 795 | free_irq(sport->rxirq, sport); |
648 | } else | 796 | } else |
@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port) | |||
654 | 802 | ||
655 | temp = readl(sport->port.membase + UCR1); | 803 | temp = readl(sport->port.membase + UCR1); |
656 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); | 804 | temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); |
805 | if (USE_IRDA(sport)) | ||
806 | temp &= ~(UCR1_IREN); | ||
807 | |||
657 | writel(temp, sport->port.membase + UCR1); | 808 | writel(temp, sport->port.membase + UCR1); |
658 | } | 809 | } |
659 | 810 | ||
@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
665 | unsigned long flags; | 816 | unsigned long flags; |
666 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; | 817 | unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; |
667 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; | 818 | unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; |
668 | unsigned int div, num, denom, ufcr; | 819 | unsigned int div, ufcr; |
820 | unsigned long num, denom; | ||
821 | uint64_t tdiv64; | ||
669 | 822 | ||
670 | /* | 823 | /* |
671 | * If we don't support modem control lines, don't allow | 824 | * If we don't support modem control lines, don't allow |
@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, | |||
761 | sport->port.membase + UCR2); | 914 | sport->port.membase + UCR2); |
762 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); | 915 | old_txrxen &= (UCR2_TXEN | UCR2_RXEN); |
763 | 916 | ||
764 | div = sport->port.uartclk / (baud * 16); | 917 | if (USE_IRDA(sport)) { |
765 | if (div > 7) | 918 | /* |
766 | div = 7; | 919 | * use maximum available submodule frequency to |
767 | if (!div) | 920 | * avoid missing short pulses due to low sampling rate |
921 | */ | ||
768 | div = 1; | 922 | div = 1; |
769 | 923 | } else { | |
770 | num = baud; | 924 | div = sport->port.uartclk / (baud * 16); |
771 | denom = port->uartclk / div / 16; | 925 | if (div > 7) |
772 | 926 | div = 7; | |
773 | /* shift num and denom right until they fit into 16 bits */ | 927 | if (!div) |
774 | while (num > 0x10000 || denom > 0x10000) { | 928 | div = 1; |
775 | num >>= 1; | ||
776 | denom >>= 1; | ||
777 | } | 929 | } |
778 | if (num > 0) | ||
779 | num -= 1; | ||
780 | if (denom > 0) | ||
781 | denom -= 1; | ||
782 | 930 | ||
783 | writel(num, sport->port.membase + UBIR); | 931 | rational_best_approximation(16 * div * baud, sport->port.uartclk, |
784 | writel(denom, sport->port.membase + UBMR); | 932 | 1 << 16, 1 << 16, &num, &denom); |
785 | 933 | ||
786 | if (div == 7) | 934 | tdiv64 = sport->port.uartclk; |
787 | div = 6; /* 6 in RFDIV means divide by 7 */ | 935 | tdiv64 *= num; |
788 | else | 936 | do_div(tdiv64, denom * 16 * div); |
789 | div = 6 - div; | 937 | tty_encode_baud_rate(sport->port.info->port.tty, |
938 | (speed_t)tdiv64, (speed_t)tdiv64); | ||
939 | |||
940 | num -= 1; | ||
941 | denom -= 1; | ||
790 | 942 | ||
791 | ufcr = readl(sport->port.membase + UFCR); | 943 | ufcr = readl(sport->port.membase + UFCR); |
792 | ufcr = (ufcr & (~UFCR_RFDIV)) | | 944 | ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); |
793 | (div << 7); | ||
794 | writel(ufcr, sport->port.membase + UFCR); | 945 | writel(ufcr, sport->port.membase + UFCR); |
795 | 946 | ||
947 | writel(num, sport->port.membase + UBIR); | ||
948 | writel(denom, sport->port.membase + UBMR); | ||
949 | |||
796 | #ifdef ONEMS | 950 | #ifdef ONEMS |
797 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); | 951 | writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); |
798 | #endif | 952 | #endif |
@@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = { | |||
1072 | 1226 | ||
1073 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) | 1227 | static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) |
1074 | { | 1228 | { |
1075 | struct imx_port *sport = platform_get_drvdata(dev); | 1229 | struct imx_port *sport = platform_get_drvdata(dev); |
1076 | 1230 | ||
1077 | if (sport) | 1231 | if (sport) |
1078 | uart_suspend_port(&imx_reg, &sport->port); | 1232 | uart_suspend_port(&imx_reg, &sport->port); |
1079 | 1233 | ||
1080 | return 0; | 1234 | return 0; |
1081 | } | 1235 | } |
1082 | 1236 | ||
1083 | static int serial_imx_resume(struct platform_device *dev) | 1237 | static int serial_imx_resume(struct platform_device *dev) |
1084 | { | 1238 | { |
1085 | struct imx_port *sport = platform_get_drvdata(dev); | 1239 | struct imx_port *sport = platform_get_drvdata(dev); |
1086 | 1240 | ||
1087 | if (sport) | 1241 | if (sport) |
1088 | uart_resume_port(&imx_reg, &sport->port); | 1242 | uart_resume_port(&imx_reg, &sport->port); |
1089 | 1243 | ||
1090 | return 0; | 1244 | return 0; |
1091 | } | 1245 | } |
1092 | 1246 | ||
1093 | static int serial_imx_probe(struct platform_device *pdev) | 1247 | static int serial_imx_probe(struct platform_device *pdev) |
@@ -1143,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev) | |||
1143 | imx_ports[pdev->id] = sport; | 1297 | imx_ports[pdev->id] = sport; |
1144 | 1298 | ||
1145 | pdata = pdev->dev.platform_data; | 1299 | pdata = pdev->dev.platform_data; |
1146 | if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) | 1300 | if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) |
1147 | sport->have_rtscts = 1; | 1301 | sport->have_rtscts = 1; |
1148 | 1302 | ||
1303 | #ifdef CONFIG_IRDA | ||
1304 | if (pdata && (pdata->flags & IMXUART_IRDA)) | ||
1305 | sport->use_irda = 1; | ||
1306 | #endif | ||
1307 | |||
1149 | if (pdata->init) { | 1308 | if (pdata->init) { |
1150 | ret = pdata->init(pdev); | 1309 | ret = pdata->init(pdev); |
1151 | if (ret) | 1310 | if (ret) |
1152 | goto clkput; | 1311 | goto clkput; |
1153 | } | 1312 | } |
1154 | 1313 | ||
1155 | uart_add_one_port(&imx_reg, &sport->port); | 1314 | ret = uart_add_one_port(&imx_reg, &sport->port); |
1315 | if (ret) | ||
1316 | goto deinit; | ||
1156 | platform_set_drvdata(pdev, &sport->port); | 1317 | platform_set_drvdata(pdev, &sport->port); |
1157 | 1318 | ||
1158 | return 0; | 1319 | return 0; |
1320 | deinit: | ||
1321 | if (pdata->exit) | ||
1322 | pdata->exit(pdev); | ||
1159 | clkput: | 1323 | clkput: |
1160 | clk_put(sport->clk); | 1324 | clk_put(sport->clk); |
1161 | clk_disable(sport->clk); | 1325 | clk_disable(sport->clk); |
@@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev) | |||
1193 | } | 1357 | } |
1194 | 1358 | ||
1195 | static struct platform_driver serial_imx_driver = { | 1359 | static struct platform_driver serial_imx_driver = { |
1196 | .probe = serial_imx_probe, | 1360 | .probe = serial_imx_probe, |
1197 | .remove = serial_imx_remove, | 1361 | .remove = serial_imx_remove, |
1198 | 1362 | ||
1199 | .suspend = serial_imx_suspend, | 1363 | .suspend = serial_imx_suspend, |
1200 | .resume = serial_imx_resume, | 1364 | .resume = serial_imx_resume, |
1201 | .driver = { | 1365 | .driver = { |
1202 | .name = "imx-uart", | 1366 | .name = "imx-uart", |
1203 | .owner = THIS_MODULE, | 1367 | .owner = THIS_MODULE, |
1204 | }, | 1368 | }, |
1205 | }; | 1369 | }; |
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index c0a3e2734e24..4e5f3bde0461 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h | |||
@@ -61,6 +61,7 @@ enum { | |||
61 | if ((DBG_##nlevel & jsm_debug)) \ | 61 | if ((DBG_##nlevel & jsm_debug)) \ |
62 | dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) | 62 | dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) |
63 | 63 | ||
64 | #define MAXLINES 256 | ||
64 | #define MAXPORTS 8 | 65 | #define MAXPORTS 8 |
65 | #define MAX_STOPS_SENT 5 | 66 | #define MAX_STOPS_SENT 5 |
66 | 67 | ||
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 31496dc0a0d1..107ce2e187b8 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c | |||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | #include "jsm.h" | 34 | #include "jsm.h" |
35 | 35 | ||
36 | static DECLARE_BITMAP(linemap, MAXLINES); | ||
37 | |||
36 | static void jsm_carrier(struct jsm_channel *ch); | 38 | static void jsm_carrier(struct jsm_channel *ch); |
37 | 39 | ||
38 | static inline int jsm_get_mstat(struct jsm_channel *ch) | 40 | static inline int jsm_get_mstat(struct jsm_channel *ch) |
@@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) | |||
433 | int __devinit jsm_uart_port_init(struct jsm_board *brd) | 435 | int __devinit jsm_uart_port_init(struct jsm_board *brd) |
434 | { | 436 | { |
435 | int i; | 437 | int i; |
438 | unsigned int line; | ||
436 | struct jsm_channel *ch; | 439 | struct jsm_channel *ch; |
437 | 440 | ||
438 | if (!brd) | 441 | if (!brd) |
@@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd) | |||
459 | brd->channels[i]->uart_port.membase = brd->re_map_membase; | 462 | brd->channels[i]->uart_port.membase = brd->re_map_membase; |
460 | brd->channels[i]->uart_port.fifosize = 16; | 463 | brd->channels[i]->uart_port.fifosize = 16; |
461 | brd->channels[i]->uart_port.ops = &jsm_ops; | 464 | brd->channels[i]->uart_port.ops = &jsm_ops; |
462 | brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; | 465 | line = find_first_zero_bit(linemap, MAXLINES); |
466 | if (line >= MAXLINES) { | ||
467 | printk(KERN_INFO "jsm: linemap is full, added device failed\n"); | ||
468 | continue; | ||
469 | } else | ||
470 | set_bit((int)line, linemap); | ||
471 | brd->channels[i]->uart_port.line = line; | ||
463 | if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) | 472 | if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) |
464 | printk(KERN_INFO "Added device failed\n"); | 473 | printk(KERN_INFO "jsm: add device failed\n"); |
465 | else | 474 | else |
466 | printk(KERN_INFO "Added device \n"); | 475 | printk(KERN_INFO "Added device \n"); |
467 | } | 476 | } |
@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) | |||
494 | 503 | ||
495 | ch = brd->channels[i]; | 504 | ch = brd->channels[i]; |
496 | 505 | ||
506 | clear_bit((int)(ch->uart_port.line), linemap); | ||
497 | uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); | 507 | uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); |
498 | } | 508 | } |
499 | 509 | ||
diff --git a/drivers/serial/timbuart.c b/drivers/serial/timbuart.c new file mode 100644 index 000000000000..ac9e5d5f742e --- /dev/null +++ b/drivers/serial/timbuart.c | |||
@@ -0,0 +1,526 @@ | |||
1 | /* | ||
2 | * timbuart.c timberdale FPGA UART driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA UART | ||
21 | */ | ||
22 | |||
23 | #include <linux/pci.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/serial_core.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/ioport.h> | ||
29 | |||
30 | #include "timbuart.h" | ||
31 | |||
32 | struct timbuart_port { | ||
33 | struct uart_port port; | ||
34 | struct tasklet_struct tasklet; | ||
35 | int usedma; | ||
36 | u8 last_ier; | ||
37 | struct platform_device *dev; | ||
38 | }; | ||
39 | |||
40 | static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800, | ||
41 | 921600, 1843200, 3250000}; | ||
42 | |||
43 | static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier); | ||
44 | |||
45 | static irqreturn_t timbuart_handleinterrupt(int irq, void *devid); | ||
46 | |||
47 | static void timbuart_stop_rx(struct uart_port *port) | ||
48 | { | ||
49 | /* spin lock held by upper layer, disable all RX interrupts */ | ||
50 | u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS; | ||
51 | iowrite8(ier, port->membase + TIMBUART_IER); | ||
52 | } | ||
53 | |||
54 | static void timbuart_stop_tx(struct uart_port *port) | ||
55 | { | ||
56 | /* spinlock held by upper layer, disable TX interrupt */ | ||
57 | u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE; | ||
58 | iowrite8(ier, port->membase + TIMBUART_IER); | ||
59 | } | ||
60 | |||
61 | static void timbuart_start_tx(struct uart_port *port) | ||
62 | { | ||
63 | struct timbuart_port *uart = | ||
64 | container_of(port, struct timbuart_port, port); | ||
65 | |||
66 | /* do not transfer anything here -> fire off the tasklet */ | ||
67 | tasklet_schedule(&uart->tasklet); | ||
68 | } | ||
69 | |||
70 | static void timbuart_flush_buffer(struct uart_port *port) | ||
71 | { | ||
72 | u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX; | ||
73 | |||
74 | iowrite8(ctl, port->membase + TIMBUART_CTRL); | ||
75 | iowrite8(TXBF, port->membase + TIMBUART_ISR); | ||
76 | } | ||
77 | |||
78 | static void timbuart_rx_chars(struct uart_port *port) | ||
79 | { | ||
80 | struct tty_struct *tty = port->info->port.tty; | ||
81 | |||
82 | while (ioread8(port->membase + TIMBUART_ISR) & RXDP) { | ||
83 | u8 ch = ioread8(port->membase + TIMBUART_RXFIFO); | ||
84 | port->icount.rx++; | ||
85 | tty_insert_flip_char(tty, ch, TTY_NORMAL); | ||
86 | } | ||
87 | |||
88 | spin_unlock(&port->lock); | ||
89 | tty_flip_buffer_push(port->info->port.tty); | ||
90 | spin_lock(&port->lock); | ||
91 | |||
92 | dev_dbg(port->dev, "%s - total read %d bytes\n", | ||
93 | __func__, port->icount.rx); | ||
94 | } | ||
95 | |||
96 | static void timbuart_tx_chars(struct uart_port *port) | ||
97 | { | ||
98 | struct circ_buf *xmit = &port->info->xmit; | ||
99 | |||
100 | while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) && | ||
101 | !uart_circ_empty(xmit)) { | ||
102 | iowrite8(xmit->buf[xmit->tail], | ||
103 | port->membase + TIMBUART_TXFIFO); | ||
104 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
105 | port->icount.tx++; | ||
106 | } | ||
107 | |||
108 | dev_dbg(port->dev, | ||
109 | "%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n", | ||
110 | __func__, | ||
111 | port->icount.tx, | ||
112 | ioread8(port->membase + TIMBUART_CTRL), | ||
113 | port->mctrl & TIOCM_RTS, | ||
114 | ioread8(port->membase + TIMBUART_BAUDRATE)); | ||
115 | } | ||
116 | |||
117 | static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier) | ||
118 | { | ||
119 | struct timbuart_port *uart = | ||
120 | container_of(port, struct timbuart_port, port); | ||
121 | struct circ_buf *xmit = &port->info->xmit; | ||
122 | |||
123 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | ||
124 | return; | ||
125 | |||
126 | if (port->x_char) | ||
127 | return; | ||
128 | |||
129 | if (isr & TXFLAGS) { | ||
130 | timbuart_tx_chars(port); | ||
131 | /* clear all TX interrupts */ | ||
132 | iowrite8(TXFLAGS, port->membase + TIMBUART_ISR); | ||
133 | |||
134 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
135 | uart_write_wakeup(port); | ||
136 | } else | ||
137 | /* Re-enable any tx interrupt */ | ||
138 | *ier |= uart->last_ier & TXFLAGS; | ||
139 | |||
140 | /* enable interrupts if there are chars in the transmit buffer, | ||
141 | * Or if we delivered some bytes and want the almost empty interrupt | ||
142 | * we wake up the upper layer later when we got the interrupt | ||
143 | * to give it some time to go out... | ||
144 | */ | ||
145 | if (!uart_circ_empty(xmit)) | ||
146 | *ier |= TXBAE; | ||
147 | |||
148 | dev_dbg(port->dev, "%s - leaving\n", __func__); | ||
149 | } | ||
150 | |||
151 | void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier) | ||
152 | { | ||
153 | if (isr & RXFLAGS) { | ||
154 | /* Some RX status is set */ | ||
155 | if (isr & RXBF) { | ||
156 | u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | | ||
157 | TIMBUART_CTRL_FLSHRX; | ||
158 | iowrite8(ctl, port->membase + TIMBUART_CTRL); | ||
159 | port->icount.overrun++; | ||
160 | } else if (isr & (RXDP)) | ||
161 | timbuart_rx_chars(port); | ||
162 | |||
163 | /* ack all RX interrupts */ | ||
164 | iowrite8(RXFLAGS, port->membase + TIMBUART_ISR); | ||
165 | } | ||
166 | |||
167 | /* always have the RX interrupts enabled */ | ||
168 | *ier |= RXBAF | RXBF | RXTT; | ||
169 | |||
170 | dev_dbg(port->dev, "%s - leaving\n", __func__); | ||
171 | } | ||
172 | |||
173 | void timbuart_tasklet(unsigned long arg) | ||
174 | { | ||
175 | struct timbuart_port *uart = (struct timbuart_port *)arg; | ||
176 | u8 isr, ier = 0; | ||
177 | |||
178 | spin_lock(&uart->port.lock); | ||
179 | |||
180 | isr = ioread8(uart->port.membase + TIMBUART_ISR); | ||
181 | dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr); | ||
182 | |||
183 | if (!uart->usedma) | ||
184 | timbuart_handle_tx_port(&uart->port, isr, &ier); | ||
185 | |||
186 | timbuart_mctrl_check(&uart->port, isr, &ier); | ||
187 | |||
188 | if (!uart->usedma) | ||
189 | timbuart_handle_rx_port(&uart->port, isr, &ier); | ||
190 | |||
191 | iowrite8(ier, uart->port.membase + TIMBUART_IER); | ||
192 | |||
193 | spin_unlock(&uart->port.lock); | ||
194 | dev_dbg(uart->port.dev, "%s leaving\n", __func__); | ||
195 | } | ||
196 | |||
197 | static unsigned int timbuart_tx_empty(struct uart_port *port) | ||
198 | { | ||
199 | u8 isr = ioread8(port->membase + TIMBUART_ISR); | ||
200 | |||
201 | return (isr & TXBAE) ? TIOCSER_TEMT : 0; | ||
202 | } | ||
203 | |||
204 | static unsigned int timbuart_get_mctrl(struct uart_port *port) | ||
205 | { | ||
206 | u8 cts = ioread8(port->membase + TIMBUART_CTRL); | ||
207 | dev_dbg(port->dev, "%s - cts %x\n", __func__, cts); | ||
208 | |||
209 | if (cts & TIMBUART_CTRL_CTS) | ||
210 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; | ||
211 | else | ||
212 | return TIOCM_DSR | TIOCM_CAR; | ||
213 | } | ||
214 | |||
215 | static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl) | ||
216 | { | ||
217 | dev_dbg(port->dev, "%s - %x\n", __func__, mctrl); | ||
218 | |||
219 | if (mctrl & TIOCM_RTS) | ||
220 | iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); | ||
221 | else | ||
222 | iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL); | ||
223 | } | ||
224 | |||
225 | static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier) | ||
226 | { | ||
227 | unsigned int cts; | ||
228 | |||
229 | if (isr & CTS_DELTA) { | ||
230 | /* ack */ | ||
231 | iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR); | ||
232 | cts = timbuart_get_mctrl(port); | ||
233 | uart_handle_cts_change(port, cts & TIOCM_CTS); | ||
234 | wake_up_interruptible(&port->info->delta_msr_wait); | ||
235 | } | ||
236 | |||
237 | *ier |= CTS_DELTA; | ||
238 | } | ||
239 | |||
240 | static void timbuart_enable_ms(struct uart_port *port) | ||
241 | { | ||
242 | /* N/A */ | ||
243 | } | ||
244 | |||
245 | static void timbuart_break_ctl(struct uart_port *port, int ctl) | ||
246 | { | ||
247 | /* N/A */ | ||
248 | } | ||
249 | |||
250 | static int timbuart_startup(struct uart_port *port) | ||
251 | { | ||
252 | struct timbuart_port *uart = | ||
253 | container_of(port, struct timbuart_port, port); | ||
254 | |||
255 | dev_dbg(port->dev, "%s\n", __func__); | ||
256 | |||
257 | iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL); | ||
258 | iowrite8(0xff, port->membase + TIMBUART_ISR); | ||
259 | /* Enable all but TX interrupts */ | ||
260 | iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA, | ||
261 | port->membase + TIMBUART_IER); | ||
262 | |||
263 | return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED, | ||
264 | "timb-uart", uart); | ||
265 | } | ||
266 | |||
267 | static void timbuart_shutdown(struct uart_port *port) | ||
268 | { | ||
269 | struct timbuart_port *uart = | ||
270 | container_of(port, struct timbuart_port, port); | ||
271 | dev_dbg(port->dev, "%s\n", __func__); | ||
272 | free_irq(port->irq, uart); | ||
273 | iowrite8(0, port->membase + TIMBUART_IER); | ||
274 | } | ||
275 | |||
276 | static int get_bindex(int baud) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | for (i = 0; i < ARRAY_SIZE(baudrates); i++) | ||
281 | if (baud <= baudrates[i]) | ||
282 | return i; | ||
283 | |||
284 | return -1; | ||
285 | } | ||
286 | |||
287 | static void timbuart_set_termios(struct uart_port *port, | ||
288 | struct ktermios *termios, | ||
289 | struct ktermios *old) | ||
290 | { | ||
291 | unsigned int baud; | ||
292 | short bindex; | ||
293 | unsigned long flags; | ||
294 | |||
295 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | ||
296 | bindex = get_bindex(baud); | ||
297 | dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex); | ||
298 | |||
299 | if (bindex < 0) | ||
300 | bindex = 0; | ||
301 | baud = baudrates[bindex]; | ||
302 | |||
303 | /* The serial layer calls into this once with old = NULL when setting | ||
304 | up initially */ | ||
305 | if (old) | ||
306 | tty_termios_copy_hw(termios, old); | ||
307 | tty_termios_encode_baud_rate(termios, baud, baud); | ||
308 | |||
309 | spin_lock_irqsave(&port->lock, flags); | ||
310 | iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE); | ||
311 | uart_update_timeout(port, termios->c_cflag, baud); | ||
312 | spin_unlock_irqrestore(&port->lock, flags); | ||
313 | } | ||
314 | |||
315 | static const char *timbuart_type(struct uart_port *port) | ||
316 | { | ||
317 | return port->type == PORT_UNKNOWN ? "timbuart" : NULL; | ||
318 | } | ||
319 | |||
320 | /* We do not request/release mappings of the registers here, | ||
321 | * currently it's done in the proble function. | ||
322 | */ | ||
323 | static void timbuart_release_port(struct uart_port *port) | ||
324 | { | ||
325 | struct platform_device *pdev = to_platform_device(port->dev); | ||
326 | int size = | ||
327 | resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
328 | |||
329 | if (port->flags & UPF_IOREMAP) { | ||
330 | iounmap(port->membase); | ||
331 | port->membase = NULL; | ||
332 | } | ||
333 | |||
334 | release_mem_region(port->mapbase, size); | ||
335 | } | ||
336 | |||
337 | static int timbuart_request_port(struct uart_port *port) | ||
338 | { | ||
339 | struct platform_device *pdev = to_platform_device(port->dev); | ||
340 | int size = | ||
341 | resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
342 | |||
343 | if (!request_mem_region(port->mapbase, size, "timb-uart")) | ||
344 | return -EBUSY; | ||
345 | |||
346 | if (port->flags & UPF_IOREMAP) { | ||
347 | port->membase = ioremap(port->mapbase, size); | ||
348 | if (port->membase == NULL) { | ||
349 | release_mem_region(port->mapbase, size); | ||
350 | return -ENOMEM; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static irqreturn_t timbuart_handleinterrupt(int irq, void *devid) | ||
358 | { | ||
359 | struct timbuart_port *uart = (struct timbuart_port *)devid; | ||
360 | |||
361 | if (ioread8(uart->port.membase + TIMBUART_IPR)) { | ||
362 | uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER); | ||
363 | |||
364 | /* disable interrupts, the tasklet enables them again */ | ||
365 | iowrite8(0, uart->port.membase + TIMBUART_IER); | ||
366 | |||
367 | /* fire off bottom half */ | ||
368 | tasklet_schedule(&uart->tasklet); | ||
369 | |||
370 | return IRQ_HANDLED; | ||
371 | } else | ||
372 | return IRQ_NONE; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Configure/autoconfigure the port. | ||
377 | */ | ||
378 | static void timbuart_config_port(struct uart_port *port, int flags) | ||
379 | { | ||
380 | if (flags & UART_CONFIG_TYPE) { | ||
381 | port->type = PORT_TIMBUART; | ||
382 | timbuart_request_port(port); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | static int timbuart_verify_port(struct uart_port *port, | ||
387 | struct serial_struct *ser) | ||
388 | { | ||
389 | /* we don't want the core code to modify any port params */ | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | |||
393 | static struct uart_ops timbuart_ops = { | ||
394 | .tx_empty = timbuart_tx_empty, | ||
395 | .set_mctrl = timbuart_set_mctrl, | ||
396 | .get_mctrl = timbuart_get_mctrl, | ||
397 | .stop_tx = timbuart_stop_tx, | ||
398 | .start_tx = timbuart_start_tx, | ||
399 | .flush_buffer = timbuart_flush_buffer, | ||
400 | .stop_rx = timbuart_stop_rx, | ||
401 | .enable_ms = timbuart_enable_ms, | ||
402 | .break_ctl = timbuart_break_ctl, | ||
403 | .startup = timbuart_startup, | ||
404 | .shutdown = timbuart_shutdown, | ||
405 | .set_termios = timbuart_set_termios, | ||
406 | .type = timbuart_type, | ||
407 | .release_port = timbuart_release_port, | ||
408 | .request_port = timbuart_request_port, | ||
409 | .config_port = timbuart_config_port, | ||
410 | .verify_port = timbuart_verify_port | ||
411 | }; | ||
412 | |||
413 | static struct uart_driver timbuart_driver = { | ||
414 | .owner = THIS_MODULE, | ||
415 | .driver_name = "timberdale_uart", | ||
416 | .dev_name = "ttyTU", | ||
417 | .major = TIMBUART_MAJOR, | ||
418 | .minor = TIMBUART_MINOR, | ||
419 | .nr = 1 | ||
420 | }; | ||
421 | |||
422 | static int timbuart_probe(struct platform_device *dev) | ||
423 | { | ||
424 | int err; | ||
425 | struct timbuart_port *uart; | ||
426 | struct resource *iomem; | ||
427 | |||
428 | dev_dbg(&dev->dev, "%s\n", __func__); | ||
429 | |||
430 | uart = kzalloc(sizeof(*uart), GFP_KERNEL); | ||
431 | if (!uart) { | ||
432 | err = -EINVAL; | ||
433 | goto err_mem; | ||
434 | } | ||
435 | |||
436 | uart->usedma = 0; | ||
437 | |||
438 | uart->port.uartclk = 3250000 * 16; | ||
439 | uart->port.fifosize = TIMBUART_FIFO_SIZE; | ||
440 | uart->port.regshift = 2; | ||
441 | uart->port.iotype = UPIO_MEM; | ||
442 | uart->port.ops = &timbuart_ops; | ||
443 | uart->port.irq = 0; | ||
444 | uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; | ||
445 | uart->port.line = 0; | ||
446 | uart->port.dev = &dev->dev; | ||
447 | |||
448 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
449 | if (!iomem) { | ||
450 | err = -ENOMEM; | ||
451 | goto err_register; | ||
452 | } | ||
453 | uart->port.mapbase = iomem->start; | ||
454 | uart->port.membase = NULL; | ||
455 | |||
456 | uart->port.irq = platform_get_irq(dev, 0); | ||
457 | if (uart->port.irq < 0) { | ||
458 | err = -EINVAL; | ||
459 | goto err_register; | ||
460 | } | ||
461 | |||
462 | tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart); | ||
463 | |||
464 | err = uart_register_driver(&timbuart_driver); | ||
465 | if (err) | ||
466 | goto err_register; | ||
467 | |||
468 | err = uart_add_one_port(&timbuart_driver, &uart->port); | ||
469 | if (err) | ||
470 | goto err_add_port; | ||
471 | |||
472 | platform_set_drvdata(dev, uart); | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | err_add_port: | ||
477 | uart_unregister_driver(&timbuart_driver); | ||
478 | err_register: | ||
479 | kfree(uart); | ||
480 | err_mem: | ||
481 | printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n", | ||
482 | err); | ||
483 | |||
484 | return err; | ||
485 | } | ||
486 | |||
487 | static int timbuart_remove(struct platform_device *dev) | ||
488 | { | ||
489 | struct timbuart_port *uart = platform_get_drvdata(dev); | ||
490 | |||
491 | tasklet_kill(&uart->tasklet); | ||
492 | uart_remove_one_port(&timbuart_driver, &uart->port); | ||
493 | uart_unregister_driver(&timbuart_driver); | ||
494 | kfree(uart); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static struct platform_driver timbuart_platform_driver = { | ||
500 | .driver = { | ||
501 | .name = "timb-uart", | ||
502 | .owner = THIS_MODULE, | ||
503 | }, | ||
504 | .probe = timbuart_probe, | ||
505 | .remove = timbuart_remove, | ||
506 | }; | ||
507 | |||
508 | /*--------------------------------------------------------------------------*/ | ||
509 | |||
510 | static int __init timbuart_init(void) | ||
511 | { | ||
512 | return platform_driver_register(&timbuart_platform_driver); | ||
513 | } | ||
514 | |||
515 | static void __exit timbuart_exit(void) | ||
516 | { | ||
517 | platform_driver_unregister(&timbuart_platform_driver); | ||
518 | } | ||
519 | |||
520 | module_init(timbuart_init); | ||
521 | module_exit(timbuart_exit); | ||
522 | |||
523 | MODULE_DESCRIPTION("Timberdale UART driver"); | ||
524 | MODULE_LICENSE("GPL v2"); | ||
525 | MODULE_ALIAS("platform:timb-uart"); | ||
526 | |||
diff --git a/drivers/serial/timbuart.h b/drivers/serial/timbuart.h new file mode 100644 index 000000000000..7e566766bc43 --- /dev/null +++ b/drivers/serial/timbuart.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * timbuart.c timberdale FPGA GPIO driver | ||
3 | * Copyright (c) 2009 Intel Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA UART | ||
21 | */ | ||
22 | |||
23 | #ifndef _TIMBUART_H | ||
24 | #define _TIMBUART_H | ||
25 | |||
26 | #define TIMBUART_FIFO_SIZE 2048 | ||
27 | |||
28 | #define TIMBUART_RXFIFO 0x08 | ||
29 | #define TIMBUART_TXFIFO 0x0c | ||
30 | #define TIMBUART_IER 0x10 | ||
31 | #define TIMBUART_IPR 0x14 | ||
32 | #define TIMBUART_ISR 0x18 | ||
33 | #define TIMBUART_CTRL 0x1c | ||
34 | #define TIMBUART_BAUDRATE 0x20 | ||
35 | |||
36 | #define TIMBUART_CTRL_RTS 0x01 | ||
37 | #define TIMBUART_CTRL_CTS 0x02 | ||
38 | #define TIMBUART_CTRL_FLSHTX 0x40 | ||
39 | #define TIMBUART_CTRL_FLSHRX 0x80 | ||
40 | |||
41 | #define TXBF 0x01 | ||
42 | #define TXBAE 0x02 | ||
43 | #define CTS_DELTA 0x04 | ||
44 | #define RXDP 0x08 | ||
45 | #define RXBAF 0x10 | ||
46 | #define RXBF 0x20 | ||
47 | #define RXTT 0x40 | ||
48 | #define RXBNAE 0x80 | ||
49 | #define TXBE 0x100 | ||
50 | |||
51 | #define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE) | ||
52 | #define TXFLAGS (TXBF | TXBAE) | ||
53 | |||
54 | #define TIMBUART_MAJOR 204 | ||
55 | #define TIMBUART_MINOR 192 | ||
56 | |||
57 | #endif /* _TIMBUART_H */ | ||
58 | |||