diff options
Diffstat (limited to 'drivers/tty/serial/samsung_tty.c')
-rw-r--r-- | drivers/tty/serial/samsung_tty.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 9fbc61151c2e..e2f49863e9c2 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -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); |