Merge tag 'tty-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[linux-2.6-microblaze.git] / drivers / tty / serial / samsung_tty.c
index 9fbc611..e2f4986 100644 (file)
@@ -65,6 +65,7 @@ enum s3c24xx_port_type {
 struct s3c24xx_uart_info {
        char                    *name;
        enum s3c24xx_port_type  type;
+       unsigned int            has_usi;
        unsigned int            port_type;
        unsigned int            fifosize;
        unsigned long           rx_fifomask;
@@ -305,8 +306,9 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
                dmaengine_pause(dma->tx_chan);
                dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
                dmaengine_terminate_all(dma->tx_chan);
-               dma_sync_single_for_cpu(ourport->port.dev,
-                       dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+               dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+                                       dma->tx_transfer_addr, dma->tx_size,
+                                       DMA_TO_DEVICE);
                async_tx_ack(dma->tx_desc);
                count = dma->tx_bytes_requested - state.residue;
                xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
@@ -338,8 +340,9 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
        count = dma->tx_bytes_requested - state.residue;
        async_tx_ack(dma->tx_desc);
 
-       dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
-                               dma->tx_size, DMA_TO_DEVICE);
+       dma_sync_single_for_cpu(dma->tx_chan->device->dev,
+                               dma->tx_transfer_addr, dma->tx_size,
+                               DMA_TO_DEVICE);
 
        spin_lock_irqsave(&port->lock, flags);
 
@@ -443,8 +446,9 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
        dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
        dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
 
-       dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
-                               dma->tx_size, DMA_TO_DEVICE);
+       dma_sync_single_for_device(dma->tx_chan->device->dev,
+                                  dma->tx_transfer_addr, dma->tx_size,
+                                  DMA_TO_DEVICE);
 
        dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
                                dma->tx_transfer_addr, dma->tx_size,
@@ -515,7 +519,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
        if (!count)
                return;
 
-       dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+       dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr,
                                dma->rx_size, DMA_FROM_DEVICE);
 
        ourport->port.icount.rx += count;
@@ -636,8 +640,8 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
 {
        struct s3c24xx_uart_dma *dma = ourport->dma;
 
-       dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
+       dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr,
+                                  dma->rx_size, DMA_FROM_DEVICE);
 
        dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
                                dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
@@ -1102,18 +1106,19 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
                goto err_release_tx;
        }
 
-       dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
-                               dma->rx_size, DMA_FROM_DEVICE);
-       if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
+       dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+                                     dma->rx_size, DMA_FROM_DEVICE);
+       if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) {
                reason = "DMA mapping error for RX buffer";
                ret = -EIO;
                goto err_free_rx;
        }
 
        /* TX buffer */
-       dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
-       if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
+       dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+                                     p->port.state->xmit.buf, UART_XMIT_SIZE,
+                                     DMA_TO_DEVICE);
+       if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
                reason = "DMA mapping error for TX buffer";
                ret = -EIO;
                goto err_unmap_rx;
@@ -1122,8 +1127,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
        return 0;
 
 err_unmap_rx:
-       dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size,
-                        DMA_FROM_DEVICE);
+       dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+                        dma->rx_size, DMA_FROM_DEVICE);
 err_free_rx:
        kfree(dma->rx_buf);
 err_release_tx:
@@ -1142,8 +1147,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
 
        if (dma->rx_chan) {
                dmaengine_terminate_all(dma->rx_chan);
-               dma_unmap_single(p->port.dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
+               dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+                                dma->rx_size, DMA_FROM_DEVICE);
                kfree(dma->rx_buf);
                dma_release_channel(dma->rx_chan);
                dma->rx_chan = NULL;
@@ -1151,8 +1156,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
 
        if (dma->tx_chan) {
                dmaengine_terminate_all(dma->tx_chan);
-               dma_unmap_single(p->port.dev, dma->tx_addr,
-                               UART_XMIT_SIZE, DMA_TO_DEVICE);
+               dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+                                UART_XMIT_SIZE, DMA_TO_DEVICE);
                dma_release_channel(dma->tx_chan);
                dma->tx_chan = NULL;
        }
@@ -1352,6 +1357,28 @@ static int apple_s5l_serial_startup(struct uart_port *port)
        return ret;
 }
 
+static void exynos_usi_init(struct uart_port *port)
+{
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_info *info = ourport->info;
+       unsigned int val;
+
+       if (!info->has_usi)
+               return;
+
+       /* Clear the software reset of USI block (it's set at startup) */
+       val = rd_regl(port, USI_CON);
+       val &= ~USI_CON_RESET_MASK;
+       wr_regl(port, USI_CON, val);
+       udelay(1);
+
+       /* Continuously provide the clock to USI IP w/o gating (for Rx mode) */
+       val = rd_regl(port, USI_OPTION);
+       val &= ~USI_OPTION_HWACG_MASK;
+       val |= USI_OPTION_HWACG_CLKREQ_ON;
+       wr_regl(port, USI_OPTION, val);
+}
+
 /* power power management control */
 
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
@@ -1379,6 +1406,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
                if (!IS_ERR(ourport->baudclk))
                        clk_prepare_enable(ourport->baudclk);
 
+               exynos_usi_init(port);
                break;
        default:
                dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level);
@@ -2102,6 +2130,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        if (ret)
                pr_warn("uart: failed to enable baudclk\n");
 
+       exynos_usi_init(port);
+
        /* Keep all interrupts masked and cleared */
        switch (ourport->info->type) {
        case TYPE_S3C6400:
@@ -2750,10 +2780,11 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
 #endif
 
 #if defined(CONFIG_ARCH_EXYNOS)
-#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
+#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi)            \
        .info = &(struct s3c24xx_uart_info) {                   \
                .name           = "Samsung Exynos UART",        \
                .type           = TYPE_S3C6400,                 \
+               .has_usi        = _has_usi,                     \
                .port_type      = PORT_S3C6400,                 \
                .has_divslot    = 1,                            \
                .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
@@ -2773,6 +2804,9 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
                .has_fracval    = 1,                            \
        }                                                       \
 
+#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
+       EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0)
+
 static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
        EXYNOS_COMMON_SERIAL_DRV_DATA,
        .fifosize = { 256, 64, 16, 16 },
@@ -2783,11 +2817,19 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
        .fifosize = { 64, 256, 16, 256 },
 };
 
+static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
+       EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1),
+       .fifosize = { 256, 64, 64, 64 },
+};
+
 #define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
 #define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
+#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos850_serial_drv_data)
+
 #else
-#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
-#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
+#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
 #endif
 
 #ifdef CONFIG_ARCH_APPLE
@@ -2843,6 +2885,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
        }, {
                .name           = "s5l-uart",
                .driver_data    = S5L_SERIAL_DRV_DATA,
+       }, {
+               .name           = "exynos850-uart",
+               .driver_data    = EXYNOS850_SERIAL_DRV_DATA,
        },
        { },
 };
@@ -2866,6 +2911,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
                .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
        { .compatible = "apple,s5l-uart",
                .data = (void *)S5L_SERIAL_DRV_DATA },
+       { .compatible = "samsung,exynos850-uart",
+               .data = (void *)EXYNOS850_SERIAL_DRV_DATA },
        {},
 };
 MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);