diff options
Diffstat (limited to 'drivers/tty/serial/samsung_tty.c')
-rw-r--r-- | drivers/tty/serial/samsung_tty.c | 84 |
1 files changed, 68 insertions, 16 deletions
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 73f951d65b93..d913d9b2762a 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -154,10 +154,33 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg))) +static u32 rd_reg(struct uart_port *port, u32 reg) +{ + switch (port->iotype) { + case UPIO_MEM: + return readb_relaxed(portaddr(port, reg)); + case UPIO_MEM32: + return readl_relaxed(portaddr(port, reg)); + default: + return 0; + } + return 0; +} + #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +static void wr_reg(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb_relaxed(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel_relaxed(val, portaddr(port, reg)); + break; + } +} + #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) /* Byte-order aware bit setting/clearing functions. */ @@ -714,7 +737,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) fifocnt--; uerstat = rd_regl(port, S3C2410_UERSTAT); - ch = rd_regb(port, S3C2410_URXH); + ch = rd_reg(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); @@ -826,7 +849,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) } if (port->x_char) { - wr_regb(port, S3C2410_UTXH, port->x_char); + wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; goto out; @@ -852,7 +875,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) break; - wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); + wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count--; @@ -916,7 +939,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) /* no modem control lines */ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) { - unsigned int umstat = rd_regb(port, S3C2410_UMSTAT); + unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); if (umstat & S3C2410_UMSTAT_CTS) return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; @@ -1281,14 +1304,14 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, struct s3c24xx_uart_info *info = ourport->info; struct clk *clk; unsigned long rate; - unsigned int cnt, baud, quot, clk_sel, best_quot = 0; + unsigned int cnt, baud, quot, best_quot = 0; char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; - clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel : - ourport->info->def_clk_sel; for (cnt = 0; cnt < info->num_clks; cnt++) { - if (!(clk_sel & (1 << cnt))) + /* Keep selected clock if provided */ + if (ourport->cfg->clk_sel && + !(ourport->cfg->clk_sel & (1 << cnt))) continue; sprintf(clkname, "clk_uart_baud%d", cnt); @@ -1974,7 +1997,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; - int ret; + int ret, prop = 0; if (np) { ret = of_alias_get_id(np, "serial"); @@ -2000,10 +2023,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; - if (np) + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + ourport->port.iotype = UPIO_MEM; + break; + case 4: + ourport->port.iotype = UPIO_MEM32; + break; + default: + dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n", + prop); + ret = -EINVAL; + break; + } + } + } + if (ourport->drv_data->fifosize[index]) ourport->port.fifosize = ourport->drv_data->fifosize[index]; else if (ourport->info->fifosize) @@ -2185,7 +2225,7 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) return NO_POLL_CHAR; - return rd_regb(port, S3C2410_URXH); + return rd_reg(port, S3C2410_URXH); } static void s3c24xx_serial_put_poll_char(struct uart_port *port, @@ -2200,7 +2240,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, c); + wr_reg(port, S3C2410_UTXH, c); } #endif /* CONFIG_CONSOLE_POLL */ @@ -2212,7 +2252,7 @@ s3c24xx_serial_console_putchar(struct uart_port *port, int ch) while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, ch); + wr_reg(port, S3C2410_UTXH, ch); } static void @@ -2587,6 +2627,18 @@ module_platform_driver(samsung_serial_driver); * Early console. */ +static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel(val, portaddr(port, reg)); + break; + } +} + struct samsung_early_console_data { u32 txfull_mask; }; @@ -2612,7 +2664,7 @@ static void samsung_early_putc(struct uart_port *port, int c) else samsung_early_busyuart(port); - writeb(c, port->membase + S3C2410_UTXH); + wr_reg_barrier(port, S3C2410_UTXH, c); } static void samsung_early_write(struct console *con, const char *s, |