diff options
Diffstat (limited to 'drivers/tty/serial/omap-serial.c')
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 141 |
1 files changed, 97 insertions, 44 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 816d1a23f9d0..fa511ebab67c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/irq.h> | 39 | #include <linux/irq.h> |
40 | #include <linux/pm_runtime.h> | 40 | #include <linux/pm_runtime.h> |
41 | #include <linux/of.h> | 41 | #include <linux/of.h> |
42 | #include <linux/of_irq.h> | ||
42 | #include <linux/gpio.h> | 43 | #include <linux/gpio.h> |
43 | #include <linux/of_gpio.h> | 44 | #include <linux/of_gpio.h> |
44 | #include <linux/platform_data/serial-omap.h> | 45 | #include <linux/platform_data/serial-omap.h> |
@@ -134,6 +135,7 @@ struct uart_omap_port { | |||
134 | struct uart_port port; | 135 | struct uart_port port; |
135 | struct uart_omap_dma uart_dma; | 136 | struct uart_omap_dma uart_dma; |
136 | struct device *dev; | 137 | struct device *dev; |
138 | int wakeirq; | ||
137 | 139 | ||
138 | unsigned char ier; | 140 | unsigned char ier; |
139 | unsigned char lcr; | 141 | unsigned char lcr; |
@@ -175,7 +177,7 @@ struct uart_omap_port { | |||
175 | bool is_suspending; | 177 | bool is_suspending; |
176 | }; | 178 | }; |
177 | 179 | ||
178 | #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) | 180 | #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) |
179 | 181 | ||
180 | static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; | 182 | static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; |
181 | 183 | ||
@@ -214,10 +216,23 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) | |||
214 | return pdata->get_context_loss_count(up->dev); | 216 | return pdata->get_context_loss_count(up->dev); |
215 | } | 217 | } |
216 | 218 | ||
219 | static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, | ||
220 | bool enable) | ||
221 | { | ||
222 | if (!up->wakeirq) | ||
223 | return; | ||
224 | |||
225 | if (enable) | ||
226 | enable_irq(up->wakeirq); | ||
227 | else | ||
228 | disable_irq(up->wakeirq); | ||
229 | } | ||
230 | |||
217 | static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) | 231 | static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) |
218 | { | 232 | { |
219 | struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); | 233 | struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); |
220 | 234 | ||
235 | serial_omap_enable_wakeirq(up, enable); | ||
221 | if (!pdata || !pdata->enable_wakeup) | 236 | if (!pdata || !pdata->enable_wakeup) |
222 | return; | 237 | return; |
223 | 238 | ||
@@ -242,12 +257,12 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) | |||
242 | unsigned int n16 = port->uartclk / (16 * baud); | 257 | unsigned int n16 = port->uartclk / (16 * baud); |
243 | int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); | 258 | int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); |
244 | int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); | 259 | int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); |
245 | if(baudAbsDiff13 < 0) | 260 | if (baudAbsDiff13 < 0) |
246 | baudAbsDiff13 = -baudAbsDiff13; | 261 | baudAbsDiff13 = -baudAbsDiff13; |
247 | if(baudAbsDiff16 < 0) | 262 | if (baudAbsDiff16 < 0) |
248 | baudAbsDiff16 = -baudAbsDiff16; | 263 | baudAbsDiff16 = -baudAbsDiff16; |
249 | 264 | ||
250 | return (baudAbsDiff13 > baudAbsDiff16); | 265 | return (baudAbsDiff13 >= baudAbsDiff16); |
251 | } | 266 | } |
252 | 267 | ||
253 | /* | 268 | /* |
@@ -258,13 +273,13 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) | |||
258 | static unsigned int | 273 | static unsigned int |
259 | serial_omap_get_divisor(struct uart_port *port, unsigned int baud) | 274 | serial_omap_get_divisor(struct uart_port *port, unsigned int baud) |
260 | { | 275 | { |
261 | unsigned int divisor; | 276 | unsigned int mode; |
262 | 277 | ||
263 | if (!serial_omap_baud_is_mode16(port, baud)) | 278 | if (!serial_omap_baud_is_mode16(port, baud)) |
264 | divisor = 13; | 279 | mode = 13; |
265 | else | 280 | else |
266 | divisor = 16; | 281 | mode = 16; |
267 | return port->uartclk/(baud * divisor); | 282 | return port->uartclk/(mode * baud); |
268 | } | 283 | } |
269 | 284 | ||
270 | static void serial_omap_enable_ms(struct uart_port *port) | 285 | static void serial_omap_enable_ms(struct uart_port *port) |
@@ -283,28 +298,40 @@ static void serial_omap_enable_ms(struct uart_port *port) | |||
283 | static void serial_omap_stop_tx(struct uart_port *port) | 298 | static void serial_omap_stop_tx(struct uart_port *port) |
284 | { | 299 | { |
285 | struct uart_omap_port *up = to_uart_omap_port(port); | 300 | struct uart_omap_port *up = to_uart_omap_port(port); |
286 | struct circ_buf *xmit = &up->port.state->xmit; | ||
287 | int res; | 301 | int res; |
288 | 302 | ||
289 | pm_runtime_get_sync(up->dev); | 303 | pm_runtime_get_sync(up->dev); |
290 | 304 | ||
291 | /* handle rs485 */ | 305 | /* Handle RS-485 */ |
292 | if (up->rs485.flags & SER_RS485_ENABLED) { | 306 | if (up->rs485.flags & SER_RS485_ENABLED) { |
293 | /* do nothing if current tx not yet completed */ | 307 | if (up->scr & OMAP_UART_SCR_TX_EMPTY) { |
294 | res = serial_in(up, UART_LSR) & UART_LSR_TEMT; | 308 | /* THR interrupt is fired when both TX FIFO and TX |
295 | if (!res) | 309 | * shift register are empty. This means there's nothing |
296 | return; | 310 | * left to transmit now, so make sure the THR interrupt |
297 | 311 | * is fired when TX FIFO is below the trigger level, | |
298 | /* if there's no more data to send, turn off rts */ | 312 | * disable THR interrupts and toggle the RS-485 GPIO |
299 | if (uart_circ_empty(xmit)) { | 313 | * data direction pin if needed. |
300 | /* if rts not already disabled */ | 314 | */ |
315 | up->scr &= ~OMAP_UART_SCR_TX_EMPTY; | ||
316 | serial_out(up, UART_OMAP_SCR, up->scr); | ||
301 | res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; | 317 | res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; |
302 | if (gpio_get_value(up->rts_gpio) != res) { | 318 | if (gpio_get_value(up->rts_gpio) != res) { |
303 | if (up->rs485.delay_rts_after_send > 0) { | 319 | if (up->rs485.delay_rts_after_send > 0) |
304 | mdelay(up->rs485.delay_rts_after_send); | 320 | mdelay(up->rs485.delay_rts_after_send); |
305 | } | ||
306 | gpio_set_value(up->rts_gpio, res); | 321 | gpio_set_value(up->rts_gpio, res); |
307 | } | 322 | } |
323 | } else { | ||
324 | /* We're asked to stop, but there's still stuff in the | ||
325 | * UART FIFO, so make sure the THR interrupt is fired | ||
326 | * when both TX FIFO and TX shift register are empty. | ||
327 | * The next THR interrupt (if no transmission is started | ||
328 | * in the meantime) will indicate the end of a | ||
329 | * transmission. Therefore we _don't_ disable THR | ||
330 | * interrupts in this situation. | ||
331 | */ | ||
332 | up->scr |= OMAP_UART_SCR_TX_EMPTY; | ||
333 | serial_out(up, UART_OMAP_SCR, up->scr); | ||
334 | return; | ||
308 | } | 335 | } |
309 | } | 336 | } |
310 | 337 | ||
@@ -384,15 +411,18 @@ static void serial_omap_start_tx(struct uart_port *port) | |||
384 | 411 | ||
385 | pm_runtime_get_sync(up->dev); | 412 | pm_runtime_get_sync(up->dev); |
386 | 413 | ||
387 | /* handle rs485 */ | 414 | /* Handle RS-485 */ |
388 | if (up->rs485.flags & SER_RS485_ENABLED) { | 415 | if (up->rs485.flags & SER_RS485_ENABLED) { |
416 | /* Fire THR interrupts when FIFO is below trigger level */ | ||
417 | up->scr &= ~OMAP_UART_SCR_TX_EMPTY; | ||
418 | serial_out(up, UART_OMAP_SCR, up->scr); | ||
419 | |||
389 | /* if rts not already enabled */ | 420 | /* if rts not already enabled */ |
390 | res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; | 421 | res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; |
391 | if (gpio_get_value(up->rts_gpio) != res) { | 422 | if (gpio_get_value(up->rts_gpio) != res) { |
392 | gpio_set_value(up->rts_gpio, res); | 423 | gpio_set_value(up->rts_gpio, res); |
393 | if (up->rs485.delay_rts_before_send > 0) { | 424 | if (up->rs485.delay_rts_before_send > 0) |
394 | mdelay(up->rs485.delay_rts_before_send); | 425 | mdelay(up->rs485.delay_rts_before_send); |
395 | } | ||
396 | } | 426 | } |
397 | } | 427 | } |
398 | 428 | ||
@@ -699,6 +729,20 @@ static int serial_omap_startup(struct uart_port *port) | |||
699 | if (retval) | 729 | if (retval) |
700 | return retval; | 730 | return retval; |
701 | 731 | ||
732 | /* Optional wake-up IRQ */ | ||
733 | if (up->wakeirq) { | ||
734 | retval = request_irq(up->wakeirq, serial_omap_irq, | ||
735 | up->port.irqflags, up->name, up); | ||
736 | if (retval) { | ||
737 | free_irq(up->port.irq, up); | ||
738 | return retval; | ||
739 | } | ||
740 | disable_irq(up->wakeirq); | ||
741 | } else { | ||
742 | dev_info(up->port.dev, "no wakeirq for uart%d\n", | ||
743 | up->port.line); | ||
744 | } | ||
745 | |||
702 | dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); | 746 | dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); |
703 | 747 | ||
704 | pm_runtime_get_sync(up->dev); | 748 | pm_runtime_get_sync(up->dev); |
@@ -787,6 +831,8 @@ static void serial_omap_shutdown(struct uart_port *port) | |||
787 | pm_runtime_mark_last_busy(up->dev); | 831 | pm_runtime_mark_last_busy(up->dev); |
788 | pm_runtime_put_autosuspend(up->dev); | 832 | pm_runtime_put_autosuspend(up->dev); |
789 | free_irq(up->port.irq, up); | 833 | free_irq(up->port.irq, up); |
834 | if (up->wakeirq) | ||
835 | free_irq(up->wakeirq, up); | ||
790 | } | 836 | } |
791 | 837 | ||
792 | static void serial_omap_uart_qos_work(struct work_struct *work) | 838 | static void serial_omap_uart_qos_work(struct work_struct *work) |
@@ -938,7 +984,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, | |||
938 | */ | 984 | */ |
939 | 985 | ||
940 | /* Set receive FIFO threshold to 16 characters and | 986 | /* Set receive FIFO threshold to 16 characters and |
941 | * transmit FIFO threshold to 16 spaces | 987 | * transmit FIFO threshold to 32 spaces |
942 | */ | 988 | */ |
943 | up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; | 989 | up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; |
944 | up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; | 990 | up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; |
@@ -1060,15 +1106,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, | |||
1060 | dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); | 1106 | dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); |
1061 | } | 1107 | } |
1062 | 1108 | ||
1063 | static int serial_omap_set_wake(struct uart_port *port, unsigned int state) | ||
1064 | { | ||
1065 | struct uart_omap_port *up = to_uart_omap_port(port); | ||
1066 | |||
1067 | serial_omap_enable_wakeup(up, state); | ||
1068 | |||
1069 | return 0; | ||
1070 | } | ||
1071 | |||
1072 | static void | 1109 | static void |
1073 | serial_omap_pm(struct uart_port *port, unsigned int state, | 1110 | serial_omap_pm(struct uart_port *port, unsigned int state, |
1074 | unsigned int oldstate) | 1111 | unsigned int oldstate) |
@@ -1353,6 +1390,15 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) | |||
1353 | up->ier = mode; | 1390 | up->ier = mode; |
1354 | serial_out(up, UART_IER, up->ier); | 1391 | serial_out(up, UART_IER, up->ier); |
1355 | 1392 | ||
1393 | /* If RS-485 is disabled, make sure the THR interrupt is fired when | ||
1394 | * TX FIFO is below the trigger level. | ||
1395 | */ | ||
1396 | if (!(up->rs485.flags & SER_RS485_ENABLED) && | ||
1397 | (up->scr & OMAP_UART_SCR_TX_EMPTY)) { | ||
1398 | up->scr &= ~OMAP_UART_SCR_TX_EMPTY; | ||
1399 | serial_out(up, UART_OMAP_SCR, up->scr); | ||
1400 | } | ||
1401 | |||
1356 | spin_unlock_irqrestore(&up->port.lock, flags); | 1402 | spin_unlock_irqrestore(&up->port.lock, flags); |
1357 | pm_runtime_mark_last_busy(up->dev); | 1403 | pm_runtime_mark_last_busy(up->dev); |
1358 | pm_runtime_put_autosuspend(up->dev); | 1404 | pm_runtime_put_autosuspend(up->dev); |
@@ -1401,7 +1447,6 @@ static struct uart_ops serial_omap_pops = { | |||
1401 | .shutdown = serial_omap_shutdown, | 1447 | .shutdown = serial_omap_shutdown, |
1402 | .set_termios = serial_omap_set_termios, | 1448 | .set_termios = serial_omap_set_termios, |
1403 | .pm = serial_omap_pm, | 1449 | .pm = serial_omap_pm, |
1404 | .set_wake = serial_omap_set_wake, | ||
1405 | .type = serial_omap_type, | 1450 | .type = serial_omap_type, |
1406 | .release_port = serial_omap_release_port, | 1451 | .release_port = serial_omap_release_port, |
1407 | .request_port = serial_omap_request_port, | 1452 | .request_port = serial_omap_request_port, |
@@ -1582,11 +1627,23 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1582 | struct uart_omap_port *up; | 1627 | struct uart_omap_port *up; |
1583 | struct resource *mem, *irq; | 1628 | struct resource *mem, *irq; |
1584 | struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); | 1629 | struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); |
1585 | int ret; | 1630 | int ret, uartirq = 0, wakeirq = 0; |
1586 | 1631 | ||
1632 | /* The optional wakeirq may be specified in the board dts file */ | ||
1587 | if (pdev->dev.of_node) { | 1633 | if (pdev->dev.of_node) { |
1634 | uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0); | ||
1635 | if (!uartirq) | ||
1636 | return -EPROBE_DEFER; | ||
1637 | wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); | ||
1588 | omap_up_info = of_get_uart_port_info(&pdev->dev); | 1638 | omap_up_info = of_get_uart_port_info(&pdev->dev); |
1589 | pdev->dev.platform_data = omap_up_info; | 1639 | pdev->dev.platform_data = omap_up_info; |
1640 | } else { | ||
1641 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1642 | if (!irq) { | ||
1643 | dev_err(&pdev->dev, "no irq resource?\n"); | ||
1644 | return -ENODEV; | ||
1645 | } | ||
1646 | uartirq = irq->start; | ||
1590 | } | 1647 | } |
1591 | 1648 | ||
1592 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1649 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -1595,12 +1652,6 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1595 | return -ENODEV; | 1652 | return -ENODEV; |
1596 | } | 1653 | } |
1597 | 1654 | ||
1598 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1599 | if (!irq) { | ||
1600 | dev_err(&pdev->dev, "no irq resource?\n"); | ||
1601 | return -ENODEV; | ||
1602 | } | ||
1603 | |||
1604 | if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), | 1655 | if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), |
1605 | pdev->dev.driver->name)) { | 1656 | pdev->dev.driver->name)) { |
1606 | dev_err(&pdev->dev, "memory region already claimed\n"); | 1657 | dev_err(&pdev->dev, "memory region already claimed\n"); |
@@ -1634,7 +1685,8 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1634 | up->port.dev = &pdev->dev; | 1685 | up->port.dev = &pdev->dev; |
1635 | up->port.type = PORT_OMAP; | 1686 | up->port.type = PORT_OMAP; |
1636 | up->port.iotype = UPIO_MEM; | 1687 | up->port.iotype = UPIO_MEM; |
1637 | up->port.irq = irq->start; | 1688 | up->port.irq = uartirq; |
1689 | up->wakeirq = wakeirq; | ||
1638 | 1690 | ||
1639 | up->port.regshift = 2; | 1691 | up->port.regshift = 2; |
1640 | up->port.fifosize = 64; | 1692 | up->port.fifosize = 64; |
@@ -1670,8 +1722,9 @@ static int serial_omap_probe(struct platform_device *pdev) | |||
1670 | up->port.uartclk = omap_up_info->uartclk; | 1722 | up->port.uartclk = omap_up_info->uartclk; |
1671 | if (!up->port.uartclk) { | 1723 | if (!up->port.uartclk) { |
1672 | up->port.uartclk = DEFAULT_CLK_SPEED; | 1724 | up->port.uartclk = DEFAULT_CLK_SPEED; |
1673 | dev_warn(&pdev->dev, "No clock speed specified: using default:" | 1725 | dev_warn(&pdev->dev, |
1674 | "%d\n", DEFAULT_CLK_SPEED); | 1726 | "No clock speed specified: using default: %d\n", |
1727 | DEFAULT_CLK_SPEED); | ||
1675 | } | 1728 | } |
1676 | 1729 | ||
1677 | up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; | 1730 | up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; |