Merge tag 'renesas-soc-fixes2-for-v3.19' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / drivers / tty / serial / atmel_serial.c
index edde3ec..4d848a2 100644 (file)
@@ -167,7 +167,6 @@ struct atmel_uart_port {
 
        struct circ_buf         rx_ring;
 
-       struct serial_rs485     rs485;          /* rs485 settings */
        struct mctrl_gpios      *gpios;
        int                     gpio_irq[UART_GPIO_MAX];
        unsigned int            tx_done_mask;
@@ -290,13 +289,11 @@ static unsigned int atmel_get_lines_status(struct uart_port *port)
 }
 
 /* Enable or disable the rs485 support */
-void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+static int atmel_config_rs485(struct uart_port *port,
+                             struct serial_rs485 *rs485conf)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
        unsigned int mode;
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
 
        /* Disable interrupts */
        UART_PUT_IDR(port, atmel_port->tx_done_mask);
@@ -306,7 +303,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
        /* Resetting serial mode to RS232 (0x0) */
        mode &= ~ATMEL_US_USMODE;
 
-       atmel_port->rs485 = *rs485conf;
+       port->rs485 = *rs485conf;
 
        if (rs485conf->flags & SER_RS485_ENABLED) {
                dev_dbg(port->dev, "Setting UART to RS485\n");
@@ -327,8 +324,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
        /* Enable interrupts */
        UART_PUT_IER(port, atmel_port->tx_done_mask);
 
-       spin_unlock_irqrestore(&port->lock, flags);
-
+       return 0;
 }
 
 /*
@@ -372,11 +368,10 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
        /* Resetting serial mode to RS232 (0x0) */
        mode &= ~ATMEL_US_USMODE;
 
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+       if (port->rs485.flags & SER_RS485_ENABLED) {
                dev_dbg(port->dev, "Setting UART to RS485\n");
-               if ((atmel_port->rs485.delay_rts_after_send) > 0)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
+               if ((port->rs485.delay_rts_after_send) > 0)
+                       UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
                mode |= ATMEL_US_USMODE_RS485;
        } else {
                dev_dbg(port->dev, "Setting UART to RS232\n");
@@ -423,8 +418,8 @@ static void atmel_stop_tx(struct uart_port *port)
        /* Disable interrupts */
        UART_PUT_IDR(port, atmel_port->tx_done_mask);
 
-       if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
-           !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
+       if ((port->rs485.flags & SER_RS485_ENABLED) &&
+           !(port->rs485.flags & SER_RS485_RX_DURING_TX))
                atmel_start_rx(port);
 }
 
@@ -441,8 +436,8 @@ static void atmel_start_tx(struct uart_port *port)
                           really need this.*/
                        return;
 
-               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
-                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
+               if ((port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(port->rs485.flags & SER_RS485_RX_DURING_TX))
                        atmel_stop_rx(port);
 
                /* re-enable PDC transmit */
@@ -807,7 +802,7 @@ static void atmel_tx_dma(struct uart_port *port)
                atmel_port->cookie_tx = dmaengine_submit(desc);
 
        } else {
-               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               if (port->rs485.flags & SER_RS485_ENABLED) {
                        /* DMA done, stop TX, start RX for RS485 */
                        atmel_start_rx(port);
                }
@@ -862,9 +857,8 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
        config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
        config.dst_addr = port->mapbase + ATMEL_US_THR;
 
-       ret = dmaengine_device_control(atmel_port->chan_tx,
-                                       DMA_SLAVE_CONFIG,
-                                       (unsigned long)&config);
+       ret = dmaengine_slave_config(atmel_port->chan_tx,
+                                    &config);
        if (ret) {
                dev_err(port->dev, "DMA tx slave configuration failed\n");
                goto chan_err;
@@ -880,32 +874,6 @@ chan_err:
        return -EINVAL;
 }
 
-static void atmel_flip_buffer_rx_dma(struct uart_port *port,
-                                       char *buf, size_t count)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-       struct tty_port *tport = &port->state->port;
-
-       dma_sync_sg_for_cpu(port->dev,
-                               &atmel_port->sg_rx,
-                               1,
-                               DMA_DEV_TO_MEM);
-
-       tty_insert_flip_string(tport, buf, count);
-
-       dma_sync_sg_for_device(port->dev,
-                               &atmel_port->sg_rx,
-                               1,
-                               DMA_DEV_TO_MEM);
-       /*
-        * Drop the lock here since it might end up calling
-        * uart_start(), which takes the lock.
-        */
-       spin_unlock(&port->lock);
-       tty_flip_buffer_push(tport);
-       spin_lock(&port->lock);
-}
-
 static void atmel_complete_rx_dma(void *arg)
 {
        struct uart_port *port = arg;
@@ -934,11 +902,12 @@ static void atmel_release_rx_dma(struct uart_port *port)
 static void atmel_rx_from_dma(struct uart_port *port)
 {
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_port *tport = &port->state->port;
        struct circ_buf *ring = &atmel_port->rx_ring;
        struct dma_chan *chan = atmel_port->chan_rx;
        struct dma_tx_state state;
        enum dma_status dmastat;
-       size_t pending, count;
+       size_t count;
 
 
        /* Reset the UART timeout early so that we don't miss one */
@@ -953,27 +922,68 @@ static void atmel_rx_from_dma(struct uart_port *port)
                tasklet_schedule(&atmel_port->tasklet);
                return;
        }
-       /* current transfer size should no larger than dma buffer */
-       pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
-       BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
+
+       /* CPU claims ownership of RX DMA buffer */
+       dma_sync_sg_for_cpu(port->dev,
+                           &atmel_port->sg_rx,
+                           1,
+                           DMA_DEV_TO_MEM);
 
        /*
-        * This will take the chars we have so far,
-        * ring->head will record the transfer size, only new bytes come
-        * will insert into the framework.
+        * ring->head points to the end of data already written by the DMA.
+        * ring->tail points to the beginning of data to be read by the
+        * framework.
+        * The current transfer size should not be larger than the dma buffer
+        * length.
         */
-       if (pending > ring->head) {
-               count = pending - ring->head;
+       ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue;
+       BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx));
+       /*
+        * At this point ring->head may point to the first byte right after the
+        * last byte of the dma buffer:
+        * 0 <= ring->head <= sg_dma_len(&atmel_port->sg_rx)
+        *
+        * However ring->tail must always points inside the dma buffer:
+        * 0 <= ring->tail <= sg_dma_len(&atmel_port->sg_rx) - 1
+        *
+        * Since we use a ring buffer, we have to handle the case
+        * where head is lower than tail. In such a case, we first read from
+        * tail to the end of the buffer then reset tail.
+        */
+       if (ring->head < ring->tail) {
+               count = sg_dma_len(&atmel_port->sg_rx) - ring->tail;
+
+               tty_insert_flip_string(tport, ring->buf + ring->tail, count);
+               ring->tail = 0;
+               port->icount.rx += count;
+       }
 
-               atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count);
+       /* Finally we read data from tail to head */
+       if (ring->tail < ring->head) {
+               count = ring->head - ring->tail;
 
-               ring->head += count;
-               if (ring->head == sg_dma_len(&atmel_port->sg_rx))
+               tty_insert_flip_string(tport, ring->buf + ring->tail, count);
+               /* Wrap ring->head if needed */
+               if (ring->head >= sg_dma_len(&atmel_port->sg_rx))
                        ring->head = 0;
-
+               ring->tail = ring->head;
                port->icount.rx += count;
        }
 
+       /* USART retreives ownership of RX DMA buffer */
+       dma_sync_sg_for_device(port->dev,
+                              &atmel_port->sg_rx,
+                              1,
+                              DMA_DEV_TO_MEM);
+
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tport);
+       spin_lock(&port->lock);
+
        UART_PUT_IER(port, ATMEL_US_TIMEOUT);
 }
 
@@ -1026,9 +1036,8 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
        config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
        config.src_addr = port->mapbase + ATMEL_US_RHR;
 
-       ret = dmaengine_device_control(atmel_port->chan_rx,
-                                       DMA_SLAVE_CONFIG,
-                                       (unsigned long)&config);
+       ret = dmaengine_slave_config(atmel_port->chan_rx,
+                                    &config);
        if (ret) {
                dev_err(port->dev, "DMA rx slave configuration failed\n");
                goto chan_err;
@@ -1240,8 +1249,8 @@ static void atmel_tx_pdc(struct uart_port *port)
                /* Enable interrupts */
                UART_PUT_IER(port, atmel_port->tx_done_mask);
        } else {
-               if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
-                   !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+               if ((port->rs485.flags & SER_RS485_ENABLED) &&
+                   !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
                        /* DMA done, stop TX, start RX for RS485 */
                        atmel_start_rx(port);
                }
@@ -1552,7 +1561,7 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port,
        return 0;
 }
 
-static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
+static void atmel_init_rs485(struct uart_port *port,
                                struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1563,7 +1572,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
                /* rs485 properties */
                if (of_property_read_u32_array(np, "rs485-rts-delay",
                                        rs485_delay, 2) == 0) {
-                       struct serial_rs485 *rs485conf = &atmel_port->rs485;
+                       struct serial_rs485 *rs485conf = &port->rs485;
 
                        rs485conf->delay_rts_before_send = rs485_delay[0];
                        rs485conf->delay_rts_after_send = rs485_delay[1];
@@ -1577,7 +1586,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
                        rs485conf->flags |= SER_RS485_ENABLED;
                }
        } else {
-               atmel_port->rs485       = pdata->rs485;
+               port->rs485       = pdata->rs485;
        }
 
 }
@@ -1801,6 +1810,20 @@ free_irq:
        return retval;
 }
 
+/*
+ * Flush any TX data submitted for DMA. Called when the TX circular
+ * buffer is reset.
+ */
+static void atmel_flush_buffer(struct uart_port *port)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+       if (atmel_use_pdc_tx(port)) {
+               UART_PUT_TCR(port, 0);
+               atmel_port->pdc_tx.ofs = 0;
+       }
+}
+
 /*
  * Disable the port
  */
@@ -1852,20 +1875,8 @@ static void atmel_shutdown(struct uart_port *port)
        atmel_free_gpio_irq(port);
 
        atmel_port->ms_irq_enabled = false;
-}
 
-/*
- * Flush any TX data submitted for DMA. Called when the TX circular
- * buffer is reset.
- */
-static void atmel_flush_buffer(struct uart_port *port)
-{
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
-
-       if (atmel_use_pdc_tx(port)) {
-               UART_PUT_TCR(port, 0);
-               atmel_port->pdc_tx.ofs = 0;
-       }
+       atmel_flush_buffer(port);
 }
 
 /*
@@ -1911,7 +1922,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 {
        unsigned long flags;
        unsigned int mode, imr, quot, baud;
-       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
        /* Get current mode register */
        mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
@@ -2013,10 +2023,9 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        /* Resetting serial mode to RS232 (0x0) */
        mode &= ~ATMEL_US_USMODE;
 
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
-               if ((atmel_port->rs485.delay_rts_after_send) > 0)
-                       UART_PUT_TTGR(port,
-                                       atmel_port->rs485.delay_rts_after_send);
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               if ((port->rs485.delay_rts_after_send) > 0)
+                       UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
                mode |= ATMEL_US_USMODE_RS485;
        }
 
@@ -2040,13 +2049,20 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void atmel_set_ldisc(struct uart_port *port, int new)
+static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios)
 {
-       if (new == N_PPS) {
+       if (termios->c_line == N_PPS) {
                port->flags |= UPF_HARDPPS_CD;
+               spin_lock_irq(&port->lock);
                atmel_enable_ms(port);
+               spin_unlock_irq(&port->lock);
        } else {
                port->flags &= ~UPF_HARDPPS_CD;
+               if (!UART_ENABLE_MS(port, termios->c_cflag)) {
+                       spin_lock_irq(&port->lock);
+                       atmel_disable_ms(port);
+                       spin_unlock_irq(&port->lock);
+               }
        }
 }
 
@@ -2148,35 +2164,6 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
 }
 #endif
 
-static int
-atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
-{
-       struct serial_rs485 rs485conf;
-
-       switch (cmd) {
-       case TIOCSRS485:
-               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-
-               atmel_config_rs485(port, &rs485conf);
-               break;
-
-       case TIOCGRS485:
-               if (copy_to_user((struct serial_rs485 *) arg,
-                                       &(to_atmel_uart_port(port)->rs485),
-                                       sizeof(rs485conf)))
-                       return -EFAULT;
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-
-
 static struct uart_ops atmel_pops = {
        .tx_empty       = atmel_tx_empty,
        .set_mctrl      = atmel_set_mctrl,
@@ -2197,7 +2184,6 @@ static struct uart_ops atmel_pops = {
        .config_port    = atmel_config_port,
        .verify_port    = atmel_verify_port,
        .pm             = atmel_serial_pm,
-       .ioctl          = atmel_ioctl,
 #ifdef CONFIG_CONSOLE_POLL
        .poll_get_char  = atmel_poll_get_char,
        .poll_put_char  = atmel_poll_put_char,
@@ -2217,7 +2203,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
        if (!atmel_init_property(atmel_port, pdev))
                atmel_set_ops(port);
 
-       atmel_init_rs485(atmel_port, pdev);
+       atmel_init_rs485(port, pdev);
 
        port->iotype            = UPIO_MEM;
        port->flags             = UPF_BOOT_AUTOCONF;
@@ -2226,6 +2212,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
        port->dev               = &pdev->dev;
        port->mapbase   = pdev->resource[0].start;
        port->irq       = pdev->resource[1].start;
+       port->rs485_config      = atmel_config_rs485;
 
        tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
                        (unsigned long)port);
@@ -2260,7 +2247,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
        }
 
        /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
-       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+       if (port->rs485.flags & SER_RS485_ENABLED)
                atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
        else if (atmel_use_pdc_tx(port)) {
                port->fifosize = PDC_BUFFER_SIZE;
@@ -2541,6 +2528,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
        struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
        void *data;
        int ret = -ENODEV;
+       bool rs485_enabled;
 
        BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
 
@@ -2588,6 +2576,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
                port->rx_ring.buf = data;
        }
 
+       rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
+
        ret = uart_add_one_port(&atmel_uart, &port->uart);
        if (ret)
                goto err_add_port;
@@ -2606,7 +2596,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
        device_init_wakeup(&pdev->dev, 1);
        platform_set_drvdata(pdev, port);
 
-       if (port->rs485.flags & SER_RS485_ENABLED) {
+       if (rs485_enabled) {
                UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
                UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
        }
@@ -2660,7 +2650,6 @@ static struct platform_driver atmel_serial_driver = {
        .resume         = atmel_serial_resume,
        .driver         = {
                .name   = "atmel_usart",
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(atmel_serial_dt_ids),
        },
 };