diff options
Diffstat (limited to 'drivers/tty/serial/pch_uart.c')
-rw-r--r-- | drivers/tty/serial/pch_uart.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index c2816f494807..4fdec6a6b758 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c | |||
@@ -39,6 +39,7 @@ enum { | |||
39 | PCH_UART_HANDLED_RX_ERR_INT_SHIFT, | 39 | PCH_UART_HANDLED_RX_ERR_INT_SHIFT, |
40 | PCH_UART_HANDLED_RX_TRG_INT_SHIFT, | 40 | PCH_UART_HANDLED_RX_TRG_INT_SHIFT, |
41 | PCH_UART_HANDLED_MS_INT_SHIFT, | 41 | PCH_UART_HANDLED_MS_INT_SHIFT, |
42 | PCH_UART_HANDLED_LS_INT_SHIFT, | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | enum { | 45 | enum { |
@@ -63,6 +64,8 @@ enum { | |||
63 | PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) | 64 | PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) |
64 | #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) | 65 | #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) |
65 | 66 | ||
67 | #define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) | ||
68 | |||
66 | #define PCH_UART_RBR 0x00 | 69 | #define PCH_UART_RBR 0x00 |
67 | #define PCH_UART_THR 0x00 | 70 | #define PCH_UART_THR 0x00 |
68 | 71 | ||
@@ -229,7 +232,6 @@ struct eg20t_port { | |||
229 | int start_tx; | 232 | int start_tx; |
230 | int start_rx; | 233 | int start_rx; |
231 | int tx_empty; | 234 | int tx_empty; |
232 | int int_dis_flag; | ||
233 | int trigger; | 235 | int trigger; |
234 | int trigger_level; | 236 | int trigger_level; |
235 | struct pch_uart_buffer rxbuf; | 237 | struct pch_uart_buffer rxbuf; |
@@ -237,7 +239,6 @@ struct eg20t_port { | |||
237 | unsigned int fcr; | 239 | unsigned int fcr; |
238 | unsigned int mcr; | 240 | unsigned int mcr; |
239 | unsigned int use_dma; | 241 | unsigned int use_dma; |
240 | unsigned int use_dma_flag; | ||
241 | struct dma_async_tx_descriptor *desc_tx; | 242 | struct dma_async_tx_descriptor *desc_tx; |
242 | struct dma_async_tx_descriptor *desc_rx; | 243 | struct dma_async_tx_descriptor *desc_rx; |
243 | struct pch_dma_slave param_tx; | 244 | struct pch_dma_slave param_tx; |
@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, | |||
560 | return i; | 561 | return i; |
561 | } | 562 | } |
562 | 563 | ||
563 | static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) | 564 | static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv) |
564 | { | 565 | { |
565 | unsigned int iir; | 566 | return ioread8(priv->membase + UART_IIR) &\ |
566 | int ret; | 567 | (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP); |
567 | |||
568 | iir = ioread8(priv->membase + UART_IIR); | ||
569 | ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); | ||
570 | return ret; | ||
571 | } | 568 | } |
572 | 569 | ||
573 | static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) | 570 | static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) |
@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port) | |||
666 | dma_release_channel(priv->chan_rx); | 663 | dma_release_channel(priv->chan_rx); |
667 | priv->chan_rx = NULL; | 664 | priv->chan_rx = NULL; |
668 | } | 665 | } |
669 | if (sg_dma_address(&priv->sg_rx)) | 666 | |
670 | dma_free_coherent(port->dev, port->fifosize, | 667 | if (priv->rx_buf_dma) { |
671 | sg_virt(&priv->sg_rx), | 668 | dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, |
672 | sg_dma_address(&priv->sg_rx)); | 669 | priv->rx_buf_dma); |
670 | priv->rx_buf_virt = NULL; | ||
671 | priv->rx_buf_dma = 0; | ||
672 | } | ||
673 | 673 | ||
674 | return; | 674 | return; |
675 | } | 675 | } |
@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1053 | unsigned int handled; | 1053 | unsigned int handled; |
1054 | u8 lsr; | 1054 | u8 lsr; |
1055 | int ret = 0; | 1055 | int ret = 0; |
1056 | unsigned int iid; | 1056 | unsigned char iid; |
1057 | unsigned long flags; | 1057 | unsigned long flags; |
1058 | int next = 1; | ||
1059 | u8 msr; | ||
1058 | 1060 | ||
1059 | spin_lock_irqsave(&priv->port.lock, flags); | 1061 | spin_lock_irqsave(&priv->port.lock, flags); |
1060 | handled = 0; | 1062 | handled = 0; |
1061 | while ((iid = pch_uart_hal_get_iid(priv)) > 1) { | 1063 | while (next) { |
1064 | iid = pch_uart_hal_get_iid(priv); | ||
1065 | if (iid & PCH_UART_IIR_IP) /* No Interrupt */ | ||
1066 | break; | ||
1062 | switch (iid) { | 1067 | switch (iid) { |
1063 | case PCH_UART_IID_RLS: /* Receiver Line Status */ | 1068 | case PCH_UART_IID_RLS: /* Receiver Line Status */ |
1064 | lsr = pch_uart_hal_get_line_status(priv); | 1069 | lsr = pch_uart_hal_get_line_status(priv); |
@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1066 | UART_LSR_PE | UART_LSR_OE)) { | 1071 | UART_LSR_PE | UART_LSR_OE)) { |
1067 | pch_uart_err_ir(priv, lsr); | 1072 | pch_uart_err_ir(priv, lsr); |
1068 | ret = PCH_UART_HANDLED_RX_ERR_INT; | 1073 | ret = PCH_UART_HANDLED_RX_ERR_INT; |
1074 | } else { | ||
1075 | ret = PCH_UART_HANDLED_LS_INT; | ||
1069 | } | 1076 | } |
1070 | break; | 1077 | break; |
1071 | case PCH_UART_IID_RDR: /* Received Data Ready */ | 1078 | case PCH_UART_IID_RDR: /* Received Data Ready */ |
@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
1092 | ret = handle_tx(priv); | 1099 | ret = handle_tx(priv); |
1093 | break; | 1100 | break; |
1094 | case PCH_UART_IID_MS: /* Modem Status */ | 1101 | case PCH_UART_IID_MS: /* Modem Status */ |
1095 | ret = PCH_UART_HANDLED_MS_INT; | 1102 | msr = pch_uart_hal_get_modem(priv); |
1103 | next = 0; /* MS ir prioirty is the lowest. So, MS ir | ||
1104 | means final interrupt */ | ||
1105 | if ((msr & UART_MSR_ANY_DELTA) == 0) | ||
1106 | break; | ||
1107 | ret |= PCH_UART_HANDLED_MS_INT; | ||
1096 | break; | 1108 | break; |
1097 | default: /* Never junp to this label */ | 1109 | default: /* Never junp to this label */ |
1098 | dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, | 1110 | dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__, |
1099 | iid, jiffies); | 1111 | iid, jiffies); |
1100 | ret = -1; | 1112 | ret = -1; |
1113 | next = 0; | ||
1101 | break; | 1114 | break; |
1102 | } | 1115 | } |
1103 | handled |= (unsigned int)ret; | 1116 | handled |= (unsigned int)ret; |
1104 | } | 1117 | } |
1105 | if (handled == 0 && iid <= 1) { | ||
1106 | if (priv->int_dis_flag) | ||
1107 | priv->int_dis_flag = 0; | ||
1108 | } | ||
1109 | 1118 | ||
1110 | spin_unlock_irqrestore(&priv->port.lock, flags); | 1119 | spin_unlock_irqrestore(&priv->port.lock, flags); |
1111 | return IRQ_RETVAL(handled); | 1120 | return IRQ_RETVAL(handled); |
@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port) | |||
1200 | priv = container_of(port, struct eg20t_port, port); | 1209 | priv = container_of(port, struct eg20t_port, port); |
1201 | priv->start_rx = 0; | 1210 | priv->start_rx = 0; |
1202 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); | 1211 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); |
1203 | priv->int_dis_flag = 1; | ||
1204 | } | 1212 | } |
1205 | 1213 | ||
1206 | /* Enable the modem status interrupts. */ | 1214 | /* Enable the modem status interrupts. */ |
@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port, | |||
1447 | __func__); | 1455 | __func__); |
1448 | return -EOPNOTSUPP; | 1456 | return -EOPNOTSUPP; |
1449 | #endif | 1457 | #endif |
1450 | priv->use_dma_flag = 1; | ||
1451 | dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); | 1458 | dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); |
1452 | if (!priv->use_dma) | 1459 | if (!priv->use_dma) |
1453 | pch_request_dma(port); | 1460 | pch_request_dma(port); |