diff options
Diffstat (limited to 'drivers/tty/serial')
83 files changed, 6716 insertions, 3261 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 570df9d2a5d..7a91c6d1eb7 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -555,7 +555,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) */ if ((p->port.type == PORT_XR17V35X) || (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, 0xff); + serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); return; } @@ -1520,7 +1520,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial8250_rx_chars(up, status); } serial8250_modem_status(up); - if (status & UART_LSR_THRE) + if (!up->dma && (status & UART_LSR_THRE)) serial8250_tx_chars(up); spin_unlock_irqrestore(&port->lock, flags); @@ -1694,6 +1694,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up) static void serial_unlink_irq_chain(struct uart_8250_port *up) { + /* + * yes, some broken gcc emit "warning: 'i' may be used uninitialized" + * but no, we are not going to take a patch that assigns NULL below. + */ struct irq_info *i; struct hlist_node *n; struct hlist_head *h; @@ -1922,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port, wait_for_xmitr(up, BOTH_EMPTY); /* * Send the character out. - * If a LF, also do CR... */ serial_port_out(port, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_TX, 13); - } /* * Finally, wait for transmitter to become empty @@ -2322,7 +2321,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { fcr = uart_config[port->type].fcr; - if (baud < 2400 || fifo_bug) { + if ((baud < 2400 && !up->dma) || fifo_bug) { fcr &= ~UART_FCR_TRIGGER_MASK; fcr |= UART_FCR_TRIGGER_1; } @@ -2334,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, * the trigger, or the MCR RTS bit is cleared. In the case where * the remote UART is not using CTS auto flow control, we must * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. + * UART to respond. IOW, at least 32 bytes of FIFO. Also enable + * AFE if hw flow control is supported */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) || + (port->flags & UPF_HARD_FLOW)) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; @@ -2356,7 +2357,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; /* @@ -2433,6 +2434,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial_dl_write(up, quot); /* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * + * We need to recalculate all of the registers, because DLM and DLL + * are already rounded to a whole integer. + * + * When recalculating we use a 32x clock instead of a 16x clock to + * allow 1-bit for rounding in the fractional part. + */ + if (up->port.type == PORT_XR17V35X) { + unsigned int baud_x32 = (port->uartclk * 2) / baud; + u16 quot = baud_x32 / 32; + u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2); + + serial_dl_write(up, quot); + serial_port_out(port, 0x2, quot_frac & 0xf); + } + + /* * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR * is written without DLAB set, this mode will be disabled. */ @@ -2670,6 +2689,10 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_16550A && port->iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; + /* HW bugs may trigger IRQ while IIR == NO_INT */ + if (port->type == PORT_TEGRA) + up->bugs |= UART_BUG_NOMSR; + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) autoconfig_irq(up); @@ -2860,14 +2883,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) touch_nmi_watchdog(); - local_irq_save(flags); - if (port->sysrq) { - /* serial8250_handle_irq() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); + if (port->sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); /* * First save the IER then disable the interrupts @@ -2899,8 +2918,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) serial8250_modem_status(up); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static int __init serial8250_console_setup(struct console *co, char *options) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 7046769608d..148ffe4c232 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -20,12 +20,15 @@ static void __dma_tx_complete(void *param) struct uart_8250_port *p = param; struct uart_8250_dma *dma = p->dma; struct circ_buf *xmit = &p->port.state->xmit; - - dma->tx_running = 0; + unsigned long flags; dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); + spin_lock_irqsave(&p->port.lock, flags); + + dma->tx_running = 0; + xmit->tail += dma->tx_size; xmit->tail &= UART_XMIT_SIZE - 1; p->port.icount.tx += dma->tx_size; @@ -35,6 +38,8 @@ static void __dma_tx_complete(void *param) if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) serial8250_tx_dma(p); + + spin_unlock_irqrestore(&p->port.lock, flags); } static void __dma_rx_complete(void *param) @@ -187,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p) dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, &dma->rx_addr, GFP_KERNEL); - if (!dma->rx_buf) { - dma_release_channel(dma->rxchan); - dma_release_channel(dma->txchan); - return -ENOMEM; - } + if (!dma->rx_buf) + goto err; /* TX buffer */ dma->tx_addr = dma_map_single(dma->txchan->device->dev, p->port.state->xmit.buf, UART_XMIT_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) { + dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, + dma->rx_buf, dma->rx_addr); + goto err; + } dev_dbg_ratelimited(p->port.dev, "got both dma channels\n"); return 0; +err: + dma_release_channel(dma->rxchan); + dma_release_channel(dma->txchan); + + return -ENOMEM; } EXPORT_SYMBOL_GPL(serial8250_request_dma); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index daf710f5c3f..51b307aab75 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -14,7 +14,6 @@ * raised, the LCR needs to be rewritten and the uart status register read. */ #include <linux/device.h> -#include <linux/init.h> #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> @@ -56,13 +55,77 @@ struct dw8250_data { - int last_lcr; - int last_mcr; - int line; - struct clk *clk; - u8 usr_reg; + u8 usr_reg; + int last_mcr; + int line; + struct clk *clk; + struct uart_8250_dma dma; }; +struct dw8250_acpi_desc { + void (*set_termios)(struct uart_port *p, struct ktermios *termios, + struct ktermios *old); +}; + +#define BYT_PRV_CLK 0x800 +#define BYT_PRV_CLK_EN (1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT 1 +#define BYT_PRV_CLK_N_VAL_SHIFT 16 +#define BYT_PRV_CLK_UPDATE (1 << 31) + +static void byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m, n; + u32 reg; + + /* + * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the + * dividers must be adjusted. + * + * uartclk = (m / n) * 100 MHz, where m <= n + */ + switch (baud) { + case 500000: + case 1000000: + case 2000000: + case 4000000: + m = 64; + n = 100; + p->uartclk = 64000000; + break; + case 3500000: + m = 56; + n = 100; + p->uartclk = 56000000; + break; + case 1500000: + case 3000000: + m = 48; + n = 100; + p->uartclk = 48000000; + break; + case 2500000: + m = 40; + n = 100; + p->uartclk = 40000000; + break; + default: + m = 2304; + n = 3125; + p->uartclk = 73728000; + } + + /* Reset the clock */ + reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BYT_PRV_CLK); + reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; + writel(reg, p->membase + BYT_PRV_CLK); + + serial8250_do_set_termios(p, termios, old); +} + static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -76,17 +139,34 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) return value; } +static void dw8250_force_idle(struct uart_port *p) +{ + serial8250_clear_and_reinit_fifos(container_of + (p, struct uart_8250_port, port)); + (void)p->serial_in(p, UART_RX); +} + static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writeb(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) + return; + dw8250_force_idle(p); + writeb(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) @@ -107,13 +187,23 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writel(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) + return; + dw8250_force_idle(p); + writel(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -131,9 +221,8 @@ static int dw8250_handle_irq(struct uart_port *p) if (serial8250_handle_irq(p, iir)) { return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* Clear the USR and write the LCR again. */ + /* Clear the USR */ (void)p->serial_in(p, d->usr_reg); - p->serial_out(p, UART_LCR, d->last_lcr); return 1; } @@ -153,6 +242,14 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) pm_runtime_put_sync_suspend(port->dev); } +static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw8250_data *data = param; + + return chan->chan_id == data->dma.tx_chan_id || + chan->chan_id == data->dma.rx_chan_id; +} + static void dw8250_setup_port(struct uart_8250_port *up) { struct uart_port *p = &up->port; @@ -240,11 +337,12 @@ static int dw8250_probe_of(struct uart_port *p, return 0; } -#ifdef CONFIG_ACPI -static int dw8250_probe_acpi(struct uart_8250_port *up) +static int dw8250_probe_acpi(struct uart_8250_port *up, + struct dw8250_data *data) { const struct acpi_device_id *id; struct uart_port *p = &up->port; + struct dw8250_acpi_desc *acpi_desc; dw8250_setup_port(up); @@ -257,24 +355,20 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) p->serial_out = dw8250_serial_out32; p->regshift = 2; - if (!p->uartclk) - p->uartclk = (unsigned int)id->driver_data; - - up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL); - if (!up->dma) - return -ENOMEM; + up->dma = &data->dma; up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; + acpi_desc = (struct dw8250_acpi_desc *)id->driver_data; + if (!acpi_desc) + return 0; + + if (acpi_desc->set_termios) + p->set_termios = acpi_desc->set_termios; + return 0; } -#else -static inline int dw8250_probe_acpi(struct uart_8250_port *up) -{ - return -ENODEV; -} -#endif /* CONFIG_ACPI */ static int dw8250_probe(struct platform_device *pdev) { @@ -314,6 +408,12 @@ static int dw8250_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk); } + data->dma.rx_chan_id = -1; + data->dma.tx_chan_id = -1; + data->dma.rx_param = data; + data->dma.tx_param = data; + data->dma.fn = dw8250_dma_filter; + uart.port.iotype = UPIO_MEM; uart.port.serial_in = dw8250_serial_in; uart.port.serial_out = dw8250_serial_out; @@ -324,7 +424,7 @@ static int dw8250_probe(struct platform_device *pdev) if (err) return err; } else if (ACPI_HANDLE(&pdev->dev)) { - err = dw8250_probe_acpi(&uart); + err = dw8250_probe_acpi(&uart, data); if (err) return err; } else { @@ -360,7 +460,7 @@ static int dw8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -378,7 +478,7 @@ static int dw8250_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_RUNTIME static int dw8250_runtime_suspend(struct device *dev) @@ -414,10 +514,16 @@ static const struct of_device_id dw8250_of_match[] = { }; MODULE_DEVICE_TABLE(of, dw8250_of_match); +static struct dw8250_acpi_desc byt_8250_desc = { + .set_termios = byt_set_termios, +}; + static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, - { "80860F0A", 0 }, + { "INT3434", 0 }, + { "INT3435", 0 }, + { "80860F0A", (kernel_ulong_t)&byt_8250_desc}, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index c100d6343d5..4858b8a99d3 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -35,18 +35,8 @@ #include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> -#ifdef CONFIG_FIX_EARLYCON_MEM -#include <asm/pgtable.h> -#include <asm/fixmap.h> -#endif -struct early_serial8250_device { - struct uart_port port; - char options[16]; /* e.g., 115200n8 */ - unsigned int baud; -}; - -static struct early_serial8250_device early_device; +static struct earlycon_device *early_device; unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) { @@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c) static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { - struct uart_port *port = &early_device.port; + struct uart_port *port = &early_device->port; unsigned int ier; /* Save the IER and disable interrupts */ @@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port) return (port->uartclk / 16) / quot; } -static void __init init_port(struct early_serial8250_device *device) +static void __init init_port(struct earlycon_device *device) { struct uart_port *port = &device->port; unsigned int divisor; @@ -148,128 +138,45 @@ static void __init init_port(struct early_serial8250_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_serial8250_device *device, - char *options) +static int __init early_serial8250_setup(struct earlycon_device *device, + const char *options) { - struct uart_port *port = &device->port; - int mmio, mmio32, length; - - if (!options) - return -ENODEV; - - port->uartclk = BASE_BAUD * 16; - - mmio = !strncmp(options, "mmio,", 5); - mmio32 = !strncmp(options, "mmio32,", 7); - if (mmio || mmio32) { - port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); - port->mapbase = simple_strtoul(options + (mmio ? 5 : 7), - &options, 0); - if (mmio32) - port->regshift = 2; -#ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, - port->mapbase & PAGE_MASK); - port->membase = - (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); - port->membase += port->mapbase & ~PAGE_MASK; -#else - port->membase = ioremap_nocache(port->mapbase, 64); - if (!port->membase) { - printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", - __func__, - (unsigned long long) port->mapbase); - return -ENOMEM; - } -#endif - } else if (!strncmp(options, "io,", 3)) { - port->iotype = UPIO_PORT; - port->iobase = simple_strtoul(options + 3, &options, 0); - mmio = 0; - } else - return -EINVAL; + if (!(device->port.membase || device->port.iobase)) + return 0; - options = strchr(options, ','); - if (options) { - options++; - device->baud = simple_strtoul(options, NULL, 0); - length = min(strcspn(options, " ") + 1, - (size_t)(sizeof(device->options))); - strlcpy(device->options, options, length); - } else { - device->baud = probe_baud(port); + if (!device->baud) { + device->baud = probe_baud(&device->port); snprintf(device->options, sizeof(device->options), "%u", - device->baud); + device->baud); } - if (mmio || mmio32) - printk(KERN_INFO - "Early serial console at MMIO%s 0x%llx (options '%s')\n", - mmio32 ? "32" : "", - (unsigned long long)port->mapbase, - device->options); - else - printk(KERN_INFO - "Early serial console at I/O port 0x%lx (options '%s')\n", - port->iobase, - device->options); - - return 0; -} - -static struct console early_serial8250_console __initdata = { - .name = "uart", - .write = early_serial8250_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -static int __init early_serial8250_setup(char *options) -{ - struct early_serial8250_device *device = &early_device; - int err; - - if (device->port.membase || device->port.iobase) - return 0; - - err = parse_options(device, options); - if (err < 0) - return err; - init_port(device); + + early_device = device; + device->con->write = early_serial8250_write; return 0; } +EARLYCON_DECLARE(uart8250, early_serial8250_setup); +EARLYCON_DECLARE(uart, early_serial8250_setup); int __init setup_early_serial8250_console(char *cmdline) { - char *options; - int err; + char match[] = "uart8250"; - options = strstr(cmdline, "uart8250,"); - if (!options) { - options = strstr(cmdline, "uart,"); - if (!options) - return 0; - } - - options = strchr(cmdline, ',') + 1; - err = early_serial8250_setup(options); - if (err < 0) - return err; - - register_console(&early_serial8250_console); + if (cmdline && cmdline[4] == ',') + match[4] = '\0'; - return 0; + return setup_earlycon(cmdline, match, early_serial8250_setup); } int serial8250_find_port_for_earlycon(void) { - struct early_serial8250_device *device = &early_device; - struct uart_port *port = &device->port; + struct earlycon_device *device = early_device; + struct uart_port *port = device ? &device->port : NULL; int line; int ret; - if (!device->port.membase && !device->port.iobase) + if (!port || (!port->membase && !port->iobase)) return -ENODEV; line = serial8250_find_port(port); @@ -284,5 +191,3 @@ int serial8250_find_port_for_earlycon(void) return ret; } - -early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 5f3bba12c15..56c87232b6a 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -18,7 +18,6 @@ */ #include <linux/device.h> -#include <linux/init.h> #include <linux/io.h> #include <linux/module.h> #include <linux/serial_8250.h> @@ -122,7 +121,7 @@ static int serial8250_em_probe(struct platform_device *pdev) up.port.dev = &pdev->dev; up.port.private_data = priv; - clk_enable(priv->sclk); + clk_prepare_enable(priv->sclk); up.port.uartclk = clk_get_rate(priv->sclk); up.port.iotype = UPIO_MEM32; @@ -134,7 +133,7 @@ static int serial8250_em_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&up); if (ret < 0) { dev_err(&pdev->dev, "unable to register 8250 port\n"); - clk_disable(priv->sclk); + clk_disable_unprepare(priv->sclk); return ret; } @@ -148,7 +147,7 @@ static int serial8250_em_remove(struct platform_device *pdev) struct serial8250_em_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); - clk_disable(priv->sclk); + clk_disable_unprepare(priv->sclk); return 0; } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index c810da7c7a8..33137b3ba94 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -9,8 +9,8 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. */ +#undef DEBUG #include <linux/module.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/string.h> #include <linux/kernel.h> @@ -27,8 +27,6 @@ #include "8250.h" -#undef SERIAL_DEBUG_PCI - /* * init function returns: * > 0 - number of ports @@ -63,7 +61,7 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - printk(KERN_WARNING + dev_err(&dev->dev, "%s: %s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" @@ -233,7 +231,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, (void *)&oldval); if (oldval == 0x00001000L) { /* RESET value */ - printk(KERN_DEBUG "Local i960 firmware missing"); + dev_dbg(&dev->dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -785,7 +783,8 @@ static int pci_netmos_9900_setup(struct serial_private *priv, { unsigned int bar; - if ((priv->dev->subsystem_device & 0xff00) == 0x3000) { + if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) && + (priv->dev->subsystem_device & 0xff00) == 0x3000) { /* netmos apparently orders BARs by datasheet layout, so serial * ports get BARs 0 and 3 (or 1 and 4 for memmapped) */ @@ -827,7 +826,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) { return sub_serports; } else { - printk(KERN_NOTICE "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } } @@ -931,7 +930,7 @@ static int pci_ite887x_init(struct pci_dev *dev) } if (!inta_addr[i]) { - printk(KERN_ERR "ite887x: could not find iobase\n"); + dev_err(&dev->dev, "ite887x: could not find iobase\n"); return -ENODEV; } @@ -1024,9 +1023,9 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - printk(KERN_DEBUG + dev_dbg(&dev->dev, "%d ports detected on Oxford PCI Express device\n", - number_uarts); + number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1260,10 +1259,10 @@ static int pci_quatech_init(struct pci_dev *dev) unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; - outl(inl(base + 0x38), base + 0x38); + outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); - outl(tmp, base + 0x3c); + outl(tmp &= ~0x01000000, base + 0x3c); } } return 0; @@ -1308,6 +1307,29 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } +static int pci_pericom_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset, maxnr; + + bar = FL_GET_BASE(board->flags); + if (board->flags & FL_BASE_BARS) + bar += idx; + else + offset += idx * board->uart_offset; + + maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> + (board->reg_shift + 3); + + if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) + return 1; + + port->port.uartclk = 14745600; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + static int ce4100_serial_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1324,6 +1346,141 @@ ce4100_serial_setup(struct serial_private *priv, return ret; } +#define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a +#define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c + +#define BYT_PRV_CLK 0x800 +#define BYT_PRV_CLK_EN (1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT 1 +#define BYT_PRV_CLK_N_VAL_SHIFT 16 +#define BYT_PRV_CLK_UPDATE (1 << 31) + +#define BYT_GENERAL_REG 0x808 +#define BYT_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3) + +#define BYT_TX_OVF_INT 0x820 +#define BYT_TX_OVF_INT_MASK (1 << 1) + +static void +byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m, n; + u32 reg; + + /* + * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the + * dividers must be adjusted. + * + * uartclk = (m / n) * 100 MHz, where m <= n + */ + switch (baud) { + case 500000: + case 1000000: + case 2000000: + case 4000000: + m = 64; + n = 100; + p->uartclk = 64000000; + break; + case 3500000: + m = 56; + n = 100; + p->uartclk = 56000000; + break; + case 1500000: + case 3000000: + m = 48; + n = 100; + p->uartclk = 48000000; + break; + case 2500000: + m = 40; + n = 100; + p->uartclk = 40000000; + break; + default: + m = 2304; + n = 3125; + p->uartclk = 73728000; + } + + /* Reset the clock */ + reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BYT_PRV_CLK); + reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; + writel(reg, p->membase + BYT_PRV_CLK); + + /* + * If auto-handshake mechanism is not enabled, + * disable rts_n override + */ + reg = readl(p->membase + BYT_GENERAL_REG); + reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE; + if (termios->c_cflag & CRTSCTS) + reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE; + writel(reg, p->membase + BYT_GENERAL_REG); + + serial8250_do_set_termios(p, termios, old); +} + +static bool byt_dma_filter(struct dma_chan *chan, void *param) +{ + return chan->chan_id == *(int *)param; +} + +static int +byt_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct uart_8250_dma *dma; + int ret; + + dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + switch (priv->dev->device) { + case PCI_DEVICE_ID_INTEL_BYT_UART1: + dma->rx_chan_id = 3; + dma->tx_chan_id = 2; + break; + case PCI_DEVICE_ID_INTEL_BYT_UART2: + dma->rx_chan_id = 5; + dma->tx_chan_id = 4; + break; + default: + return -EINVAL; + } + + dma->rxconf.slave_id = dma->rx_chan_id; + dma->rxconf.src_maxburst = 16; + + dma->txconf.slave_id = dma->tx_chan_id; + dma->txconf.dst_maxburst = 16; + + dma->fn = byt_dma_filter; + dma->rx_param = &dma->rx_chan_id; + dma->tx_param = &dma->tx_chan_id; + + ret = pci_default_setup(priv, board, port, idx); + port->port.iotype = UPIO_MEM; + port->port.type = PORT_16550A; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + port->port.set_termios = byt_set_termios; + port->port.fifosize = 64; + port->tx_loadsz = 64; + port->dma = dma; + port->capabilities = UART_CAP_FIFO | UART_CAP_AFE; + + /* Disable Tx counter interrupts */ + writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT); + + return ret; +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1344,17 +1501,80 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +static int pci_fintek_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + unsigned long base; + unsigned long iobase; + unsigned long ciobase = 0; + u8 config_base; + + /* + * We are supposed to be able to read these from the PCI config space, + * but the values there don't seem to match what we need to use, so + * just use these hard-coded values for now, as they are correct. + */ + switch (idx) { + case 0: iobase = 0xe000; config_base = 0x40; break; + case 1: iobase = 0xe008; config_base = 0x48; break; + case 2: iobase = 0xe010; config_base = 0x50; break; + case 3: iobase = 0xe018; config_base = 0x58; break; + case 4: iobase = 0xe020; config_base = 0x60; break; + case 5: iobase = 0xe028; config_base = 0x68; break; + case 6: iobase = 0xe030; config_base = 0x70; break; + case 7: iobase = 0xe038; config_base = 0x78; break; + case 8: iobase = 0xe040; config_base = 0x80; break; + case 9: iobase = 0xe048; config_base = 0x88; break; + case 10: iobase = 0xe050; config_base = 0x90; break; + case 11: iobase = 0xe058; config_base = 0x98; break; + default: + /* Unknown number of ports, get out of here */ + return -EINVAL; + } + + if (idx < 4) { + base = pci_resource_start(priv->dev, 3); + ciobase = (int)(base + (0x8 * idx)); + } + + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", + __func__, idx, iobase, ciobase, config_base); + + /* Enable UART I/O port */ + pci_write_config_byte(pdev, config_base + 0x00, 0x01); + + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(pdev, config_base + 0x01, 0x33); + + /* LSB UART */ + pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + + /* MSB UART */ + pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + + /* irq number, this usually fails, but the spec says to do it anyway. */ + pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + + port->port.iotype = UPIO_PORT; + port->port.iobase = iobase; + port->port.mapbase = 0; + port->port.membase = NULL; + port->port.regshift = 0; + + return 0; +} + static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { port->port.flags |= UPF_NO_TXEN_TEST; - printk(KERN_DEBUG "serial8250: skipping TxEn test for device " - "[%04x:%04x] subsystem [%04x:%04x]\n", - priv->dev->vendor, - priv->dev->device, - priv->dev->subsystem_vendor, - priv->dev->subsystem_device); + dev_dbg(&priv->dev->dev, + "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", + priv->dev->vendor, priv->dev->device, + priv->dev->subsystem_vendor, priv->dev->subsystem_device); return pci_default_setup(priv, board, port, idx); } @@ -1533,6 +1753,8 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_VENDOR_ID_ADVANTECH 0x13fe #define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66 #define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620 +#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618 +#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618 #define PCI_DEVICE_ID_TITAN_200I 0x8028 #define PCI_DEVICE_ID_TITAN_400I 0x8048 #define PCI_DEVICE_ID_TITAN_800I 0x8088 @@ -1545,6 +1767,7 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_TITAN_800E 0xA014 #define PCI_DEVICE_ID_TITAN_200EI 0xA016 #define PCI_DEVICE_ID_TITAN_200EISI 0xA017 +#define PCI_DEVICE_ID_TITAN_200V3 0xA306 #define PCI_DEVICE_ID_TITAN_400V3 0xA310 #define PCI_DEVICE_ID_TITAN_410V3 0xA312 #define PCI_DEVICE_ID_TITAN_800V3 0xA314 @@ -1557,6 +1780,7 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_WCH_CH352_2S 0x3253 #define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 +#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 #define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 @@ -1662,6 +1886,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = kt_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, /* * ITE */ @@ -1826,6 +2064,31 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .exit = pci_plx9050_exit, }, /* + * Pericom + */ + { + .vendor = 0x12d8, + .device = 0x7952, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = 0x12d8, + .device = 0x7954, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = 0x12d8, + .device = 0x7958, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + + /* * PLX */ { @@ -2150,6 +2413,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_omegapci_setup, }, + /* WCH CH353 1S1P card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_1S1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, /* WCH CH353 2S1P card (16550 clone) */ { .vendor = PCI_VENDOR_ID_WCH, @@ -2255,6 +2526,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_brcm_trumanage_setup, }, + { + .vendor = 0x1c29, + .device = 0x1104, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1108, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1112, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, /* * Default "match everything" terminator entry @@ -2449,9 +2741,13 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_4_3906250, pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, + pbn_byt, pbn_omegapci, pbn_NETMOS9900_2s_115200, pbn_brcm_trumanage, + pbn_fintek_4, + pbn_fintek_8, + pbn_fintek_12, }; /* @@ -3185,6 +3481,17 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .reg_shift = 2, }, + /* + * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on, + * but is overridden by byt_set_termios. + */ + [pbn_byt] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 2764800, + .uart_offset = 0x80, + .reg_shift = 2, + }, [pbn_omegapci] = { .flags = FL_BASE0, .num_ports = 8, @@ -3202,6 +3509,24 @@ static struct pciserial_board pci_boards[] = { .reg_shift = 2, .base_baud = 115200, }, + [pbn_fintek_4] = { + .num_ports = 4, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, + [pbn_fintek_8] = { + .num_ports = 8, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, + [pbn_fintek_12] = { + .num_ports = 12, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, }; static const struct pci_device_id blacklist[] = { @@ -3212,6 +3537,7 @@ static const struct pci_device_id blacklist[] = { /* multi-io cards handled by parport_serial */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ + { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ }; /* @@ -3362,14 +3688,15 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) if (quirk->setup(priv, board, &uart, i)) break; -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n", - uart.port.iobase, uart.port.irq, uart.port.iotype); -#endif + dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype); priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); + dev_err(&dev->dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, + uart.port.iotype, priv->line[i]); break; } } @@ -3462,7 +3789,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", + dev_err(&dev->dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } @@ -3520,8 +3847,6 @@ static void pciserial_remove_one(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); - pci_set_drvdata(dev, NULL); - pciserial_remove_ports(priv); pci_disable_device(dev); @@ -3555,7 +3880,7 @@ static int pciserial_resume_one(struct pci_dev *dev) err = pci_enable_device(dev); /* FIXME: We cannot simply error out here */ if (err) - printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); + dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; @@ -3567,6 +3892,13 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, pbn_b2_8_921600 }, + /* Advantech also use 0x3618 and 0xf618 */ + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618, + PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618, + PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, @@ -4140,6 +4472,9 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi_2_4000000 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, @@ -4848,6 +5183,15 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_ce4100_1_115200 }, + /* Intel BayTrail */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, /* * Cronyx Omega PCI @@ -4918,6 +5262,11 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_exar_XR17V358 }, + /* Fintek PCI serial cards */ + { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, + { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, + { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index 35d9ab95c5c..682a2fbe5c0 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -12,7 +12,6 @@ * the Free Software Foundation; either version 2 of the License. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/pnp.h> #include <linux/string.h> diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f3b306efaa5..349ee598b34 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -41,7 +41,7 @@ config SERIAL_8250_DEPRECATED_OPTIONS accept kernel parameters in both forms like 8250_core.nr_uarts=4 and 8250.nr_uarts=4. We now renamed the module back to 8250, but if anybody noticed in 3.7 and changed their userspace we still have to - keep the 8350_core.* options around until they revert the changes + keep the 8250_core.* options around until they revert the changes they already did. If 8250 is built as a module, this adds 8250_core alias instead. @@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE bool "Console on 8250/16550 and compatible serial port" depends on SERIAL_8250=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON ---help--- If you say Y here, it will be possible to use a serial port as the system console (the system console is the device which receives all @@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE If unsure, say N. -config FIX_EARLYCON_MEM - bool - depends on X86 - default y - config SERIAL_8250_GSC tristate depends on SERIAL_8250 && GSC diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 1b74b88e1e1..4d180c9423e 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -34,7 +34,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index febd45cd502..fb57159bad3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -7,6 +7,13 @@ if TTY menu "Serial drivers" depends on HAS_IOMEM +config SERIAL_EARLYCON + bool + help + Support for early consoles with the earlycon parameter. This enables + the console before standard serial driver is probed. The console is + enabled when early_param is processed. + source "drivers/tty/serial/8250/Kconfig" comment "Non-8250 serial port support" @@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE bool "Support for console on AMBA serial port" depends on SERIAL_AMBA_PL011=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON ---help--- Say Y here if you wish to use an AMBA PrimeCell UART as the system console (the system console is the device which receives all kernel @@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_EARLYCON_ARM_SEMIHOST + bool "Early console using ARM semihosting" + depends on ARM64 || ARM + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Support for early debug console using ARM semihosting. This enables + the console before standard serial driver is probed. This is enabled + with "earlycon=smh" on the kernel command line. The console is + enabled when early_param is processed. + config SERIAL_SB1250_DUART tristate "BCM1xxx on-chip DUART serial support" depends on SIBYTE_SB1xxx_SOC=y @@ -97,6 +117,7 @@ config SERIAL_ATMEL bool "AT91 / AT32 on-chip serial port support" depends on ARCH_AT91 || AVR32 select SERIAL_CORE + select SERIAL_MCTRL_GPIO help This enables the driver for the on-chip UARTs of the Atmel AT91 and AT32 processors. @@ -181,9 +202,8 @@ config SERIAL_KS8695_CONSOLE config SERIAL_CLPS711X tristate "CLPS711X serial port support" - depends on ARCH_CLPS711X + depends on ARCH_CLPS711X || COMPILE_TEST select SERIAL_CORE - default y help This enables the driver for the on-chip UARTs of the Cirrus Logic EP711x/EP721x/EP731x processors. @@ -290,7 +310,7 @@ config SERIAL_MAX3100 MAX3100 chip support config SERIAL_MAX310X - bool "MAX310X support" + tristate "MAX310X support" depends on SPI_MASTER select SERIAL_CORE select REGMAP_SPI if SPI_MASTER @@ -709,7 +729,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on HAVE_CLK && (SUPERH || ARCH_SHMOBILE) + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS @@ -1025,7 +1045,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE @@ -1035,7 +1055,7 @@ config SERIAL_MSM_CONSOLE config SERIAL_MSM_HS tristate "MSM UART High Speed: Serial Driver" - depends on ARCH_MSM + depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 select SERIAL_CORE help If you have a machine based on MSM family of SoCs, you @@ -1146,31 +1166,13 @@ config SERIAL_QE This driver supports the QE serial ports on Freescale embedded PowerPC that contain a QUICC Engine. -config SERIAL_SC26XX - tristate "SC2681/SC2692 serial port support" - depends on SNI_RM - select SERIAL_CORE - help - This is a driver for the onboard serial ports of - older RM400 machines. - -config SERIAL_SC26XX_CONSOLE - bool "Console on SC2681/SC2692 serial port" - depends on SERIAL_SC26XX=y - select SERIAL_CORE_CONSOLE - help - Support for Console on SC2681/SC2692 serial ports. - config SERIAL_SCCNXP tristate "SCCNXP serial port support" - depends on !SERIAL_SC26XX select SERIAL_CORE - default n help This selects support for an advanced UART from NXP (Philips). Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92, SC28L202, SCC68681 and SCC68692. - Positioned as a replacement for the driver SC26XX. config SERIAL_SCCNXP_CONSOLE bool "Console on SCCNXP serial port" @@ -1179,6 +1181,16 @@ config SERIAL_SCCNXP_CONSOLE help Support for console on SCCNXP serial ports. +config SERIAL_SC16IS7XX + tristate "SC16IS7xx serial support" + depends on I2C + select SERIAL_CORE + select REGMAP_I2C if I2C + help + This selects support for SC16IS7xx serial ports. + Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, + SC16IS760 and SC16IS762. + config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" depends on BLACKFIN @@ -1245,6 +1257,7 @@ config SERIAL_BFIN_SPORT3_UART_CTSRTS config SERIAL_TIMBERDALE tristate "Support for timberdale UART" select SERIAL_CORE + depends on X86_32 || COMPILE_TEST ---help--- Add support for UART controller on timberdale. @@ -1341,7 +1354,7 @@ config SERIAL_IFX6X60 config SERIAL_PCH_UART tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) select SERIAL_CORE help This driver is for PCH(Platform controller Hub) UART of Intel EG20T @@ -1387,18 +1400,19 @@ config SERIAL_MXS_AUART_CONSOLE Enable a MXS AUART port to be the system console. config SERIAL_XILINX_PS_UART - tristate "Xilinx PS UART support" + tristate "Cadence (Xilinx Zynq) UART support" depends on OF select SERIAL_CORE help - This driver supports the Xilinx PS UART port. + This driver supports the Cadence UART. It is found e.g. in Xilinx + Zynq. config SERIAL_XILINX_PS_UART_CONSOLE - bool "Xilinx PS UART console support" + bool "Cadence UART console support" depends on SERIAL_XILINX_PS_UART=y select SERIAL_CORE_CONSOLE help - Enable a Xilinx PS UART port to be the system console. + Enable a Cadence UART port to be the system console. config SERIAL_AR933X tristate "AR933X serial port support" @@ -1497,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS config SERIAL_FSL_LPUART tristate "Freescale lpuart serial port support" + depends on HAS_DMA select SERIAL_CORE help Support for the on-chip lpuart on some Freescale SOCs. @@ -1512,6 +1527,7 @@ config SERIAL_FSL_LPUART_CONSOLE config SERIAL_ST_ASC tristate "ST ASC serial port support" select SERIAL_CORE + depends on ARM || COMPILE_TEST help This driver is for the on-chip Asychronous Serial Controller on STMicroelectronics STi SoCs. @@ -1525,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE depends on SERIAL_ST_ASC=y select SERIAL_CORE_CONSOLE +config SERIAL_MEN_Z135 + tristate "MEN 16z135 Support" + select SERIAL_CORE + depends on MCB + help + Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core + on a MCB carrier. + + This driver can also be build as a module. If so, the module will be called + men_z135_uart.ko + endmenu +config SERIAL_MCTRL_GPIO + tristate + endif # TTY diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 3068c772208..0080cc362e0 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o +obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o +obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o + # These Sparc drivers have to appear before others such as 8250 # which share ttySx minor node space. Otherwise console device # names change and other unplesantries. @@ -47,8 +50,8 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o -obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o +obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -88,3 +91,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o obj-$(CONFIG_SERIAL_RP2) += rp2.o obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o +obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o + +# GPIOLIB helpers for modem control lines +obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 501667e3e3f..323376668b7 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -185,6 +185,12 @@ static void altera_uart_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); spin_unlock_irqrestore(&port->lock, flags); + + /* + * FIXME: port->read_status_mask and port->ignore_status_mask + * need to be initialized based on termios settings for + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT + */ } static void altera_uart_rx_chars(struct altera_uart *pp) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 8b90f0b6dfd..971af1e22d0 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -420,7 +420,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, uap->port.read_status_mask = UART01x_RSR_OE; if (termios->c_iflag & INPCK) uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uap->port.read_status_mask |= UART01x_RSR_BE; /* @@ -728,7 +728,6 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id) amba_set_drvdata(dev, uap); ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { - amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; clk_put(uap->clk); unmap: @@ -745,8 +744,6 @@ static int pl010_remove(struct amba_device *dev) struct uart_amba_port *uap = amba_get_drvdata(dev); int i; - amba_set_drvdata(dev, NULL); - uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) @@ -759,9 +756,10 @@ static int pl010_remove(struct amba_device *dev) return 0; } -static int pl010_suspend(struct amba_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pl010_suspend(struct device *dev) { - struct uart_amba_port *uap = amba_get_drvdata(dev); + struct uart_amba_port *uap = dev_get_drvdata(dev); if (uap) uart_suspend_port(&amba_reg, &uap->port); @@ -769,15 +767,18 @@ static int pl010_suspend(struct amba_device *dev, pm_message_t state) return 0; } -static int pl010_resume(struct amba_device *dev) +static int pl010_resume(struct device *dev) { - struct uart_amba_port *uap = amba_get_drvdata(dev); + struct uart_amba_port *uap = dev_get_drvdata(dev); if (uap) uart_resume_port(&amba_reg, &uap->port); return 0; } +#endif + +static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume); static struct amba_id pl010_ids[] = { { @@ -792,12 +793,11 @@ MODULE_DEVICE_TABLE(amba, pl010_ids); static struct amba_driver pl010_driver = { .drv = { .name = "uart-pl010", + .pm = &pl010_dev_pm_ops, }, .id_table = pl010_ids, .probe = pl010_probe, .remove = pl010_remove, - .suspend = pl010_suspend, - .resume = pl010_resume, }; static int __init pl010_init(void) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index aaa22867e65..0e26dcbd5ea 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -112,8 +112,6 @@ static struct vendor_data vendor_st = { .get_fifosize = get_fifosize_st, }; -static struct uart_amba_port *amba_ports[UART_NR]; - /* Deals with DMA transactions */ struct pl011_sgbuf { @@ -305,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * /* Optionally make use of an RX channel as well */ chan = dma_request_slave_channel(dev, "rx"); - + if (!chan && plat->dma_rx_param) { chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param); @@ -320,7 +318,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, - .src_maxburst = uap->fifosize >> 1, + .src_maxburst = uap->fifosize >> 2, .device_fc = false, }; @@ -969,6 +967,8 @@ static void pl011_dma_rx_poll(unsigned long args) spin_lock_irqsave(&uap->port.lock, flags); pl011_dma_rx_stop(uap); + uap->im |= UART011_RXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); spin_unlock_irqrestore(&uap->port.lock, flags); uap->dmarx.running = false; @@ -1216,8 +1216,8 @@ __acquires(&uap->port.lock) dev_dbg(uap->port.dev, "could not trigger RX DMA job " "fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); } else { - uap->im &= ~UART011_RXIM; #ifdef CONFIG_DMA_ENGINE /* Start Rx DMA poll */ if (uap->dmarx.poll_rate) { @@ -1229,8 +1229,6 @@ __acquires(&uap->port.lock) } #endif } - - writew(uap->im, uap->port.membase + UART011_IMSC); } spin_lock(&uap->port.lock); } @@ -1513,10 +1511,25 @@ static int pl011_hwinit(struct uart_port *port) return retval; } +static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) +{ + writew(lcr_h, uap->port.membase + uap->lcrh_rx); + if (uap->lcrh_rx != uap->lcrh_tx) { + int i; + /* + * Wait 10 PCLKs before writing LCRH_TX register, + * to get this delay write read only register 10 times + */ + for (i = 0; i < 10; ++i) + writew(0xff, uap->port.membase + UART011_MIS); + writew(lcr_h, uap->port.membase + uap->lcrh_tx); + } +} + static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; - unsigned int cr; + unsigned int cr, lcr_h, fbrd, ibrd; int retval; retval = pl011_hwinit(port); @@ -1535,32 +1548,36 @@ static int pl011_startup(struct uart_port *port) writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); /* - * Provoke TX FIFO interrupt into asserting. + * Provoke TX FIFO interrupt into asserting. Taking care to preserve + * baud rate and data format specified by FBRD, IBRD and LCRH as the + * UART may already be in use as a console. */ + spin_lock_irq(&uap->port.lock); + + fbrd = readw(uap->port.membase + UART011_FBRD); + ibrd = readw(uap->port.membase + UART011_IBRD); + lcr_h = readw(uap->port.membase + uap->lcrh_rx); + cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE; writew(cr, uap->port.membase + UART011_CR); writew(0, uap->port.membase + UART011_FBRD); writew(1, uap->port.membase + UART011_IBRD); - writew(0, uap->port.membase + uap->lcrh_rx); - if (uap->lcrh_tx != uap->lcrh_rx) { - int i; - /* - * Wait 10 PCLKs before writing LCRH_TX register, - * to get this delay write read only register 10 times - */ - for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + UART011_MIS); - writew(0, uap->port.membase + uap->lcrh_tx); - } + pl011_write_lcr_h(uap, 0); writew(0, uap->port.membase + UART01x_DR); while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) barrier(); + writew(fbrd, uap->port.membase + UART011_FBRD); + writew(ibrd, uap->port.membase + UART011_IBRD); + pl011_write_lcr_h(uap, lcr_h); + /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); + spin_unlock_irq(&uap->port.lock); + /* * initialise the old status of the modem signals */ @@ -1629,11 +1646,13 @@ static void pl011_shutdown(struct uart_port *port) * it during startup(). */ uap->autorts = false; + spin_lock_irq(&uap->port.lock); cr = readw(uap->port.membase + UART011_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); + spin_unlock_irq(&uap->port.lock); /* * disable break condition and fifos @@ -1725,7 +1744,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = UART011_DR_OE | 255; if (termios->c_iflag & INPCK) port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART011_DR_BE; /* @@ -1797,17 +1816,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * UART011_FBRD & UART011_IBRD. * ----------^----------^----------^----------^----- */ - writew(lcr_h, port->membase + uap->lcrh_rx); - if (uap->lcrh_rx != uap->lcrh_tx) { - int i; - /* - * Wait 10 PCLKs before writing LCRH_TX register, - * to get this delay write read only register 10 times - */ - for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + UART011_MIS); - writew(lcr_h, port->membase + uap->lcrh_tx); - } + pl011_write_lcr_h(uap, lcr_h); writew(old_cr, port->membase + UART011_CR); spin_unlock_irqrestore(&port->lock, flags); @@ -2036,6 +2045,35 @@ static struct console amba_console = { }; #define AMBA_CONSOLE (&amba_console) + +static void pl011_putc(struct uart_port *port, int c) +{ + while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + ; + writeb(c, port->membase + UART01x_DR); + while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) + ; +} + +static void pl011_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, pl011_putc); +} + +static int __init pl011_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = pl011_early_write; + return 0; +} +EARLYCON_DECLARE(pl011, pl011_early_console_setup); +OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); + #else #define AMBA_CONSOLE NULL #endif @@ -2145,10 +2183,19 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) amba_ports[i] = uap; amba_set_drvdata(dev, uap); + + if (!amba_reg.state) { + ret = uart_register_driver(&amba_reg); + if (ret < 0) { + pr_err("Failed to register AMBA-PL011 driver\n"); + return ret; + } + } + ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { - amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; + uart_unregister_driver(&amba_reg); pl011_dma_remove(uap); } out: @@ -2158,24 +2205,27 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) static int pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); + bool busy = false; int i; - amba_set_drvdata(dev, NULL); - uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) if (amba_ports[i] == uap) amba_ports[i] = NULL; + else if (amba_ports[i]) + busy = true; pl011_dma_remove(uap); + if (!busy) + uart_unregister_driver(&amba_reg); return 0; } -#ifdef CONFIG_PM -static int pl011_suspend(struct amba_device *dev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pl011_suspend(struct device *dev) { - struct uart_amba_port *uap = amba_get_drvdata(dev); + struct uart_amba_port *uap = dev_get_drvdata(dev); if (!uap) return -EINVAL; @@ -2183,9 +2233,9 @@ static int pl011_suspend(struct amba_device *dev, pm_message_t state) return uart_suspend_port(&amba_reg, &uap->port); } -static int pl011_resume(struct amba_device *dev) +static int pl011_resume(struct device *dev) { - struct uart_amba_port *uap = amba_get_drvdata(dev); + struct uart_amba_port *uap = dev_get_drvdata(dev); if (!uap) return -EINVAL; @@ -2194,6 +2244,8 @@ static int pl011_resume(struct amba_device *dev) } #endif +static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); + static struct amba_id pl011_ids[] = { { .id = 0x00041011, @@ -2213,34 +2265,23 @@ MODULE_DEVICE_TABLE(amba, pl011_ids); static struct amba_driver pl011_driver = { .drv = { .name = "uart-pl011", + .pm = &pl011_dev_pm_ops, }, .id_table = pl011_ids, .probe = pl011_probe, .remove = pl011_remove, -#ifdef CONFIG_PM - .suspend = pl011_suspend, - .resume = pl011_resume, -#endif }; static int __init pl011_init(void) { - int ret; printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); - ret = uart_register_driver(&amba_reg); - if (ret == 0) { - ret = amba_driver_register(&pl011_driver); - if (ret) - uart_unregister_driver(&amba_reg); - } - return ret; + return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { amba_driver_unregister(&pl011_driver); - uart_unregister_driver(&amba_reg); } /* diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 569872f4c9b..008c223eaf2 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -177,7 +177,7 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart) uart->port.icount.tx++; uart->port.x_char = 0; sent = 1; - } else if (xmit->tail != xmit->head) { /* TODO: uart_circ_empty */ + } else if (!uart_circ_empty(xmit)) { ch = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); uart->port.icount.tx++; @@ -533,7 +533,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) unsigned long *plat_data; struct arc_uart_port *uart = &arc_uart_ports[dev_id]; - plat_data = (unsigned long *)dev_get_platdata(&pdev->dev); + plat_data = dev_get_platdata(&pdev->dev); if (!plat_data) return -ENODEV; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d067285a2d2..c4f75031410 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -35,21 +35,21 @@ #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/dma-mapping.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> #include <linux/uaccess.h> #include <linux/platform_data/atmel.h> #include <linux/timer.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/err.h> +#include <linux/irq.h> #include <asm/io.h> #include <asm/ioctls.h> -#ifdef CONFIG_ARM -#include <mach/cpu.h> -#include <asm/gpio.h> -#endif - #define PDC_BUFFER_SIZE 512 /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ @@ -60,6 +60,8 @@ #include <linux/serial_core.h> +#include "serial_mctrl_gpio.h" + static void atmel_start_rx(struct uart_port *port); static void atmel_stop_rx(struct uart_port *port); @@ -99,6 +101,7 @@ static void atmel_stop_rx(struct uart_port *port); #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) #define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) #define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME) +#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION) /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) @@ -114,9 +117,6 @@ static void atmel_stop_rx(struct uart_port *port); #define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) #define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) -static int (*atmel_open_hook)(struct uart_port *); -static void (*atmel_close_hook)(struct uart_port *); - struct atmel_dma_buffer { unsigned char *buf; dma_addr_t dma_addr; @@ -167,7 +167,10 @@ 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; + bool ms_irq_enabled; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ int (*prepare_rx)(struct uart_port *port); @@ -241,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port) return atmel_port->use_dma_rx; } +static unsigned int atmel_get_lines_status(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status, ret = 0; + + status = UART_GET_CSR(port); + + mctrl_gpio_get(atmel_port->gpios, &ret); + + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, + UART_GPIO_CTS))) { + if (ret & TIOCM_CTS) + status &= ~ATMEL_US_CTS; + else + status |= ATMEL_US_CTS; + } + + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, + UART_GPIO_DSR))) { + if (ret & TIOCM_DSR) + status &= ~ATMEL_US_DSR; + else + status |= ATMEL_US_DSR; + } + + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, + UART_GPIO_RI))) { + if (ret & TIOCM_RI) + status &= ~ATMEL_US_RI; + else + status |= ATMEL_US_RI; + } + + if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, + UART_GPIO_DCD))) { + if (ret & TIOCM_CD) + status &= ~ATMEL_US_DCD; + else + status |= ATMEL_US_DCD; + } + + return status; +} + /* Enable or disable the rs485 support */ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) { @@ -300,21 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) unsigned int mode; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); -#ifdef CONFIG_ARCH_AT91RM9200 - if (cpu_is_at91rm9200()) { - /* - * AT91RM9200 Errata #39: RTS0 is not internally connected - * to PA21. We need to drive the pin manually. - */ - if (port->mapbase == AT91RM9200_BASE_US0) { - if (mctrl & TIOCM_RTS) - at91_set_gpio_value(AT91_PIN_PA21, 0); - else - at91_set_gpio_value(AT91_PIN_PA21, 1); - } - } -#endif - if (mctrl & TIOCM_RTS) control |= ATMEL_US_RTSEN; else @@ -327,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) UART_PUT_CR(port, control); + mctrl_gpio_set(atmel_port->gpios, mctrl); + /* Local loopback mode? */ mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE; if (mctrl & TIOCM_LOOP) @@ -354,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) */ static u_int atmel_get_mctrl(struct uart_port *port) { - unsigned int status, ret = 0; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int ret = 0, status; status = UART_GET_CSR(port); @@ -370,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port) if (!(status & ATMEL_US_RI)) ret |= TIOCM_RI; - return ret; + return mctrl_gpio_get(atmel_port->gpios, &ret); } /* @@ -457,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port) */ static void atmel_enable_ms(struct uart_port *port) { - UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC - | ATMEL_US_DCDIC | ATMEL_US_CTSIC); + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + uint32_t ier = 0; + + /* + * Interrupt should not be enabled twice + */ + if (atmel_port->ms_irq_enabled) + return; + + atmel_port->ms_irq_enabled = true; + + if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0) + enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]); + else + ier |= ATMEL_US_CTSIC; + + if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0) + enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]); + else + ier |= ATMEL_US_DSRIC; + + if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0) + enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]); + else + ier |= ATMEL_US_RIIC; + + if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0) + enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]); + else + ier |= ATMEL_US_DCDIC; + + UART_PUT_IER(port, ier); } /* @@ -824,9 +889,6 @@ static void atmel_release_rx_dma(struct uart_port *port) atmel_port->desc_rx = NULL; atmel_port->chan_rx = NULL; atmel_port->cookie_rx = -EINVAL; - - if (!atmel_port->is_usart) - del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_dma(struct uart_port *port) @@ -1050,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, static irqreturn_t atmel_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, pending, pass_counter = 0; + bool gpio_handled = false; do { - status = UART_GET_CSR(port); + status = atmel_get_lines_status(port); pending = status & UART_GET_IMR(port); + if (!gpio_handled) { + /* + * Dealing with GPIO interrupt + */ + if (irq == atmel_port->gpio_irq[UART_GPIO_CTS]) + pending |= ATMEL_US_CTSIC; + + if (irq == atmel_port->gpio_irq[UART_GPIO_DSR]) + pending |= ATMEL_US_DSRIC; + + if (irq == atmel_port->gpio_irq[UART_GPIO_RI]) + pending |= ATMEL_US_RIIC; + + if (irq == atmel_port->gpio_irq[UART_GPIO_DCD]) + pending |= ATMEL_US_DCDIC; + + gpio_handled = true; + } if (!pending) break; @@ -1228,9 +1310,6 @@ static void atmel_release_rx_pdc(struct uart_port *port) DMA_FROM_DEVICE); kfree(pdc->buf); } - - if (!atmel_port->is_usart) - del_timer_sync(&atmel_port->uart_timer); } static void atmel_rx_from_pdc(struct uart_port *port) @@ -1499,10 +1578,11 @@ static void atmel_set_ops(struct uart_port *port) /* * Get ip name usart or uart */ -static int atmel_get_ip_name(struct uart_port *port) +static void atmel_get_ip_name(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int name = UART_GET_IP_NAME(port); + u32 version; int usart, uart; /* usart and uart ascii */ usart = 0x55534152; @@ -1517,11 +1597,62 @@ static int atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "This is uart\n"); atmel_port->is_usart = false; } else { - dev_err(port->dev, "Not supported ip name, set to uart\n"); - return -EINVAL; + /* fallback for older SoCs: use version field */ + version = UART_GET_IP_VERSION(port); + switch (version) { + case 0x302: + case 0x10213: + dev_dbg(port->dev, "This version is usart\n"); + atmel_port->is_usart = true; + break; + case 0x203: + case 0x10202: + dev_dbg(port->dev, "This version is uart\n"); + atmel_port->is_usart = false; + break; + default: + dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); + } } +} - return 0; +static void atmel_free_gpio_irq(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + enum mctrl_gpio_idx i; + + for (i = 0; i < UART_GPIO_MAX; i++) + if (atmel_port->gpio_irq[i] >= 0) + free_irq(atmel_port->gpio_irq[i], port); +} + +static int atmel_request_gpio_irq(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + int *irq = atmel_port->gpio_irq; + enum mctrl_gpio_idx i; + int err = 0; + + for (i = 0; (i < UART_GPIO_MAX) && !err; i++) { + if (irq[i] < 0) + continue; + + irq_set_status_flags(irq[i], IRQ_NOAUTOEN); + err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH, + "atmel_serial", port); + if (err) + dev_err(port->dev, "atmel_startup - Can't get %d irq\n", + irq[i]); + } + + /* + * If something went wrong, rollback. + */ + while (err && (--i >= 0)) + if (irq[i] >= 0) + free_irq(irq[i], port); + + return err; } /* @@ -1540,6 +1671,7 @@ static int atmel_startup(struct uart_port *port) * handle an unexpected interrupt */ UART_PUT_IDR(port, -1); + atmel_port->ms_irq_enabled = false; /* * Allocate the IRQ @@ -1547,11 +1679,18 @@ static int atmel_startup(struct uart_port *port) retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, tty ? tty->name : "atmel_serial", port); if (retval) { - printk("atmel_serial: atmel_startup - Can't get irq\n"); + dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; } /* + * Get the GPIO lines IRQ + */ + retval = atmel_request_gpio_irq(port); + if (retval) + goto free_irq; + + /* * Initialize DMA (if necessary) */ atmel_init_property(atmel_port, pdev); @@ -1567,20 +1706,9 @@ static int atmel_startup(struct uart_port *port) if (retval < 0) atmel_set_ops(port); } - /* - * If there is a specific "open" function (to register - * control line interrupts) - */ - if (atmel_open_hook) { - retval = atmel_open_hook(port); - if (retval) { - free_irq(port->irq, port); - return retval; - } - } /* Save current CSR for comparison in atmel_tasklet_func() */ - atmel_port->irq_status_prev = UART_GET_CSR(port); + atmel_port->irq_status_prev = atmel_get_lines_status(port); atmel_port->irq_status = atmel_port->irq_status_prev; /* @@ -1590,12 +1718,13 @@ static int atmel_startup(struct uart_port *port) /* enable xmit & rcvr */ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + setup_timer(&atmel_port->uart_timer, + atmel_uart_timer_callback, + (unsigned long)port); + if (atmel_use_pdc_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { - setup_timer(&atmel_port->uart_timer, - atmel_uart_timer_callback, - (unsigned long)port); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ @@ -1610,9 +1739,6 @@ static int atmel_startup(struct uart_port *port) } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { - setup_timer(&atmel_port->uart_timer, - atmel_uart_timer_callback, - (unsigned long)port); mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); /* set USART timeout */ @@ -1628,6 +1754,11 @@ static int atmel_startup(struct uart_port *port) } return 0; + +free_irq: + free_irq(port->irq, port); + + return retval; } /* @@ -1636,12 +1767,30 @@ static int atmel_startup(struct uart_port *port) static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + /* + * Prevent any tasklets being scheduled during + * cleanup + */ + del_timer_sync(&atmel_port->uart_timer); + + /* + * Clear out any scheduled tasklets before + * we destroy the buffers + */ + tasklet_kill(&atmel_port->tasklet); + /* - * Ensure everything is stopped. + * Ensure everything is stopped and + * disable all interrupts, port and break condition. */ atmel_stop_rx(port); atmel_stop_tx(port); + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, -1); + + /* * Shut-down the DMA. */ @@ -1651,22 +1800,18 @@ static void atmel_shutdown(struct uart_port *port) atmel_port->release_tx(port); /* - * Disable all interrupts, port and break condition. + * Reset ring buffer pointers */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); + atmel_port->rx_ring.head = 0; + atmel_port->rx_ring.tail = 0; /* - * Free the interrupt + * Free the interrupts */ free_irq(port->irq, port); + atmel_free_gpio_irq(port); - /* - * If there is a specific "close" function (to unregister - * control line interrupts) - */ - if (atmel_close_hook) - atmel_close_hook(port); + atmel_port->ms_irq_enabled = false; } /* @@ -1714,7 +1859,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, clk_disable_unprepare(atmel_port->clk); break; default: - printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); + dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); } } @@ -1787,7 +1932,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= ATMEL_US_RXBRK; if (atmel_use_pdc_rx(port)) @@ -1829,13 +1974,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, mode &= ~ATMEL_US_USMODE; if (atmel_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); mode |= ATMEL_US_USMODE_RS485; - } else { - dev_dbg(port->dev, "Setting UART to RS232\n"); } /* set the parity, stop bits and data size */ @@ -2330,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev) #define atmel_serial_resume NULL #endif +static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) +{ + enum mctrl_gpio_idx i; + struct gpio_desc *gpiod; + + p->gpios = mctrl_gpio_init(dev, 0); + if (IS_ERR_OR_NULL(p->gpios)) + return -1; + + for (i = 0; i < UART_GPIO_MAX; i++) { + gpiod = mctrl_gpio_to_gpiod(p->gpios, i); + if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN)) + p->gpio_irq[i] = gpiod_to_irq(gpiod); + else + p->gpio_irq[i] = -EINVAL; + } + + return 0; +} + static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; @@ -2366,6 +2528,11 @@ static int atmel_serial_probe(struct platform_device *pdev) port->backup_imr = 0; port->uart.line = ret; + ret = atmel_init_gpios(port, &pdev->dev); + if (ret < 0) + dev_err(&pdev->dev, "%s", + "Failed to initialize GPIOs. The serial port may not work as expected"); + ret = atmel_init_port(port, pdev); if (ret) goto err; @@ -2405,9 +2572,7 @@ static int atmel_serial_probe(struct platform_device *pdev) /* * Get port name of usart or uart */ - ret = atmel_get_ip_name(&port->uart); - if (ret < 0) - goto err_add_port; + atmel_get_ip_name(&port->uart); return 0; @@ -2429,11 +2594,12 @@ static int atmel_serial_remove(struct platform_device *pdev) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; + tasklet_kill(&atmel_port->tasklet); + device_init_wakeup(&pdev->dev, 0); ret = uart_remove_one_port(&atmel_uart, port); - tasklet_kill(&atmel_port->tasklet); kfree(atmel_port->rx_ring.buf); /* "port" is allocated statically, so we shouldn't free it */ diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 649d5129c4b..231519022b7 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -29,10 +29,9 @@ #include <linux/sysrq.h> #include <linux/serial.h> #include <linux/serial_core.h> - -#include <bcm63xx_irq.h> -#include <bcm63xx_regs.h> -#include <bcm63xx_io.h> +#include <linux/serial_bcm63xx.h> +#include <linux/io.h> +#include <linux/of.h> #define BCM63XX_NR_UARTS 2 @@ -81,13 +80,13 @@ static struct uart_port ports[BCM63XX_NR_UARTS]; static inline unsigned int bcm_uart_readl(struct uart_port *port, unsigned int offset) { - return bcm_readl(port->membase + offset); + return __raw_readl(port->membase + offset); } static inline void bcm_uart_writel(struct uart_port *port, unsigned int value, unsigned int offset) { - bcm_writel(value, port->membase + offset); + __raw_writel(value, port->membase + offset); } /* @@ -568,7 +567,7 @@ static void bcm_uart_set_termios(struct uart_port *port, port->read_status_mask |= UART_FIFO_FRAMEERR_MASK; port->read_status_mask |= UART_FIFO_PARERR_MASK; } - if (new->c_iflag & (BRKINT)) + if (new->c_iflag & (IGNBRK | BRKINT)) port->read_status_mask |= UART_FIFO_BRKDET_MASK; port->ignore_status_mask = 0; @@ -591,7 +590,7 @@ static int bcm_uart_request_port(struct uart_port *port) { unsigned int size; - size = RSET_UART_SIZE; + size = UART_REG_SIZE; if (!request_mem_region(port->mapbase, size, "bcm63xx")) { dev_err(port->dev, "Memory region busy\n"); return -EBUSY; @@ -611,7 +610,7 @@ static int bcm_uart_request_port(struct uart_port *port) */ static void bcm_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, RSET_UART_SIZE); + release_mem_region(port->mapbase, UART_REG_SIZE); iounmap(port->membase); } @@ -808,6 +807,9 @@ static int bcm_uart_probe(struct platform_device *pdev) struct clk *clk; int ret; + if (pdev->dev.of_node) + pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); + if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) return -EINVAL; @@ -859,6 +861,12 @@ static int bcm_uart_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id bcm63xx_of_match[] = { + { .compatible = "brcm,bcm6345-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm63xx_of_match); + /* * platform driver stuff */ @@ -868,6 +876,7 @@ static struct platform_driver bcm_uart_platform_driver = { .driver = { .owner = THIS_MODULE, .name = "bcm63xx_uart", + .of_match_table = bcm63xx_of_match, }, }; diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 87636cc61a2..4f229703328 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -766,9 +766,8 @@ static int sport_uart_probe(struct platform_device *pdev) return -ENOMEM; } - ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), - DRV_NAME); + ret = peripheral_request_list(dev_get_platdata(&pdev->dev), + DRV_NAME); if (ret) { dev_err(&pdev->dev, "Fail to request SPORT peripherals\n"); @@ -844,8 +843,7 @@ static int sport_uart_probe(struct platform_device *pdev) out_error_unmap: iounmap(sport->port.membase); out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); out_error_free_mem: kfree(sport); bfin_sport_uart_ports[pdev->id] = NULL; @@ -864,8 +862,7 @@ static int sport_uart_remove(struct platform_device *pdev) if (sport) { uart_remove_one_port(&sport_uart_reg, &sport->port); iounmap(sport->port.membase); - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); kfree(sport); bfin_sport_uart_ports[pdev->id] = NULL; } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 3c75e8e0402..ac86a20992e 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -680,7 +680,7 @@ static int bfin_serial_startup(struct uart_port *port) default: uart_dma_ch_rx = uart_dma_ch_tx = 0; break; - }; + } if (uart_dma_ch_rx && request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { @@ -726,7 +726,7 @@ static int bfin_serial_startup(struct uart_port *port) #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, - IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + 0, "BFIN_UART_MODEM_STATUS", uart)) { uart->cts_pin = -1; dev_info(port->dev, "Unable to attach BlackFin UART Modem Status interrupt.\n"); } @@ -765,7 +765,7 @@ static void bfin_serial_shutdown(struct uart_port *port) break; default: break; - }; + } #endif free_irq(uart->rx_irq, uart); free_irq(uart->tx_irq, uart); @@ -833,7 +833,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = OE; if (termios->c_iflag & INPCK) port->read_status_mask |= (FE | PE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= BI; /* @@ -1240,7 +1240,7 @@ static int bfin_serial_probe(struct platform_device *pdev) */ #endif ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), + dev_get_platdata(&pdev->dev), DRIVER_NAME); if (ret) { dev_err(&pdev->dev, @@ -1358,8 +1358,7 @@ static int bfin_serial_probe(struct platform_device *pdev) out_error_unmap: iounmap(uart->port.membase); out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); out_error_free_mem: kfree(uart); bfin_serial_ports[pdev->id] = NULL; @@ -1377,8 +1376,7 @@ static int bfin_serial_remove(struct platform_device *pdev) if (uart) { uart_remove_one_port(&bfin_serial_reg, &uart->port); iounmap(uart->port.membase); - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); kfree(uart); bfin_serial_ports[pdev->id] = NULL; } @@ -1432,8 +1430,8 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev) return -ENOENT; } - ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), DRIVER_NAME); + ret = peripheral_request_list(dev_get_platdata(&pdev->dev), + DRIVER_NAME); if (ret) { dev_err(&pdev->dev, "fail to request bfin serial peripherals\n"); @@ -1463,8 +1461,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev) return 0; out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); return ret; } diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 7e4e4088471..14aaea0d413 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -21,44 +21,66 @@ #include <linux/console.h> #include <linux/serial_core.h> #include <linux/serial.h> -#include <linux/io.h> #include <linux/clk.h> +#include <linux/io.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/ioport.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/regmap.h> -#include <mach/hardware.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.h> -#define UART_CLPS711X_NAME "uart-clps711x" +#define UART_CLPS711X_DEVNAME "ttyCL" #define UART_CLPS711X_NR 2 #define UART_CLPS711X_MAJOR 204 #define UART_CLPS711X_MINOR 40 -#define UBRLCR(port) ((port)->line ? UBRLCR2 : UBRLCR1) -#define UARTDR(port) ((port)->line ? UARTDR2 : UARTDR1) -#define SYSFLG(port) ((port)->line ? SYSFLG2 : SYSFLG1) -#define SYSCON(port) ((port)->line ? SYSCON2 : SYSCON1) -#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1) -#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1) +#define UARTDR_OFFSET (0x00) +#define UBRLCR_OFFSET (0x40) + +#define UARTDR_FRMERR (1 << 8) +#define UARTDR_PARERR (1 << 9) +#define UARTDR_OVERR (1 << 10) + +#define UBRLCR_BAUD_MASK ((1 << 12) - 1) +#define UBRLCR_BREAK (1 << 12) +#define UBRLCR_PRTEN (1 << 13) +#define UBRLCR_EVENPRT (1 << 14) +#define UBRLCR_XSTOP (1 << 15) +#define UBRLCR_FIFOEN (1 << 16) +#define UBRLCR_WRDLEN5 (0 << 17) +#define UBRLCR_WRDLEN6 (1 << 17) +#define UBRLCR_WRDLEN7 (2 << 17) +#define UBRLCR_WRDLEN8 (3 << 17) +#define UBRLCR_WRDLEN_MASK (3 << 17) struct clps711x_port { - struct uart_driver uart; - struct clk *uart_clk; - struct uart_port port[UART_CLPS711X_NR]; - int tx_enabled[UART_CLPS711X_NR]; -#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE - struct console console; -#endif + struct uart_port port; + unsigned int tx_enabled; + int rx_irq; + struct regmap *syscon; + bool use_ms; +}; + +static struct uart_driver clps711x_uart = { + .owner = THIS_MODULE, + .driver_name = UART_CLPS711X_DEVNAME, + .dev_name = UART_CLPS711X_DEVNAME, + .major = UART_CLPS711X_MAJOR, + .minor = UART_CLPS711X_MINOR, + .nr = UART_CLPS711X_NR, }; static void uart_clps711x_stop_tx(struct uart_port *port) { struct clps711x_port *s = dev_get_drvdata(port->dev); - if (s->tx_enabled[port->line]) { - disable_irq(TX_IRQ(port)); - s->tx_enabled[port->line] = 0; + if (s->tx_enabled) { + disable_irq(port->irq); + s->tx_enabled = 0; } } @@ -66,33 +88,27 @@ static void uart_clps711x_start_tx(struct uart_port *port) { struct clps711x_port *s = dev_get_drvdata(port->dev); - if (!s->tx_enabled[port->line]) { - enable_irq(TX_IRQ(port)); - s->tx_enabled[port->line] = 1; + if (!s->tx_enabled) { + s->tx_enabled = 1; + enable_irq(port->irq); } } -static void uart_clps711x_stop_rx(struct uart_port *port) -{ - disable_irq(RX_IRQ(port)); -} - -static void uart_clps711x_enable_ms(struct uart_port *port) -{ - /* Do nothing */ -} - static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id) { struct uart_port *port = dev_id; - unsigned int status, ch, flg; + struct clps711x_port *s = dev_get_drvdata(port->dev); + unsigned int status, flg; + u16 ch; for (;;) { - status = clps_readl(SYSFLG(port)); - if (status & SYSFLG_URXFE) + u32 sysflg = 0; + + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + if (sysflg & SYSFLG_URXFE) break; - ch = clps_readw(UARTDR(port)); + ch = readw(port->membase + UARTDR_OFFSET); status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR); ch &= 0xff; @@ -138,23 +154,29 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) struct circ_buf *xmit = &port->state->xmit; if (port->x_char) { - clps_writew(port->x_char, UARTDR(port)); + writew(port->x_char, port->membase + UARTDR_OFFSET); port->icount.tx++; port->x_char = 0; return IRQ_HANDLED; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - disable_irq_nosync(TX_IRQ(port)); - s->tx_enabled[port->line] = 0; + if (s->tx_enabled) { + disable_irq_nosync(port->irq); + s->tx_enabled = 0; + } return IRQ_HANDLED; } while (!uart_circ_empty(xmit)) { - clps_writew(xmit->buf[xmit->tail], UARTDR(port)); + u32 sysflg = 0; + + writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; - if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF)) + + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + if (sysflg & SYSFLG_UTXFF) break; } @@ -166,20 +188,28 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id) static unsigned int uart_clps711x_tx_empty(struct uart_port *port) { - return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT; + struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; + + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + + return (sysflg & SYSFLG_UBUSY) ? 0 : TIOCSER_TEMT; } static unsigned int uart_clps711x_get_mctrl(struct uart_port *port) { - unsigned int status, result = 0; + struct clps711x_port *s = dev_get_drvdata(port->dev); + unsigned int result = 0; + + if (s->use_ms) { + u32 sysflg = 0; - if (port->line == 0) { - status = clps_readl(SYSFLG1); - if (status & SYSFLG1_DCD) + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + if (sysflg & SYSFLG1_DCD) result |= TIOCM_CAR; - if (status & SYSFLG1_DSR) + if (sysflg & SYSFLG1_DSR) result |= TIOCM_DSR; - if (status & SYSFLG1_CTS) + if (sysflg & SYSFLG1_CTS) result |= TIOCM_CTS; } else result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; @@ -194,65 +224,53 @@ static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl) static void uart_clps711x_break_ctl(struct uart_port *port, int break_state) { - unsigned long flags; unsigned int ubrlcr; - spin_lock_irqsave(&port->lock, flags); - - ubrlcr = clps_readl(UBRLCR(port)); + ubrlcr = readl(port->membase + UBRLCR_OFFSET); if (break_state) ubrlcr |= UBRLCR_BREAK; else ubrlcr &= ~UBRLCR_BREAK; - clps_writel(ubrlcr, UBRLCR(port)); + writel(ubrlcr, port->membase + UBRLCR_OFFSET); +} + +static void uart_clps711x_set_ldisc(struct uart_port *port, int ld) +{ + if (!port->line) { + struct clps711x_port *s = dev_get_drvdata(port->dev); - spin_unlock_irqrestore(&port->lock, flags); + regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN, + (ld == N_IRDA) ? SYSCON1_SIREN : 0); + } } static int uart_clps711x_startup(struct uart_port *port) { struct clps711x_port *s = dev_get_drvdata(port->dev); - int ret; - - s->tx_enabled[port->line] = 1; - /* Allocate the IRQs */ - ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx, - 0, UART_CLPS711X_NAME " TX", port); - if (ret) - return ret; - - ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx, - 0, UART_CLPS711X_NAME " RX", port); - if (ret) { - devm_free_irq(port->dev, TX_IRQ(port), port); - return ret; - } /* Disable break */ - clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port)); + writel(readl(port->membase + UBRLCR_OFFSET) & ~UBRLCR_BREAK, + port->membase + UBRLCR_OFFSET); /* Enable the port */ - clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port)); - - return 0; + return regmap_update_bits(s->syscon, SYSCON_OFFSET, + SYSCON_UARTEN, SYSCON_UARTEN); } static void uart_clps711x_shutdown(struct uart_port *port) { - /* Free the interrupts */ - devm_free_irq(port->dev, TX_IRQ(port), port); - devm_free_irq(port->dev, RX_IRQ(port), port); + struct clps711x_port *s = dev_get_drvdata(port->dev); /* Disable the port */ - clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port)); + regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0); } static void uart_clps711x_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int ubrlcr, baud, quot; - unsigned long flags; + u32 ubrlcr; + unsigned int baud, quot; /* Mask termios capabilities we don't support */ termios->c_cflag &= ~CMSPAR; @@ -291,8 +309,6 @@ static void uart_clps711x_set_termios(struct uart_port *port, /* Enable FIFO */ ubrlcr |= UBRLCR_FIFOEN; - spin_lock_irqsave(&port->lock, flags); - /* Set read status mask */ port->read_status_mask = UARTDR_OVERR; if (termios->c_iflag & INPCK) @@ -306,9 +322,7 @@ static void uart_clps711x_set_termios(struct uart_port *port, uart_update_timeout(port, termios->c_cflag, baud); - clps_writel(ubrlcr | (quot - 1), UBRLCR(port)); - - spin_unlock_irqrestore(&port->lock, flags); + writel(ubrlcr | (quot - 1), port->membase + UBRLCR_OFFSET); } static const char *uart_clps711x_type(struct uart_port *port) @@ -322,14 +336,12 @@ static void uart_clps711x_config_port(struct uart_port *port, int flags) port->type = PORT_CLPS711X; } -static void uart_clps711x_release_port(struct uart_port *port) +static void uart_clps711x_nop_void(struct uart_port *port) { - /* Do nothing */ } -static int uart_clps711x_request_port(struct uart_port *port) +static int uart_clps711x_nop_int(struct uart_port *port) { - /* Do nothing */ return 0; } @@ -339,183 +351,238 @@ static const struct uart_ops uart_clps711x_ops = { .get_mctrl = uart_clps711x_get_mctrl, .stop_tx = uart_clps711x_stop_tx, .start_tx = uart_clps711x_start_tx, - .stop_rx = uart_clps711x_stop_rx, - .enable_ms = uart_clps711x_enable_ms, + .stop_rx = uart_clps711x_nop_void, + .enable_ms = uart_clps711x_nop_void, .break_ctl = uart_clps711x_break_ctl, + .set_ldisc = uart_clps711x_set_ldisc, .startup = uart_clps711x_startup, .shutdown = uart_clps711x_shutdown, .set_termios = uart_clps711x_set_termios, .type = uart_clps711x_type, .config_port = uart_clps711x_config_port, - .release_port = uart_clps711x_release_port, - .request_port = uart_clps711x_request_port, + .release_port = uart_clps711x_nop_void, + .request_port = uart_clps711x_nop_int, }; #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { - while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF) - barrier(); + struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; + + /* Wait for FIFO is not full */ + do { + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + } while (sysflg & SYSFLG_UTXFF); - clps_writew(ch, UARTDR(port)); + writew(ch, port->membase + UARTDR_OFFSET); } static void uart_clps711x_console_write(struct console *co, const char *c, unsigned n) { - struct clps711x_port *s = (struct clps711x_port *)co->data; - struct uart_port *port = &s->port[co->index]; - u32 syscon; - - /* Ensure that the port is enabled */ - syscon = clps_readl(SYSCON(port)); - clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); + struct uart_port *port = clps711x_uart.state[co->index].uart_port; + struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; uart_console_write(port, c, n, uart_clps711x_console_putchar); /* Wait for transmitter to become empty */ - while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY) - barrier(); - - /* Restore the uart state */ - clps_writel(syscon, SYSCON(port)); + do { + regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); + } while (sysflg & SYSFLG_UBUSY); } -static void uart_clps711x_console_get_options(struct uart_port *port, - int *baud, int *parity, - int *bits) +static int uart_clps711x_console_setup(struct console *co, char *options) { - if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { - unsigned int ubrlcr, quot; + int baud = 38400, bits = 8, parity = 'n', flow = 'n'; + int ret, index = co->index; + struct clps711x_port *s; + struct uart_port *port; + unsigned int quot; + u32 ubrlcr; - ubrlcr = clps_readl(UBRLCR(port)); + if (index < 0 || index >= UART_CLPS711X_NR) + return -EINVAL; - *parity = 'n'; - if (ubrlcr & UBRLCR_PRTEN) { - if (ubrlcr & UBRLCR_EVENPRT) - *parity = 'e'; - else - *parity = 'o'; - } + port = clps711x_uart.state[index].uart_port; + if (!port) + return -ENODEV; - if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) - *bits = 7; - else - *bits = 8; + s = dev_get_drvdata(port->dev); - quot = ubrlcr & UBRLCR_BAUD_MASK; - *baud = port->uartclk / (16 * (quot + 1)); - } -} + if (!options) { + u32 syscon = 0; -static int uart_clps711x_console_setup(struct console *co, char *options) -{ - int baud = 38400, bits = 8, parity = 'n', flow = 'n'; - struct clps711x_port *s = (struct clps711x_port *)co->data; - struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; + regmap_read(s->syscon, SYSCON_OFFSET, &syscon); + if (syscon & SYSCON_UARTEN) { + ubrlcr = readl(port->membase + UBRLCR_OFFSET); + + if (ubrlcr & UBRLCR_PRTEN) { + if (ubrlcr & UBRLCR_EVENPRT) + parity = 'e'; + else + parity = 'o'; + } + + if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) + bits = 7; - if (options) + quot = ubrlcr & UBRLCR_BAUD_MASK; + baud = port->uartclk / (16 * (quot + 1)); + } + } else uart_parse_options(options, &baud, &parity, &bits, &flow); - else - uart_clps711x_console_get_options(port, &baud, &parity, &bits); - return uart_set_options(port, co, baud, parity, bits, flow); + ret = uart_set_options(port, co, baud, parity, bits, flow); + if (ret) + return ret; + + return regmap_update_bits(s->syscon, SYSCON_OFFSET, + SYSCON_UARTEN, SYSCON_UARTEN); } + +static struct console clps711x_console = { + .name = UART_CLPS711X_DEVNAME, + .device = uart_console_device, + .write = uart_clps711x_console_write, + .setup = uart_clps711x_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; #endif static int uart_clps711x_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; + int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id; struct clps711x_port *s; - int ret, i; + struct resource *res; + struct clk *uart_clk; - s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL); - if (!s) { - dev_err(&pdev->dev, "Error allocating port structure\n"); + if (index < 0 || index >= UART_CLPS711X_NR) + return -EINVAL; + + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); + if (!s) return -ENOMEM; + + uart_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(uart_clk)) + return PTR_ERR(uart_clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + s->port.membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(s->port.membase)) + return PTR_ERR(s->port.membase); + + s->port.irq = platform_get_irq(pdev, 0); + if (IS_ERR_VALUE(s->port.irq)) + return s->port.irq; + + s->rx_irq = platform_get_irq(pdev, 1); + if (IS_ERR_VALUE(s->rx_irq)) + return s->rx_irq; + + if (!np) { + char syscon_name[9]; + + sprintf(syscon_name, "syscon.%i", index + 1); + s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); + if (IS_ERR(s->syscon)) + return PTR_ERR(s->syscon); + + s->use_ms = !index; + } else { + s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(s->syscon)) + return PTR_ERR(s->syscon); + + if (!index) + s->use_ms = of_property_read_bool(np, "uart-use-ms"); } + + s->port.line = index; + s->port.dev = &pdev->dev; + s->port.iotype = UPIO_MEM32; + s->port.mapbase = res->start; + s->port.type = PORT_CLPS711X; + s->port.fifosize = 16; + s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port.uartclk = clk_get_rate(uart_clk); + s->port.ops = &uart_clps711x_ops; + platform_set_drvdata(pdev, s); - s->uart_clk = devm_clk_get(&pdev->dev, "uart"); - if (IS_ERR(s->uart_clk)) { - dev_err(&pdev->dev, "Can't get UART clocks\n"); - return PTR_ERR(s->uart_clk); - } + ret = uart_add_one_port(&clps711x_uart, &s->port); + if (ret) + return ret; - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttyCL"; - s->uart.major = UART_CLPS711X_MAJOR; - s->uart.minor = UART_CLPS711X_MINOR; - s->uart.nr = UART_CLPS711X_NR; -#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE - s->uart.cons = &s->console; - s->uart.cons->device = uart_console_device; - s->uart.cons->write = uart_clps711x_console_write; - s->uart.cons->setup = uart_clps711x_console_setup; - s->uart.cons->flags = CON_PRINTBUFFER; - s->uart.cons->index = -1; - s->uart.cons->data = s; - strcpy(s->uart.cons->name, "ttyCL"); -#endif - ret = uart_register_driver(&s->uart); + /* Disable port */ + if (!uart_console(&s->port)) + regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0); + + s->tx_enabled = 1; + + ret = devm_request_irq(&pdev->dev, s->port.irq, uart_clps711x_int_tx, 0, + dev_name(&pdev->dev), &s->port); if (ret) { - dev_err(&pdev->dev, "Registering UART driver failed\n"); - devm_clk_put(&pdev->dev, s->uart_clk); + uart_remove_one_port(&clps711x_uart, &s->port); return ret; } - for (i = 0; i < UART_CLPS711X_NR; i++) { - s->port[i].line = i; - s->port[i].dev = &pdev->dev; - s->port[i].irq = TX_IRQ(&s->port[i]); - s->port[i].iobase = SYSCON(&s->port[i]); - s->port[i].type = PORT_CLPS711X; - s->port[i].fifosize = 16; - s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; - s->port[i].uartclk = clk_get_rate(s->uart_clk); - s->port[i].ops = &uart_clps711x_ops; - WARN_ON(uart_add_one_port(&s->uart, &s->port[i])); - } + ret = devm_request_irq(&pdev->dev, s->rx_irq, uart_clps711x_int_rx, 0, + dev_name(&pdev->dev), &s->port); + if (ret) + uart_remove_one_port(&clps711x_uart, &s->port); - return 0; + return ret; } static int uart_clps711x_remove(struct platform_device *pdev) { struct clps711x_port *s = platform_get_drvdata(pdev); - int i; - for (i = 0; i < UART_CLPS711X_NR; i++) - uart_remove_one_port(&s->uart, &s->port[i]); - - devm_clk_put(&pdev->dev, s->uart_clk); - uart_unregister_driver(&s->uart); - - return 0; + return uart_remove_one_port(&clps711x_uart, &s->port); } -static struct platform_driver clps711x_uart_driver = { +static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = { + { .compatible = "cirrus,clps711x-uart", }, + { } +}; +MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids); + +static struct platform_driver clps711x_uart_platform = { .driver = { - .name = UART_CLPS711X_NAME, - .owner = THIS_MODULE, + .name = "clps711x-uart", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(clps711x_uart_dt_ids), }, .probe = uart_clps711x_probe, .remove = uart_clps711x_remove, }; -module_platform_driver(clps711x_uart_driver); - -static struct platform_device clps711x_uart_device = { - .name = UART_CLPS711X_NAME, -}; static int __init uart_clps711x_init(void) { - return platform_device_register(&clps711x_uart_device); + int ret; + +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE + clps711x_uart.cons = &clps711x_console; + clps711x_console.data = &clps711x_uart; +#endif + + ret = uart_register_driver(&clps711x_uart); + if (ret) + return ret; + + return platform_driver_register(&clps711x_uart_platform); } module_init(uart_clps711x_init); static void __exit uart_clps711x_exit(void) { - platform_device_unregister(&clps711x_uart_device); + platform_driver_unregister(&clps711x_uart_platform); + uart_unregister_driver(&clps711x_uart); } module_exit(uart_clps711x_exit); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 1a535f70dc4..aa60e6d13ec 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -41,6 +41,8 @@ #include <linux/bootmem.h> #include <linux/dma-mapping.h> #include <linux/fs_uart_pd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> @@ -969,7 +971,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags) * Note that this is called with interrupts already disabled */ static void cpm_uart_early_write(struct uart_cpm_port *pinfo, - const char *string, u_int count) + const char *string, u_int count, bool handle_linefeed) { unsigned int i; cbd_t __iomem *bdp, *bdbase; @@ -1011,7 +1013,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo, bdp++; /* if a LF, also do CR... */ - if (*string == 10) { + if (handle_linefeed && *string == 10) { while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; @@ -1109,7 +1111,7 @@ static void cpm_put_poll_char(struct uart_port *port, static char ch[2]; ch[0] = (char)c; - cpm_uart_early_write(pinfo, ch, 1); + cpm_uart_early_write(pinfo, ch, 1, false); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1207,7 +1209,7 @@ static int cpm_uart_init_port(struct device_node *np, pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; spin_lock_init(&pinfo->port.lock); - pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + pinfo->port.irq = irq_of_parse_and_map(np, 0); if (pinfo->port.irq == NO_IRQ) { ret = -EINVAL; goto out_pram; @@ -1273,7 +1275,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, spin_lock_irqsave(&pinfo->port.lock, flags); } - cpm_uart_early_write(pinfo, s, count); + cpm_uart_early_write(pinfo, s, count, true); if (unlikely(nolock)) { local_irq_restore(flags); diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c index 18f79575894..6d3b22e9324 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c @@ -29,7 +29,6 @@ #include <linux/tty.h> #include <linux/gfp.h> #include <linux/ioport.h> -#include <linux/init.h> #include <linux/serial.h> #include <linux/console.h> #include <linux/sysrq.h> @@ -45,6 +44,7 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <linux/of_address.h> #include "cpm_uart.h" diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c index a4927e66e74..f46d2ca8720 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c @@ -29,7 +29,6 @@ #include <linux/tty.h> #include <linux/ioport.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/serial.h> #include <linux/console.h> #include <linux/sysrq.h> diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 477f22f773f..d567ac5d3af 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -286,7 +286,6 @@ static struct e100_serial rs_table[] = { #endif }, /* ttyS0 */ -#ifndef CONFIG_SVINTO_SIM { .baud = DEF_BAUD, .ioport = (unsigned char *)R_SERIAL1_CTRL, .irq = 1U << 16, /* uses DMA 8 and 9 */ @@ -447,7 +446,6 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 0 #endif } /* ttyS3 */ -#endif }; @@ -1035,7 +1033,6 @@ cflag_to_etrax_baud(unsigned int cflag) static inline void e100_dtr(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM unsigned char mask = e100_modem_pins[info->line].dtr_mask; #ifdef SERIAL_DEBUG_IO @@ -1060,7 +1057,6 @@ e100_dtr(struct e100_serial *info, int set) info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif -#endif } /* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive @@ -1069,7 +1065,6 @@ e100_dtr(struct e100_serial *info, int set) static inline void e100_rts(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM unsigned long flags; local_irq_save(flags); info->rx_ctrl &= ~E100_RTS_MASK; @@ -1079,7 +1074,6 @@ e100_rts(struct e100_serial *info, int set) #ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set); #endif -#endif } @@ -1087,7 +1081,6 @@ e100_rts(struct e100_serial *info, int set) static inline void e100_ri_out(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM /* RI is active low */ { unsigned char mask = e100_modem_pins[info->line].ri_mask; @@ -1099,12 +1092,10 @@ e100_ri_out(struct e100_serial *info, int set) *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; local_irq_restore(flags); } -#endif } static inline void e100_cd_out(struct e100_serial *info, int set) { -#ifndef CONFIG_SVINTO_SIM /* CD is active low */ { unsigned char mask = e100_modem_pins[info->line].cd_mask; @@ -1116,27 +1107,22 @@ e100_cd_out(struct e100_serial *info, int set) *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; local_irq_restore(flags); } -#endif } static inline void e100_disable_rx(struct e100_serial *info) { -#ifndef CONFIG_SVINTO_SIM /* disable the receiver */ info->ioport[REG_REC_CTRL] = (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif } static inline void e100_enable_rx(struct e100_serial *info) { -#ifndef CONFIG_SVINTO_SIM /* enable the receiver */ info->ioport[REG_REC_CTRL] = (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable)); -#endif } /* the rx DMA uses both the dma_descr and the dma_eop interrupts */ @@ -1554,24 +1540,6 @@ transmit_chars_dma(struct e100_serial *info) unsigned int c, sentl; struct etrax_dma_descr *descr; -#ifdef CONFIG_SVINTO_SIM - /* This will output too little if tail is not 0 always since - * we don't reloop to send the other part. Anyway this SHOULD be a - * no-op - transmit_chars_dma would never really be called during sim - * since rs_write does not write into the xmit buffer then. - */ - if (info->xmit.tail) - printk("Error in serial.c:transmit_chars-dma(), tail!=0\n"); - if (info->xmit.head != info->xmit.tail) { - SIMCOUT(info->xmit.buf + info->xmit.tail, - CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE)); - info->xmit.head = info->xmit.tail; /* move back head */ - info->tr_running = 0; - } - return; -#endif /* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->oclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1842,13 +1810,6 @@ static void receive_chars_dma(struct e100_serial *info) struct tty_struct *tty; unsigned char rstat; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif - /* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */ *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1934,12 +1895,6 @@ static int start_recv_dma(struct e100_serial *info) static void start_receive(struct e100_serial *info) { -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - return; -#endif if (info->uses_dma_in) { /* reset the input dma channel to be sure it works */ @@ -1972,17 +1927,6 @@ tr_interrupt(int irq, void *dev_id) int i; int handled = 0; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? tr_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - /* find out the line that caused this irq and get it from rs_table */ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ @@ -2021,17 +1965,6 @@ rec_interrupt(int irq, void *dev_id) int i; int handled = 0; -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? rec_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return IRQ_HANDLED; -#endif - /* find out the line that caused this irq and get it from rs_table */ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ @@ -2153,7 +2086,7 @@ static void flush_timeout_function(unsigned long data) fast_timers[info->line].function = NULL; serial_fast_timer_expired++; - TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); + TIMERD(DEBUG_LOG(info->line, "flush_timeout %i ", info->line)); TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); check_flush_timeout(info); } @@ -2173,10 +2106,6 @@ timed_flush_handler(unsigned long ptr) struct e100_serial *info; int i; -#ifdef CONFIG_SVINTO_SIM - return; -#endif - for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (info->uses_dma_in) @@ -2729,25 +2658,6 @@ startup(struct e100_serial * info) printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf); #endif -#ifdef CONFIG_SVINTO_SIM - /* Bits and pieces collected from below. Better to have them - in one ifdef:ed clause than to mix in a lot of ifdefs, - right? */ - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->xmit.head = info->xmit.tail = 0; - info->first_recv_buffer = info->last_recv_buffer = NULL; - info->recv_cnt = info->max_recv_cnt = 0; - - for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) - info->rec_descr[i].buf = NULL; - - /* No real action in the simulator, but may set info important - to ioctl. */ - change_speed(info); -#else - /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) @@ -2837,8 +2747,6 @@ startup(struct e100_serial * info) e100_rts(info, 1); e100_dtr(info, 1); -#endif /* CONFIG_SVINTO_SIM */ - info->port.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); @@ -2857,7 +2765,6 @@ shutdown(struct e100_serial * info) struct etrax_recv_buffer *buffer; int i; -#ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line)); e100_disable_rx(info); @@ -2882,8 +2789,6 @@ shutdown(struct e100_serial * info) info->tr_running = 0; } -#endif /* CONFIG_SVINTO_SIM */ - if (!(info->port.flags & ASYNC_INITIALIZED)) return; @@ -2995,17 +2900,12 @@ change_speed(struct e100_serial *info) IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal); r_alt_ser_baudrate_shadow &= ~mask; r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8)); -#ifndef CONFIG_SVINTO_SIM *R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow; -#endif /* CONFIG_SVINTO_SIM */ info->baud = cflag_to_baud(cflag); -#ifndef CONFIG_SVINTO_SIM info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag); -#endif /* CONFIG_SVINTO_SIM */ } -#ifndef CONFIG_SVINTO_SIM /* start with default settings and then fill in changes */ local_irq_save(flags); /* 8 bit, no/even parity */ @@ -3073,7 +2973,6 @@ change_speed(struct e100_serial *info) *((unsigned long *)&info->ioport[REG_XOFF]) = xoff; local_irq_restore(flags); -#endif /* !CONFIG_SVINTO_SIM */ update_char_time(info); @@ -3122,11 +3021,6 @@ static int rs_raw_write(struct tty_struct *tty, count, info->ioport[REG_STATUS]); #endif -#ifdef CONFIG_SVINTO_SIM - /* Really simple. The output is here and now. */ - SIMCOUT(buf, count); - return count; -#endif local_save_flags(flags); DFLOW(DEBUG_LOG(info->line, "write count %i ", count)); DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty))); @@ -3463,7 +3357,6 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value) { unsigned int result = TIOCSER_TEMT; -#ifndef CONFIG_SVINTO_SIM unsigned long curr_time = jiffies; unsigned long curr_time_usec = GET_JIFFIES_USEC(); unsigned long elapsed_usec = @@ -3474,7 +3367,6 @@ get_lsr_info(struct e100_serial * info, unsigned int *value) elapsed_usec < 2*info->char_time_usec) { result = 0; } -#endif if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -3804,7 +3696,6 @@ rs_close(struct tty_struct *tty, struct file * filp) e100_disable_serial_data_irq(info); #endif -#ifndef CONFIG_SVINTO_SIM e100_disable_rx(info); e100_disable_rx_irq(info); @@ -3816,7 +3707,6 @@ rs_close(struct tty_struct *tty, struct file * filp) */ rs_wait_until_sent(tty, HZ); } -#endif shutdown(info); rs_flush_buffer(tty); @@ -4479,7 +4369,6 @@ static int __init rs_init(void) fast_timer_init(); #endif -#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_ETRAX_KGDB /* Not needed in simulator. May only complicate stuff. */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ @@ -4489,7 +4378,6 @@ static int __init rs_init(void) panic("%s: Failed to request irq8", __func__); #endif -#endif /* CONFIG_SVINTO_SIM */ return 0; } diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 2f2b2e538a5..cdbbc788230 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -625,7 +625,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios, dport->port.read_status_mask = DZ_OERR; if (termios->c_iflag & INPCK) dport->port.read_status_mask |= DZ_FERR | DZ_PERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) dport->port.read_status_mask |= DZ_BREAK; /* characters to ignore */ diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c new file mode 100644 index 00000000000..383db10fbb4 --- /dev/null +++ b/drivers/tty/serial/earlycon-arm-semihost.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * Author: Marc Zyngier <marc.zyngier@arm.com> + * + * Adapted for ARM and earlycon: + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring <robh@kernel.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/serial_core.h> + +#ifdef CONFIG_THUMB2_KERNEL +#define SEMIHOST_SWI "0xab" +#else +#define SEMIHOST_SWI "0x123456" +#endif + +/* + * Semihosting-based debug console + */ +static void smh_putc(struct uart_port *port, int c) +{ +#ifdef CONFIG_ARM64 + asm volatile("mov x1, %0\n" + "mov x0, #3\n" + "hlt 0xf000\n" + : : "r" (&c) : "x0", "x1", "memory"); +#else + asm volatile("mov r1, %0\n" + "mov r0, #3\n" + "svc " SEMIHOST_SWI "\n" + : : "r" (&c) : "r0", "r1", "memory"); +#endif +} + +static void smh_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + uart_console_write(&dev->port, s, n, smh_putc); +} + +int __init early_smh_setup(struct earlycon_device *device, const char *opt) +{ + device->con->write = smh_write; + return 0; +} +EARLYCON_DECLARE(smh, early_smh_setup); diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c new file mode 100644 index 00000000000..a514ee6f540 --- /dev/null +++ b/drivers/tty/serial/earlycon.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * Author: Rob Herring <robh@kernel.org> + * + * Based on 8250 earlycon: + * (c) Copyright 2004 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/console.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/serial_core.h> +#include <linux/sizes.h> +#include <linux/mod_devicetable.h> + +#ifdef CONFIG_FIX_EARLYCON_MEM +#include <asm/fixmap.h> +#endif + +#include <asm/serial.h> + +static struct console early_con = { + .name = "uart", /* 8250 console switch requires this name */ + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +static struct earlycon_device early_console_dev = { + .con = &early_con, +}; + +static const struct of_device_id __earlycon_of_table_sentinel + __used __section(__earlycon_of_table_end); + +static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) +{ + void __iomem *base; +#ifdef CONFIG_FIX_EARLYCON_MEM + set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); + base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + base += paddr & ~PAGE_MASK; +#else + base = ioremap(paddr, size); +#endif + if (!base) + pr_err("%s: Couldn't map 0x%llx\n", __func__, + (unsigned long long)paddr); + + return base; +} + +static int __init parse_options(struct earlycon_device *device, + char *options) +{ + struct uart_port *port = &device->port; + int mmio, mmio32, length; + unsigned long addr; + + if (!options) + return -ENODEV; + + mmio = !strncmp(options, "mmio,", 5); + mmio32 = !strncmp(options, "mmio32,", 7); + if (mmio || mmio32) { + port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32); + options += mmio ? 5 : 7; + addr = simple_strtoul(options, NULL, 0); + port->mapbase = addr; + if (mmio32) + port->regshift = 2; + } else if (!strncmp(options, "io,", 3)) { + port->iotype = UPIO_PORT; + options += 3; + addr = simple_strtoul(options, NULL, 0); + port->iobase = addr; + mmio = 0; + } else if (!strncmp(options, "0x", 2)) { + port->iotype = UPIO_MEM; + addr = simple_strtoul(options, NULL, 0); + port->mapbase = addr; + } else { + return -EINVAL; + } + + port->uartclk = BASE_BAUD * 16; + + options = strchr(options, ','); + if (options) { + options++; + device->baud = simple_strtoul(options, NULL, 0); + length = min(strcspn(options, " ") + 1, + (size_t)(sizeof(device->options))); + strlcpy(device->options, options, length); + } + + if (mmio || mmio32) + pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", + mmio32 ? "32" : "", + (unsigned long long)port->mapbase, + device->options); + else + pr_info("Early serial console at I/O port 0x%lx (options '%s')\n", + port->iobase, + device->options); + + return 0; +} + +int __init setup_earlycon(char *buf, const char *match, + int (*setup)(struct earlycon_device *, const char *)) +{ + int err; + size_t len; + struct uart_port *port = &early_console_dev.port; + + if (!buf || !match || !setup) + return 0; + + len = strlen(match); + if (strncmp(buf, match, len)) + return 0; + if (buf[len] && (buf[len] != ',')) + return 0; + + buf += len + 1; + + err = parse_options(&early_console_dev, buf); + /* On parsing error, pass the options buf to the setup function */ + if (!err) + buf = NULL; + + if (port->mapbase) + port->membase = earlycon_map(port->mapbase, 64); + + early_console_dev.con->data = &early_console_dev; + err = setup(&early_console_dev, buf); + if (err < 0) + return err; + if (!early_console_dev.con->write) + return -ENODEV; + + register_console(early_console_dev.con); + return 0; +} + +int __init of_setup_earlycon(unsigned long addr, + int (*setup)(struct earlycon_device *, const char *)) +{ + int err; + struct uart_port *port = &early_console_dev.port; + + port->iotype = UPIO_MEM; + port->mapbase = addr; + port->uartclk = BASE_BAUD * 16; + port->membase = earlycon_map(addr, SZ_4K); + + early_console_dev.con->data = &early_console_dev; + err = setup(&early_console_dev, NULL); + if (err < 0) + return err; + if (!early_console_dev.con->write) + return -ENODEV; + + + register_console(early_console_dev.con); + return 0; +} diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 0eb5b5673ed..3b0ee9afd76 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -407,7 +407,7 @@ static void efm32_uart_set_termios(struct uart_port *port, if (new->c_iflag & INPCK) port->read_status_mask |= UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & (BRKINT | PARMRK)) + if (new->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SW_UARTn_RXDATAX_BERR; port->ignore_status_mask = 0; @@ -671,7 +671,10 @@ static int efm32_uart_probe_dt(struct platform_device *pdev, if (!np) return 1; - ret = of_property_read_u32(np, "location", &location); + ret = of_property_read_u32(np, "efm32,location", &location); + if (ret) + /* fall back to old and (wrongly) generic property "location" */ + ret = of_property_read_u32(np, "location", &location); if (!ret) { if (location > 5) { dev_err(&pdev->dev, "invalid location\n"); @@ -795,6 +798,9 @@ static int efm32_uart_remove(struct platform_device *pdev) static const struct of_device_id efm32_uart_dt_ids[] = { { + .compatible = "energymicro,efm32-uart", + }, { + /* doesn't follow the "vendor,device" scheme, don't use */ .compatible = "efm32,uart", }, { /* sentinel */ @@ -836,6 +842,7 @@ static void __exit efm32_uart_exit(void) platform_driver_unregister(&efm32_uart_driver); uart_unregister_driver(&efm32_uart_reg); } +module_exit(efm32_uart_exit); MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); MODULE_DESCRIPTION("EFM32 UART/USART driver"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 8978dc9a58b..49385c86cfb 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -13,14 +13,19 @@ #define SUPPORT_SYSRQ #endif -#include <linux/module.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/dmapool.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/clk.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/console.h> +#include <linux/of_dma.h> #include <linux/serial_core.h> +#include <linux/slab.h> #include <linux/tty_flip.h> /* All registers are 8-bit width */ @@ -112,6 +117,10 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 +#define DMA_MAXBURST 16 +#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1) +#define FSL_UART_RX_DMA_BUFFER_SIZE 64 + #define DRIVER_NAME "fsl-lpuart" #define DEV_NAME "ttyLP" #define UART_NR 6 @@ -121,6 +130,24 @@ struct lpuart_port { struct clk *clk; unsigned int txfifo_size; unsigned int rxfifo_size; + + bool lpuart_dma_use; + struct dma_chan *dma_tx_chan; + struct dma_chan *dma_rx_chan; + struct dma_async_tx_descriptor *dma_tx_desc; + struct dma_async_tx_descriptor *dma_rx_desc; + dma_addr_t dma_tx_buf_bus; + dma_addr_t dma_rx_buf_bus; + dma_cookie_t dma_tx_cookie; + dma_cookie_t dma_rx_cookie; + unsigned char *dma_tx_buf_virt; + unsigned char *dma_rx_buf_virt; + unsigned int dma_tx_bytes; + unsigned int dma_rx_bytes; + int dma_tx_in_progress; + int dma_rx_in_progress; + unsigned int dma_rx_timeout; + struct timer_list lpuart_timer; }; static struct of_device_id lpuart_dt_ids[] = { @@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, lpuart_dt_ids); +/* Forward declare this for the dma callbacks*/ +static void lpuart_dma_tx_complete(void *arg); +static void lpuart_dma_rx_complete(void *arg); + static void lpuart_stop_tx(struct uart_port *port) { unsigned char temp; @@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port) { } +static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, + struct tty_port *tty, int count) +{ + int copied; + + sport->port.icount.rx += count; + + if (!tty) { + dev_err(sport->port.dev, "No tty port\n"); + return; + } + + dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + copied = tty_insert_flip_string(tty, + ((unsigned char *)(sport->dma_rx_buf_virt)), count); + + if (copied != count) { + WARN_ON(1); + dev_err(sport->port.dev, "RxData copy to tty layer failed\n"); + } + + dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); +} + +static void lpuart_pio_tx(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + + while (!uart_circ_empty(xmit) && + readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) { + writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + dma_addr_t tx_bus_addr; + + dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, + UART_XMIT_SIZE, DMA_TO_DEVICE); + sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK); + tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; + sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, + tx_bus_addr, sport->dma_tx_bytes, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + + if (!sport->dma_tx_desc) { + dev_err(sport->port.dev, "Not able to get desc for tx\n"); + return -EIO; + } + + sport->dma_tx_desc->callback = lpuart_dma_tx_complete; + sport->dma_tx_desc->callback_param = sport; + sport->dma_tx_in_progress = 1; + sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); + dma_async_issue_pending(sport->dma_tx_chan); + + return 0; +} + +static void lpuart_prepare_tx(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long count = CIRC_CNT_TO_END(xmit->head, + xmit->tail, UART_XMIT_SIZE); + + if (!count) + return; + + if (count < DMA_MAXBURST) + writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + else { + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, + sport->port.membase + UARTCR5); + lpuart_dma_tx(sport, count); + } +} + +static void lpuart_dma_tx_complete(void *arg) +{ + struct lpuart_port *sport = arg; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + async_tx_ack(sport->dma_tx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); + sport->dma_tx_in_progress = 0; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + lpuart_prepare_tx(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int lpuart_dma_rx(struct lpuart_port *sport) +{ + dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); + sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan, + sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + + if (!sport->dma_rx_desc) { + dev_err(sport->port.dev, "Not able to get desc for rx\n"); + return -EIO; + } + + sport->dma_rx_desc->callback = lpuart_dma_rx_complete; + sport->dma_rx_desc->callback_param = sport; + sport->dma_rx_in_progress = 1; + sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); + dma_async_issue_pending(sport->dma_rx_chan); + + return 0; +} + +static void lpuart_dma_rx_complete(void *arg) +{ + struct lpuart_port *sport = arg; + struct tty_port *port = &sport->port.state->port; + unsigned long flags; + + async_tx_ack(sport->dma_rx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->dma_rx_in_progress = 0; + lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE); + tty_flip_buffer_push(port); + lpuart_dma_rx(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void lpuart_timer_func(unsigned long data) +{ + struct lpuart_port *sport = (struct lpuart_port *)data; + struct tty_port *port = &sport->port.state->port; + struct dma_tx_state state; + unsigned long flags; + unsigned char temp; + int count; + + del_timer(&sport->lpuart_timer); + dmaengine_pause(sport->dma_rx_chan); + dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state); + dmaengine_terminate_all(sport->dma_rx_chan); + count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue; + async_tx_ack(sport->dma_rx_desc); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->dma_rx_in_progress = 0; + lpuart_copy_rx_to_tty(sport, port, count); + tty_flip_buffer_push(port); + temp = readb(sport->port.membase + UARTCR5); + writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static inline void lpuart_prepare_rx(struct lpuart_port *sport) +{ + unsigned long flags; + unsigned char temp; + + spin_lock_irqsave(&sport->port.lock, flags); + + init_timer(&sport->lpuart_timer); + sport->lpuart_timer.function = lpuart_timer_func; + sport->lpuart_timer.data = (unsigned long)sport; + sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; + add_timer(&sport->lpuart_timer); + + lpuart_dma_rx(sport); + temp = readb(sport->port.membase + UARTCR5); + writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static void lpuart_start_tx(struct uart_port *port) { - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct circ_buf *xmit = &sport->port.state->xmit; unsigned char temp; temp = readb(port->membase + UARTCR2); writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); - if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) - lpuart_transmit_buffer(sport); + if (sport->lpuart_dma_use) { + if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress) + lpuart_prepare_tx(sport); + } else { + if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) + lpuart_transmit_buffer(sport); + } } static irqreturn_t lpuart_txint(int irq, void *dev_id) @@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) sts = readb(sport->port.membase + UARTSR1); - if (sts & UARTSR1_RDRF) - lpuart_rxint(irq, dev_id); - + if (sts & UARTSR1_RDRF) { + if (sport->lpuart_dma_use) + lpuart_prepare_rx(sport); + else + lpuart_rxint(irq, dev_id); + } if (sts & UARTSR1_TDRE && - !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) - lpuart_txint(irq, dev_id); + !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) { + if (sport->lpuart_dma_use) + lpuart_pio_tx(sport); + else + lpuart_txint(irq, dev_id); + } return IRQ_HANDLED; } @@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); - writeb(2, sport->port.membase + UARTTWFIFO); + writeb(0, sport->port.membase + UARTTWFIFO); writeb(1, sport->port.membase + UARTRWFIFO); /* Restore cr2 */ writeb(cr2_saved, sport->port.membase + UARTCR2); } +static int lpuart_dma_tx_request(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *tx_chan; + struct dma_slave_config dma_tx_sconfig; + dma_addr_t dma_bus; + unsigned char *dma_buf; + int ret; + + tx_chan = dma_request_slave_channel(sport->port.dev, "tx"); + + if (!tx_chan) { + dev_err(sport->port.dev, "Dma tx channel request failed!\n"); + return -ENODEV; + } + + dma_bus = dma_map_single(tx_chan->device->dev, + sport->port.state->xmit.buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + if (dma_mapping_error(tx_chan->device->dev, dma_bus)) { + dev_err(sport->port.dev, "dma_map_single tx failed\n"); + dma_release_channel(tx_chan); + return -ENOMEM; + } + + dma_buf = sport->port.state->xmit.buf; + dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_tx_sconfig.dst_maxburst = DMA_MAXBURST; + dma_tx_sconfig.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig); + + if (ret < 0) { + dev_err(sport->port.dev, + "Dma slave config failed, err = %d\n", ret); + dma_release_channel(tx_chan); + return ret; + } + + sport->dma_tx_chan = tx_chan; + sport->dma_tx_buf_virt = dma_buf; + sport->dma_tx_buf_bus = dma_bus; + sport->dma_tx_in_progress = 0; + + return 0; +} + +static int lpuart_dma_rx_request(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *rx_chan; + struct dma_slave_config dma_rx_sconfig; + dma_addr_t dma_bus; + unsigned char *dma_buf; + int ret; + + rx_chan = dma_request_slave_channel(sport->port.dev, "rx"); + + if (!rx_chan) { + dev_err(sport->port.dev, "Dma rx channel request failed!\n"); + return -ENODEV; + } + + dma_buf = devm_kzalloc(sport->port.dev, + FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL); + + if (!dma_buf) { + dev_err(sport->port.dev, "Dma rx alloc failed\n"); + dma_release_channel(rx_chan); + return -ENOMEM; + } + + dma_bus = dma_map_single(rx_chan->device->dev, dma_buf, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + + if (dma_mapping_error(rx_chan->device->dev, dma_bus)) { + dev_err(sport->port.dev, "dma_map_single rx failed\n"); + dma_release_channel(rx_chan); + return -ENOMEM; + } + + dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; + dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_rx_sconfig.src_maxburst = 1; + dma_rx_sconfig.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig); + + if (ret < 0) { + dev_err(sport->port.dev, + "Dma slave config failed, err = %d\n", ret); + dma_release_channel(rx_chan); + return ret; + } + + sport->dma_rx_chan = rx_chan; + sport->dma_rx_buf_virt = dma_buf; + sport->dma_rx_buf_bus = dma_bus; + sport->dma_rx_in_progress = 0; + + sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * + FSL_UART_RX_DMA_BUFFER_SIZE * 3 / + sport->rxfifo_size / 2; + + if (sport->dma_rx_timeout < msecs_to_jiffies(20)) + sport->dma_rx_timeout = msecs_to_jiffies(20); + + return 0; +} + +static void lpuart_dma_tx_free(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *dma_chan; + + dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus, + UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_chan = sport->dma_tx_chan; + sport->dma_tx_chan = NULL; + sport->dma_tx_buf_bus = 0; + sport->dma_tx_buf_virt = NULL; + dma_release_channel(dma_chan); +} + +static void lpuart_dma_rx_free(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_chan *dma_chan; + + dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus, + FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); + + dma_chan = sport->dma_rx_chan; + sport->dma_rx_chan = NULL; + sport->dma_rx_buf_bus = 0; + sport->dma_rx_buf_virt = NULL; + dma_release_channel(dma_chan); +} + static int lpuart_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); @@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port) unsigned long flags; unsigned char temp; + /*whether use dma support by dma request results*/ + if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) { + sport->lpuart_dma_use = false; + } else { + sport->lpuart_dma_use = true; + temp = readb(port->membase + UARTCR5); + writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); + } + ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0, DRIVER_NAME, sport); if (ret) @@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); devm_free_irq(port->dev, port->irq, sport); + + if (sport->lpuart_dma_use) { + lpuart_dma_tx_free(port); + lpuart_dma_rx_free(port); + } } static void @@ -496,7 +902,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSR1_FE; /* characters to ignore */ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index d98e4334897..67423805e6d 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -455,11 +455,11 @@ static void load_code(struct icom_port *icom_port) for (index = 0; index < fw->size; index++) new_page[index] = fw->data[index]; - release_firmware(fw); - writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); writel(temp_pci, &icom_port->dram->mac_load_addr); + release_firmware(fw); + /*Setting the syncReg to 0x80 causes adapter to start downloading the personality code into adapter instruction RAM. Once code is loaded, it will begin executing and, based on diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index af286e6713e..59039097099 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1008,7 +1008,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return -ENODEV; } - pl_data = (struct ifx_modem_platform_data *)dev_get_platdata(&spi->dev); + pl_data = dev_get_platdata(&spi->dev); if (!pl_data) { dev_err(&spi->dev, "missing platform data!"); return -ENODEV; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a0ebbc9ce5c..044e86d528a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -116,7 +116,7 @@ #define UCR3_DSR (1<<10) /* Data set ready */ #define UCR3_DCD (1<<9) /* Data carrier detect */ #define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ @@ -223,8 +223,7 @@ struct imx_port { struct dma_chan *dma_chan_rx, *dma_chan_tx; struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; - unsigned int rx_bytes, tx_bytes; - struct work_struct tsk_dma_rx, tsk_dma_tx; + unsigned int tx_bytes; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; }; @@ -445,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port) temp = readl(sport->port.membase + UCR2); writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + + /* disable the `Receiver Ready Interrrupt` */ + temp = readl(sport->port.membase + UCR1); + writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); } /* @@ -497,42 +500,32 @@ static void dma_tx_callback(void *data) dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); + uart_write_wakeup(&sport->port); if (waitqueue_active(&sport->dma_wait)) { wake_up(&sport->dma_wait); dev_dbg(sport->port.dev, "exit in %s.\n", __func__); return; } - - schedule_work(&sport->tsk_dma_tx); } -static void dma_tx_work(struct work_struct *w) +static void imx_dma_tx(struct imx_port *sport) { - struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx); struct circ_buf *xmit = &sport->port.state->xmit; struct scatterlist *sgl = sport->tx_sgl; struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; struct device *dev = sport->port.dev; enum dma_status status; - unsigned long flags; int ret; - status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL); + status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL); if (DMA_IN_PROGRESS == status) return; - spin_lock_irqsave(&sport->port.lock, flags); sport->tx_bytes = uart_circ_chars_pending(xmit); - if (sport->tx_bytes == 0) { - spin_unlock_irqrestore(&sport->port.lock, flags); - return; - } - if (xmit->tail > xmit->head) { + if (xmit->tail > xmit->head && xmit->head > 0) { sport->dma_tx_nents = 2; sg_init_table(sgl, 2); sg_set_buf(sgl, xmit->buf + xmit->tail, @@ -542,7 +535,6 @@ static void dma_tx_work(struct work_struct *w) sport->dma_tx_nents = 1; sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); } - spin_unlock_irqrestore(&sport->port.lock, flags); ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); if (ret == 0) { @@ -575,6 +567,9 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (uart_circ_empty(&port->state->xmit)) + return; + if (USE_IRDA(sport)) { /* half duplex in IrDA mode; have to disable receive mode */ temp = readl(sport->port.membase + UCR4); @@ -609,11 +604,7 @@ static void imx_start_tx(struct uart_port *port) } if (sport->dma_is_enabled) { - /* - * We may in the interrupt context, so arise a work_struct to - * do the real job. - */ - schedule_work(&sport->tsk_dma_tx); + imx_dma_tx(sport); return; } @@ -732,6 +723,7 @@ out: return IRQ_HANDLED; } +static int start_rx_dma(struct imx_port *sport); /* * If the RXFIFO is filled with some data, and then we * arise a DMA operation to receive them. @@ -750,7 +742,7 @@ static void imx_dma_rxint(struct imx_port *sport) writel(temp, sport->port.membase + UCR1); /* tell the DMA to receive the data. */ - schedule_work(&sport->tsk_dma_rx); + start_rx_dma(sport); } } @@ -795,8 +787,15 @@ static irqreturn_t imx_int(int irq, void *dev_id) static unsigned int imx_tx_empty(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + unsigned int ret; - return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + + /* If the TX DMA is working, return 0. */ + if (sport->dma_is_enabled && sport->dma_is_txing) + ret = 0; + + return ret; } /* @@ -813,6 +812,9 @@ static unsigned int imx_get_mctrl(struct uart_port *port) if (readl(sport->port.membase + UCR2) & UCR2_CTS) tmp |= TIOCM_RTS; + if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP) + tmp |= TIOCM_LOOP; + return tmp; } @@ -828,6 +830,11 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) temp |= UCR2_CTS; writel(temp, sport->port.membase + UCR2); + + temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; + if (mctrl & TIOCM_LOOP) + temp |= UTS_LOOP; + writel(temp, sport->port.membase + uts_reg(sport)); } /* @@ -865,22 +872,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) } #define RX_BUF_SIZE (PAGE_SIZE) -static int start_rx_dma(struct imx_port *sport); -static void dma_rx_work(struct work_struct *w) -{ - struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx); - struct tty_port *port = &sport->port.state->port; - - if (sport->rx_bytes) { - tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes); - tty_flip_buffer_push(port); - sport->rx_bytes = 0; - } - - if (sport->dma_is_rxing) - start_rx_dma(sport); -} - static void imx_rx_dma_done(struct imx_port *sport) { unsigned long temp; @@ -912,6 +903,7 @@ static void dma_rx_callback(void *data) struct imx_port *sport = data; struct dma_chan *chan = sport->dma_chan_rx; struct scatterlist *sgl = &sport->rx_sgl; + struct tty_port *port = &sport->port.state->port; struct dma_tx_state state; enum dma_status status; unsigned int count; @@ -919,13 +911,15 @@ static void dma_rx_callback(void *data) /* unmap it first */ dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); - status = chan->device->device_tx_status(chan, (dma_cookie_t)0, &state); + status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); count = RX_BUF_SIZE - state.residue; dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (count) { - sport->rx_bytes = count; - schedule_work(&sport->tsk_dma_rx); + tty_insert_flip_string(port, sport->rx_buf, count); + tty_flip_buffer_push(port); + + start_rx_dma(sport); } else imx_rx_dma_done(sport); } @@ -1007,7 +1001,6 @@ static int imx_uart_dma_init(struct imx_port *sport) ret = -ENOMEM; goto err; } - sport->rx_bytes = 0; /* Prepare for TX : */ sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); @@ -1038,11 +1031,7 @@ err: static void imx_enable_dma(struct imx_port *sport) { unsigned long temp; - struct tty_port *port = &sport->port.state->port; - port->low_latency = 1; - INIT_WORK(&sport->tsk_dma_tx, dma_tx_work); - INIT_WORK(&sport->tsk_dma_rx, dma_rx_work); init_waitqueue_head(&sport->dma_wait); /* set UCR1 */ @@ -1063,7 +1052,6 @@ static void imx_enable_dma(struct imx_port *sport) static void imx_disable_dma(struct imx_port *sport) { unsigned long temp; - struct tty_port *port = &sport->port.state->port; /* clear UCR1 */ temp = readl(sport->port.membase + UCR1); @@ -1081,7 +1069,6 @@ static void imx_disable_dma(struct imx_port *sport) writel(temp, sport->port.membase + UCR4); sport->dma_is_enabled = 0; - port->low_latency = 0; } /* half the RX buffer size */ @@ -1090,7 +1077,7 @@ static void imx_disable_dma(struct imx_port *sport) static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - int retval; + int retval, i; unsigned long flags, temp; retval = clk_prepare_enable(sport->clk_per); @@ -1118,17 +1105,15 @@ static int imx_startup(struct uart_port *port) writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); - if (USE_IRDA(sport)) { - /* reset fifo's and state machines */ - int i = 100; - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && - (--i > 0)) { - udelay(1); - } - } + /* Reset fifo's and state machines */ + i = 100; + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later @@ -1136,25 +1121,25 @@ static int imx_startup(struct uart_port *port) */ if (sport->txirq > 0) { retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out1; retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out2; /* do not use RTS IRQ on IrDA */ if (!USE_IRDA(sport)) { retval = request_irq(sport->rtsirq, imx_rtsint, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) goto error_out3; } } else { retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); + dev_name(port->dev), sport); if (retval) { free_irq(sport->port.irq, sport); goto error_out1; @@ -1183,18 +1168,9 @@ static int imx_startup(struct uart_port *port) temp |= UCR2_IRTS; writel(temp, sport->port.membase + UCR2); - if (USE_IRDA(sport)) { - /* clear RX-FIFO */ - int i = 64; - while ((--i > 0) && - (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { - barrier(); - } - } - if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - temp |= IMX21_UCR3_RXDMUXSEL; + temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; writel(temp, sport->port.membase + UCR3); } @@ -1303,6 +1279,16 @@ static void imx_shutdown(struct uart_port *port) clk_disable_unprepare(sport->clk_ipg); } +static void imx_flush_buffer(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + if (sport->dma_is_enabled) { + sport->tx_bytes = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + } +} + static void imx_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -1479,44 +1465,13 @@ static const char *imx_type(struct uart_port *port) } /* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - - return ret ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void imx_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) + if (flags & UART_CONFIG_TYPE) sport->port.type = PORT_IMX; } @@ -1539,7 +1494,7 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) ret = -EINVAL; if (sport->port.uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) + if (sport->port.mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; if (sport->port.iobase != ser->port) ret = -EINVAL; @@ -1623,10 +1578,9 @@ static struct uart_ops imx_pops = { .break_ctl = imx_break_ctl, .startup = imx_startup, .shutdown = imx_shutdown, + .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, .config_port = imx_config_port, .verify_port = imx_verify_port, #if defined(CONFIG_CONSOLE_POLL) @@ -1912,9 +1866,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, sport->devdata = of_id->data; - if (of_device_is_stdout_path(np)) - add_preferred_console(imx_reg.cons->name, sport->port.line, 0); - return 0; } #else @@ -1946,7 +1897,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport, static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; - struct imxuart_platform_data *pdata; void __iomem *base; int ret = 0; struct resource *res; @@ -1962,12 +1912,9 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; @@ -2003,38 +1950,16 @@ static int serial_imx_probe(struct platform_device *pdev) imx_ports[sport->port.line] = sport; - pdata = dev_get_platdata(&pdev->dev); - if (pdata && pdata->init) { - ret = pdata->init(pdev); - if (ret) - return ret; - } - - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; platform_set_drvdata(pdev, sport); - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); - return ret; + return uart_add_one_port(&imx_reg, &sport->port); } static int serial_imx_remove(struct platform_device *pdev) { - struct imxuart_platform_data *pdata; struct imx_port *sport = platform_get_drvdata(pdev); - pdata = dev_get_platdata(&pdev->dev); - - uart_remove_one_port(&imx_reg, &sport->port); - - if (pdata && pdata->exit) - pdata->exit(pdev); - - return 0; + return uart_remove_one_port(&imx_reg, &sport->port); } static struct platform_driver serial_imx_driver = { diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index cb3c81eb099..99b7b869786 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -603,6 +603,8 @@ static void ip22zilog_start_tx(struct uart_port *port) } else { struct circ_buf *xmit = &port->state->xmit; + if (uart_circ_empty(xmit)) + return; writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -832,7 +834,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, up->curregs[5] |= Tx8; up->parity_mask = 0xff; break; - }; + } up->curregs[4] &= ~0x0c; if (cflag & CSTOPB) up->curregs[4] |= SB2; @@ -850,7 +852,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= BRK_ABRT; up->port.ignore_status_mask = 0; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 5dafcf1c227..cfadf2971b1 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/compiler.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/atomic.h> @@ -45,13 +44,22 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)"); static bool kgdb_nmi_tty_enabled; +static int kgdb_nmi_console_setup(struct console *co, char *options) +{ + /* The NMI console uses the dbg_io_ops to issue console messages. To + * avoid duplicate messages during kdb sessions we must inform kdb's + * I/O utilities that messages sent to the console will automatically + * be displayed on the dbg_io. + */ + dbg_io_ops->is_console = true; + + return 0; +} + static void kgdb_nmi_console_write(struct console *co, const char *s, uint c) { int i; - if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0) - return; - for (i = 0; i < c; i++) dbg_io_ops->write_char(s[i]); } @@ -66,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx) static struct console kgdb_nmi_console = { .name = "ttyNMI", + .setup = kgdb_nmi_console_setup, .write = kgdb_nmi_console_write, .device = kgdb_nmi_console_device, .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, @@ -81,29 +90,10 @@ static struct console kgdb_nmi_console = { struct kgdb_nmi_tty_priv { struct tty_port port; - struct tasklet_struct tlet; + struct timer_list timer; STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo; }; -static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port) -{ - return container_of(port, struct kgdb_nmi_tty_priv, port); -} - -/* - * Our debugging console is polled in a tasklet, so we'll check for input - * every tick. In HZ-less mode, we should program the next tick. We have - * to use the lowlevel stuff as no locks should be grabbed. - */ -#ifdef CONFIG_HIGH_RES_TIMERS -static void kgdb_tty_poke(void) -{ - tick_program_event(ktime_get(), 0); -} -#else -static inline void kgdb_tty_poke(void) {} -#endif - static struct tty_port *kgdb_nmi_port; static void kgdb_tty_recv(int ch) @@ -114,14 +104,13 @@ static void kgdb_tty_recv(int ch) if (!kgdb_nmi_port || ch < 0) return; /* - * Can't use port->tty->driver_data as tty might be not there. Tasklet + * Can't use port->tty->driver_data as tty might be not there. Timer * will check for tty and will get the ref, but here we don't have to * do that, and actually, we can't: we're in NMI context, no locks are * possible. */ - priv = kgdb_nmi_port_to_priv(kgdb_nmi_port); + priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port); kfifo_in(&priv->fifo, &c, 1); - kgdb_tty_poke(); } static int kgdb_nmi_poll_one_knock(void) @@ -205,7 +194,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data) struct kgdb_nmi_tty_priv *priv = (void *)data; char ch; - tasklet_schedule(&priv->tlet); + priv->timer.expires = jiffies + (HZ/100); + add_timer(&priv->timer); if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo))) return; @@ -217,18 +207,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data) static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty) { - struct kgdb_nmi_tty_priv *priv = tty->driver_data; + struct kgdb_nmi_tty_priv *priv = + container_of(port, struct kgdb_nmi_tty_priv, port); kgdb_nmi_port = port; - tasklet_schedule(&priv->tlet); + priv->timer.expires = jiffies + (HZ/100); + add_timer(&priv->timer); + return 0; } static void kgdb_nmi_tty_shutdown(struct tty_port *port) { - struct kgdb_nmi_tty_priv *priv = port->tty->driver_data; + struct kgdb_nmi_tty_priv *priv = + container_of(port, struct kgdb_nmi_tty_priv, port); - tasklet_kill(&priv->tlet); + del_timer(&priv->timer); kgdb_nmi_port = NULL; } @@ -247,7 +241,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty) return -ENOMEM; INIT_KFIFO(priv->fifo); - tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv); + setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv); tty_port_init(&priv->port); priv->port.ops = &kgdb_nmi_tty_port_ops; tty->driver_data = priv; diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 9cd9b4eba9f..5702828fb62 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -266,9 +266,11 @@ static void m32r_sio_start_tx(struct uart_port *port) if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; + if (!uart_circ_empty(xmit)) { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + } } while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY); #else @@ -737,7 +739,7 @@ static void m32r_sio_set_termios(struct uart_port *port, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index b2e707aa603..ba285cd45b5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1,7 +1,7 @@ /* * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * - * Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru> + * Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru> * * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org> * Based on max3110.c, by Feng Tang <feng.tang@intel.com> @@ -13,19 +13,21 @@ * (at your option) any later version. */ -#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/bitops.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/regmap.h> -#include <linux/gpio.h> #include <linux/spi/spi.h> - -#include <linux/platform_data/max310x.h> +#include <linux/uaccess.h> #define MAX310X_NAME "max310x" #define MAX310X_MAJOR 204 @@ -161,10 +163,6 @@ /* IRDA register bits */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ #define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ -#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ -#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ -#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ -#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ /* Flow control trigger level register masks */ #define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ @@ -220,26 +218,6 @@ * XOFF2 */ -/* GPIO configuration register bits */ -#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ -#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ -#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ -#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ -#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ -#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ -#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ -#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ - -/* GPIO DATA register bits */ -#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ -#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ -#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ -#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ -#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ -#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ -#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ -#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ - /* PLL configuration register masks */ #define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ #define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ @@ -283,16 +261,15 @@ struct max310x_devtype { struct max310x_one { struct uart_port port; struct work_struct tx_work; + struct work_struct md_work; }; struct max310x_port { struct uart_driver uart; struct max310x_devtype *devtype; struct regmap *regmap; - struct regmap_config regcfg; struct mutex mutex; - struct max310x_pdata *pdata; - int gpio_used; + struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif @@ -504,25 +481,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg) return false; } -static void max310x_set_baud(struct uart_port *port, int baud) +static int max310x_set_baud(struct uart_port *port, int baud) { - unsigned int mode = 0, div = port->uartclk / baud; + unsigned int mode = 0, clk = port->uartclk, div = clk / baud; - if (!(div / 16)) { + /* Check for minimal value for divider */ + if (div < 16) + div = 16; + + if (clk % baud && (div / 16) < 0x8000) { /* Mode x2 */ mode = MAX310X_BRGCFG_2XMODE_BIT; - div = (port->uartclk * 2) / baud; - } - - if (!(div / 16)) { - /* Mode x4 */ - mode = MAX310X_BRGCFG_4XMODE_BIT; - div = (port->uartclk * 4) / baud; + clk = port->uartclk * 2; + div = clk / baud; + + if (clk % baud && (div / 16) < 0x8000) { + /* Mode x4 */ + mode = MAX310X_BRGCFG_4XMODE_BIT; + clk = port->uartclk * 4; + div = clk / baud; + } } max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8); max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16); max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode); + + return DIV_ROUND_CLOSEST(clk, div); } static int max310x_update_best_err(unsigned long f, long *besterr) @@ -538,18 +523,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int max310x_set_ref_clk(struct max310x_port *s) +static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, + bool xtal) { unsigned int div, clksrc, pllcfg = 0; long besterr = -1; - unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; + unsigned long fdiv, fmul, bestfreq = freq; /* First, update error without PLL */ - max310x_update_best_err(s->pdata->frequency, &besterr); + max310x_update_best_err(freq, &besterr); /* Try all possible PLL dividers */ for (div = 1; (div <= 63) && besterr; div++) { - fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); + fdiv = DIV_ROUND_CLOSEST(freq, div); /* Try multiplier 6 */ fmul = fdiv * 6; @@ -582,10 +568,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) } /* Configure clock source */ - if (s->pdata->driver_flags & MAX310X_EXT_CLK) - clksrc = MAX310X_CLKSRC_EXTCLK_BIT; - else - clksrc = MAX310X_CLKSRC_CRYST_BIT; + clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT; /* Configure PLL */ if (pllcfg) { @@ -597,7 +580,7 @@ static int max310x_set_ref_clk(struct max310x_port *s) regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); /* Wait for crystal */ - if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK)) + if (pllcfg && xtal) msleep(10); return (int)bestfreq; @@ -690,7 +673,7 @@ static void max310x_handle_tx(struct uart_port *port) max310x_port_write(port, MAX310X_THR_REG, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - }; + } } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -782,11 +765,21 @@ static unsigned int max310x_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } +static void max310x_md_proc(struct work_struct *ws) +{ + struct max310x_one *one = container_of(ws, struct max310x_one, md_work); + + max310x_port_update(&one->port, MAX310X_MODE2_REG, + MAX310X_MODE2_LOOPBACK_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + MAX310X_MODE2_LOOPBACK_BIT : 0); +} + static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* DCD and DSR are not wired and CTS/RTS is hadnled automatically - * so do nothing - */ + struct max310x_one *one = container_of(port, struct max310x_one, port); + + schedule_work(&one->md_work); } static void max310x_break_ctl(struct uart_port *port, int break_state) @@ -842,7 +835,7 @@ static void max310x_set_termios(struct uart_port *port, if (termios->c_iflag & INPCK) port->read_status_mask |= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= MAX310X_LSR_RXBRK_BIT; /* Set status ignore mask */ @@ -875,40 +868,76 @@ static void max310x_set_termios(struct uart_port *port, port->uartclk / 4); /* Setup baudrate generator */ - max310x_set_baud(port, baud); + baud = max310x_set_baud(port, baud); /* Update timeout according to new baud rate */ uart_update_timeout(port, termios->c_cflag, baud); } +static int max310x_ioctl(struct uart_port *port, unsigned int cmd, + unsigned long arg) +{ +#if defined(TIOCSRS485) && defined(TIOCGRS485) + struct serial_rs485 rs485; + unsigned int val; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) + return -EFAULT; + if (rs485.delay_rts_before_send > 0x0f || + rs485.delay_rts_after_send > 0x0f) + return -ERANGE; + val = (rs485.delay_rts_before_send << 4) | + rs485.delay_rts_after_send; + max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val); + if (rs485.flags & SER_RS485_ENABLED) { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, + MAX310X_MODE1_TRNSCVCTRL_BIT); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, + MAX310X_MODE2_ECHOSUPR_BIT); + } else { + max310x_port_update(port, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, 0); + max310x_port_update(port, MAX310X_MODE2_REG, + MAX310X_MODE2_ECHOSUPR_BIT, 0); + } + return 0; + case TIOCGRS485: + memset(&rs485, 0, sizeof(rs485)); + val = max310x_port_read(port, MAX310X_MODE1_REG); + rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ? + SER_RS485_ENABLED : 0; + rs485.flags |= SER_RS485_RTS_ON_SEND; + val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG); + rs485.delay_rts_before_send = val >> 4; + rs485.delay_rts_after_send = val & 0x0f; + if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485))) + return -EFAULT; + return 0; + default: + break; + } +#endif + + return -ENOIOCTLCMD; +} + static int max310x_startup(struct uart_port *port) { - unsigned int val, line = port->line; struct max310x_port *s = dev_get_drvdata(port->dev); + unsigned int val; s->devtype->power(port, 1); - /* Configure baud rate, 9600 as default */ - max310x_set_baud(port, 9600); - - /* Configure LCR register, 8N1 mode by default */ - max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8); - /* Configure MODE1 register */ max310x_port_update(port, MAX310X_MODE1_REG, - MAX310X_MODE1_TRNSCVCTRL_BIT, - (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL) - ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0); - - /* Configure MODE2 register */ - val = MAX310X_MODE2_RXEMPTINV_BIT; - if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK) - val |= MAX310X_MODE2_LOOPBACK_BIT; - if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) - val |= MAX310X_MODE2_ECHOSUPR_BIT; - - /* Reset FIFOs */ - val |= MAX310X_MODE2_FIFORST_BIT; + MAX310X_MODE1_TRNSCVCTRL_BIT, 0); + + /* Configure MODE2 register & Reset FIFOs*/ + val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT; max310x_port_write(port, MAX310X_MODE2_REG, val); max310x_port_update(port, MAX310X_MODE2_REG, MAX310X_MODE2_FIFORST_BIT, 0); @@ -989,6 +1018,7 @@ static const struct uart_ops max310x_ops = { .release_port = max310x_null_void, .config_port = max310x_config_port, .verify_port = max310x_verify_port, + .ioctl = max310x_ioctl, }; static int __maybe_unused max310x_suspend(struct device *dev) @@ -1017,6 +1047,8 @@ static int __maybe_unused max310x_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); + #ifdef CONFIG_GPIOLIB static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) { @@ -1063,23 +1095,16 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip, } #endif -static int max310x_probe(struct device *dev, int is_spi, - struct max310x_devtype *devtype, int irq) +static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, + struct regmap *regmap, int irq, unsigned long flags) { + int i, ret, fmin, fmax, freq, uartclk; + struct clk *clk_osc, *clk_xtal; struct max310x_port *s; - struct max310x_pdata *pdata = dev_get_platdata(dev); - int i, ret, uartclk; + bool xtal = false; - /* Check for IRQ */ - if (irq <= 0) { - dev_err(dev, "No IRQ specified\n"); - return -ENOTSUPP; - } - - if (!pdata) { - dev_err(dev, "No platform data supplied\n"); - return -EINVAL; - } + if (IS_ERR(regmap)) + return PTR_ERR(regmap); /* Alloc port structure */ s = devm_kzalloc(dev, sizeof(*s) + @@ -1089,52 +1114,44 @@ static int max310x_probe(struct device *dev, int is_spi, return -ENOMEM; } - /* Check input frequency */ - if ((pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) - goto err_freq; - /* Check frequency for quartz */ - if (!(pdata->driver_flags & MAX310X_EXT_CLK) && - ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) - goto err_freq; - - s->pdata = pdata; - s->devtype = devtype; - dev_set_drvdata(dev, s); - - mutex_init(&s->mutex); + clk_osc = devm_clk_get(dev, "osc"); + clk_xtal = devm_clk_get(dev, "xtal"); + if (!IS_ERR(clk_osc)) { + s->clk = clk_osc; + fmin = 500000; + fmax = 35000000; + } else if (!IS_ERR(clk_xtal)) { + s->clk = clk_xtal; + fmin = 1000000; + fmax = 4000000; + xtal = true; + } else if (PTR_ERR(clk_osc) == -EPROBE_DEFER || + PTR_ERR(clk_xtal) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else { + dev_err(dev, "Cannot get clock\n"); + return -EINVAL; + } - /* Setup regmap */ - s->regcfg.reg_bits = 8; - s->regcfg.val_bits = 8; - s->regcfg.read_flag_mask = 0x00; - s->regcfg.write_flag_mask = 0x80; - s->regcfg.cache_type = REGCACHE_RBTREE; - s->regcfg.writeable_reg = max310x_reg_writeable; - s->regcfg.volatile_reg = max310x_reg_volatile; - s->regcfg.precious_reg = max310x_reg_precious; - s->regcfg.max_register = devtype->nr * 0x20 - 1; - - if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) { - struct spi_device *spi = to_spi_device(dev); - - s->regmap = devm_regmap_init_spi(spi, &s->regcfg); - } else - return -ENOTSUPP; + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; - if (IS_ERR(s->regmap)) { - dev_err(dev, "Failed to initialize register map\n"); - return PTR_ERR(s->regmap); + freq = clk_get_rate(s->clk); + /* Check frequency limits */ + if (freq < fmin || freq > fmax) { + ret = -ERANGE; + goto out_clk; } - /* Board specific configure */ - if (s->pdata->init) - s->pdata->init(); + s->regmap = regmap; + s->devtype = devtype; + dev_set_drvdata(dev, s); /* Check device to ensure we are talking to what we expect */ ret = devtype->detect(dev); if (ret) - return ret; + goto out_clk; for (i = 0; i < devtype->nr; i++) { unsigned int offs = i << 5; @@ -1156,7 +1173,7 @@ static int max310x_probe(struct device *dev, int is_spi, MAX310X_MODE1_AUTOSLEEP_BIT); } - uartclk = max310x_set_ref_clk(s); + uartclk = max310x_set_ref_clk(s, freq, xtal); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); /* Register UART driver */ @@ -1168,9 +1185,28 @@ static int max310x_probe(struct device *dev, int is_spi, ret = uart_register_driver(&s->uart); if (ret) { dev_err(dev, "Registering UART driver failed\n"); - return ret; + goto out_clk; } +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr * 4; + s->gpio.can_sleep = 1; + ret = gpiochip_add(&s->gpio); + if (ret) + goto out_uart; +#endif + + mutex_init(&s->mutex); + for (i = 0; i < devtype->nr; i++) { /* Initialize port data */ s->p[i].port.line = i; @@ -1178,8 +1214,7 @@ static int max310x_probe(struct device *dev, int is_spi, s->p[i].port.irq = irq; s->p[i].port.type = PORT_MAX310X; s->p[i].port.fifosize = MAX310X_FIFO_SIZE; - s->p[i].port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE | - UPF_LOW_LATENCY; + s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; s->p[i].port.iotype = UPIO_PORT; s->p[i].port.iobase = i * 0x20; s->p[i].port.membase = (void __iomem *)~0; @@ -1195,48 +1230,35 @@ static int max310x_probe(struct device *dev, int is_spi, MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); + /* Initialize queue for changing mode */ + INIT_WORK(&s->p[i].md_work, max310x_md_proc); /* Register port */ uart_add_one_port(&s->uart, &s->p[i].port); /* Go to suspend mode */ devtype->power(&s->p[i].port, 0); } -#ifdef CONFIG_GPIOLIB - /* Setup GPIO cotroller */ - if (s->pdata->gpio_base) { - s->gpio.owner = THIS_MODULE; - s->gpio.dev = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = max310x_gpio_direction_input; - s->gpio.get = max310x_gpio_get; - s->gpio.direction_output= max310x_gpio_direction_output; - s->gpio.set = max310x_gpio_set; - s->gpio.base = s->pdata->gpio_base; - s->gpio.ngpio = devtype->nr * 4; - s->gpio.can_sleep = 1; - if (!gpiochip_add(&s->gpio)) - s->gpio_used = 1; - } else - dev_info(dev, "GPIO support not enabled\n"); -#endif - /* Setup interrupt */ ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(dev), s); - if (ret) { - dev_err(dev, "Unable to reguest IRQ %i\n", irq); + IRQF_ONESHOT | flags, dev_name(dev), s); + if (!ret) + return 0; + + dev_err(dev, "Unable to reguest IRQ %i\n", irq); + + mutex_destroy(&s->mutex); + #ifdef CONFIG_GPIOLIB - if (s->gpio_used) - WARN_ON(gpiochip_remove(&s->gpio)); + WARN_ON(gpiochip_remove(&s->gpio)); + +out_uart: #endif - } + uart_unregister_driver(&s->uart); - return ret; +out_clk: + clk_disable_unprepare(s->clk); -err_freq: - dev_err(dev, "Frequency parameter incorrect\n"); - return -EINVAL; + return ret; } static int max310x_remove(struct device *dev) @@ -1244,30 +1266,51 @@ static int max310x_remove(struct device *dev) struct max310x_port *s = dev_get_drvdata(dev); int i, ret = 0; +#ifdef CONFIG_GPIOLIB + ret = gpiochip_remove(&s->gpio); + if (ret) + return ret; +#endif + for (i = 0; i < s->uart.nr; i++) { cancel_work_sync(&s->p[i].tx_work); + cancel_work_sync(&s->p[i].md_work); uart_remove_one_port(&s->uart, &s->p[i].port); s->devtype->power(&s->p[i].port, 0); } + mutex_destroy(&s->mutex); uart_unregister_driver(&s->uart); - -#ifdef CONFIG_GPIOLIB - if (s->gpio_used) - ret = gpiochip_remove(&s->gpio); -#endif - - if (s->pdata->exit) - s->pdata->exit(); + clk_disable_unprepare(s->clk); return ret; } +static const struct of_device_id __maybe_unused max310x_dt_ids[] = { + { .compatible = "maxim,max3107", .data = &max3107_devtype, }, + { .compatible = "maxim,max3108", .data = &max3108_devtype, }, + { .compatible = "maxim,max3109", .data = &max3109_devtype, }, + { .compatible = "maxim,max14830", .data = &max14830_devtype }, + { } +}; +MODULE_DEVICE_TABLE(of, max310x_dt_ids); + +static struct regmap_config regcfg = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = 0x80, + .cache_type = REGCACHE_RBTREE, + .writeable_reg = max310x_reg_writeable, + .volatile_reg = max310x_reg_volatile, + .precious_reg = max310x_reg_precious, +}; + #ifdef CONFIG_SPI_MASTER static int max310x_spi_probe(struct spi_device *spi) { - struct max310x_devtype *devtype = - (struct max310x_devtype *)spi_get_device_id(spi)->driver_data; + struct max310x_devtype *devtype; + unsigned long flags = 0; + struct regmap *regmap; int ret; /* Setup SPI bus */ @@ -1275,12 +1318,25 @@ static int max310x_spi_probe(struct spi_device *spi) spi->mode = spi->mode ? : SPI_MODE_0; spi->max_speed_hz = spi->max_speed_hz ? : 26000000; ret = spi_setup(spi); - if (ret) { - dev_err(&spi->dev, "SPI setup failed\n"); + if (ret) return ret; + + if (spi->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(max310x_dt_ids, &spi->dev); + + devtype = (struct max310x_devtype *)of_id->data; + } else { + const struct spi_device_id *id_entry = spi_get_device_id(spi); + + devtype = (struct max310x_devtype *)id_entry->driver_data; + flags = IRQF_TRIGGER_FALLING; } - return max310x_probe(&spi->dev, 1, devtype, spi->irq); + regcfg.max_register = devtype->nr * 0x20 - 1; + regmap = devm_regmap_init_spi(spi, ®cfg); + + return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags); } static int max310x_spi_remove(struct spi_device *spi) @@ -1288,8 +1344,6 @@ static int max310x_spi_remove(struct spi_device *spi) return max310x_remove(&spi->dev); } -static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume); - static const struct spi_device_id max310x_id_table[] = { { "max3107", (kernel_ulong_t)&max3107_devtype, }, { "max3108", (kernel_ulong_t)&max3108_devtype, }, @@ -1301,9 +1355,10 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_uart_driver = { .driver = { - .name = MAX310X_NAME, - .owner = THIS_MODULE, - .pm = &max310x_pm_ops, + .name = MAX310X_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max310x_dt_ids), + .pm = &max310x_pm_ops, }, .probe = max310x_spi_probe, .remove = max310x_spi_remove, diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 0edfaf8cd26..a6f085717f9 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -248,6 +248,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, mr1 |= MCFUART_MR1_PARITYNONE; } + /* + * FIXME: port->read_status_mask and port->ignore_status_mask + * need to be initialized based on termios settings for + * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT + */ + if (termios->c_cflag & CSTOPB) mr2 |= MCFUART_MR2_STOP2; else diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c new file mode 100644 index 00000000000..c9d18548783 --- /dev/null +++ b/drivers/tty/serial/men_z135_uart.c @@ -0,0 +1,867 @@ +/* + * MEN 16z135 High Speed UART + * + * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de) + * Author: Johannes Thumshirn <johannes.thumshirn@men.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2 of the License. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/serial_core.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/tty_flip.h> +#include <linux/bitops.h> +#include <linux/mcb.h> + +#define MEN_Z135_MAX_PORTS 12 +#define MEN_Z135_BASECLK 29491200 +#define MEN_Z135_FIFO_SIZE 1024 +#define MEN_Z135_NUM_MSI_VECTORS 2 +#define MEN_Z135_FIFO_WATERMARK 1020 + +#define MEN_Z135_STAT_REG 0x0 +#define MEN_Z135_RX_RAM 0x4 +#define MEN_Z135_TX_RAM 0x400 +#define MEN_Z135_RX_CTRL 0x800 +#define MEN_Z135_TX_CTRL 0x804 +#define MEN_Z135_CONF_REG 0x808 +#define MEN_Z135_UART_FREQ 0x80c +#define MEN_Z135_BAUD_REG 0x810 +#define MENZ135_TIMEOUT 0x814 + +#define MEN_Z135_MEM_SIZE 0x818 + +#define IS_IRQ(x) ((x) & 1) +#define IRQ_ID(x) (((x) >> 1) & 7) + +#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */ +#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */ +#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */ +#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */ +#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \ + | MEN_Z135_IER_RLSIEN \ + | MEN_Z135_IER_MSIEN \ + | MEN_Z135_IER_TXCIEN) + +#define MEN_Z135_MCR_DTR BIT(24) +#define MEN_Z135_MCR_RTS BIT(25) +#define MEN_Z135_MCR_OUT1 BIT(26) +#define MEN_Z135_MCR_OUT2 BIT(27) +#define MEN_Z135_MCR_LOOP BIT(28) +#define MEN_Z135_MCR_RCFC BIT(29) + +#define MEN_Z135_MSR_DCTS BIT(0) +#define MEN_Z135_MSR_DDSR BIT(1) +#define MEN_Z135_MSR_DRI BIT(2) +#define MEN_Z135_MSR_DDCD BIT(3) +#define MEN_Z135_MSR_CTS BIT(4) +#define MEN_Z135_MSR_DSR BIT(5) +#define MEN_Z135_MSR_RI BIT(6) +#define MEN_Z135_MSR_DCD BIT(7) + +#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */ + +#define MEN_Z135_WL5 0 /* CS5 */ +#define MEN_Z135_WL6 1 /* CS6 */ +#define MEN_Z135_WL7 2 /* CS7 */ +#define MEN_Z135_WL8 3 /* CS8 */ + +#define MEN_Z135_STB_SHIFT 2 /* Stopbits */ +#define MEN_Z135_NSTB1 0 +#define MEN_Z135_NSTB2 1 + +#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */ +#define MEN_Z135_PAR_DIS 0 +#define MEN_Z135_PAR_ENA 1 + +#define MEN_Z135_PTY_SHIFT 4 /* Parity type */ +#define MEN_Z135_PTY_ODD 0 +#define MEN_Z135_PTY_EVN 1 + +#define MEN_Z135_LSR_DR BIT(0) +#define MEN_Z135_LSR_OE BIT(1) +#define MEN_Z135_LSR_PE BIT(2) +#define MEN_Z135_LSR_FE BIT(3) +#define MEN_Z135_LSR_BI BIT(4) +#define MEN_Z135_LSR_THEP BIT(5) +#define MEN_Z135_LSR_TEXP BIT(6) +#define MEN_Z135_LSR_RXFIFOERR BIT(7) + +#define MEN_Z135_IRQ_ID_MST 0 +#define MEN_Z135_IRQ_ID_TSA 1 +#define MEN_Z135_IRQ_ID_RDA 2 +#define MEN_Z135_IRQ_ID_RLS 3 +#define MEN_Z135_IRQ_ID_CTI 6 + +#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff) + +#define BYTES_TO_ALIGN(x) ((x) & 0x3) + +static int line; + +static int txlvl = 5; +module_param(txlvl, int, S_IRUGO); +MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)"); + +static int rxlvl = 6; +module_param(rxlvl, int, S_IRUGO); +MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)"); + +static int align; +module_param(align, int, S_IRUGO); +MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0"); + +struct men_z135_port { + struct uart_port port; + struct mcb_device *mdev; + unsigned char *rxbuf; + u32 stat_reg; + spinlock_t lock; +}; +#define to_men_z135(port) container_of((port), struct men_z135_port, port) + +/** + * men_z135_reg_set() - Set value in register + * @uart: The UART port + * @addr: Register address + * @val: value to set + */ +static inline void men_z135_reg_set(struct men_z135_port *uart, + u32 addr, u32 val) +{ + struct uart_port *port = &uart->port; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&uart->lock, flags); + + reg = ioread32(port->membase + addr); + reg |= val; + iowrite32(reg, port->membase + addr); + + spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_reg_clr() - Unset value in register + * @uart: The UART port + * @addr: Register address + * @val: value to clear + */ +static inline void men_z135_reg_clr(struct men_z135_port *uart, + u32 addr, u32 val) +{ + struct uart_port *port = &uart->port; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&uart->lock, flags); + + reg = ioread32(port->membase + addr); + reg &= ~val; + iowrite32(reg, port->membase + addr); + + spin_unlock_irqrestore(&uart->lock, flags); +} + +/** + * men_z135_handle_modem_status() - Handle change of modem status + * @port: The UART port + * + * Handle change of modem status register. This is done by reading the "delta" + * versions of DCD (Data Carrier Detect) and CTS (Clear To Send). + */ +static void men_z135_handle_modem_status(struct men_z135_port *uart) +{ + if (uart->stat_reg & MEN_Z135_MSR_DDCD) + uart_handle_dcd_change(&uart->port, + uart->stat_reg & ~MEN_Z135_MSR_DCD); + if (uart->stat_reg & MEN_Z135_MSR_DCTS) + uart_handle_cts_change(&uart->port, + uart->stat_reg & ~MEN_Z135_MSR_CTS); +} + +static void men_z135_handle_lsr(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + u8 lsr; + + lsr = (uart->stat_reg >> 16) & 0xff; + + if (lsr & MEN_Z135_LSR_OE) + port->icount.overrun++; + if (lsr & MEN_Z135_LSR_PE) + port->icount.parity++; + if (lsr & MEN_Z135_LSR_FE) + port->icount.frame++; + if (lsr & MEN_Z135_LSR_BI) { + port->icount.brk++; + uart_handle_break(port); + } +} + +/** + * get_rx_fifo_content() - Get the number of bytes in RX FIFO + * @uart: The UART port + * + * Read RXC register from hardware and return current FIFO fill size. + */ +static u16 get_rx_fifo_content(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + u32 stat_reg; + u16 rxc; + u8 rxc_lo; + u8 rxc_hi; + + stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + rxc_lo = stat_reg >> 24; + rxc_hi = (stat_reg & 0xC0) >> 6; + + rxc = rxc_lo | (rxc_hi << 8); + + return rxc; +} + +/** + * men_z135_handle_rx() - RX tasklet routine + * @arg: Pointer to struct men_z135_port + * + * Copy from RX FIFO and acknowledge number of bytes copied. + */ +static void men_z135_handle_rx(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + struct tty_port *tport = &port->state->port; + int copied; + u16 size; + int room; + + size = get_rx_fifo_content(uart); + + if (size == 0) + return; + + /* Avoid accidently accessing TX FIFO instead of RX FIFO. Last + * longword in RX FIFO cannot be read.(0x004-0x3FF) + */ + if (size > MEN_Z135_FIFO_WATERMARK) + size = MEN_Z135_FIFO_WATERMARK; + + room = tty_buffer_request_room(tport, size); + if (room != size) + dev_warn(&uart->mdev->dev, + "Not enough room in flip buffer, truncating to %d\n", + room); + + if (room == 0) + return; + + memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room); + /* Be sure to first copy all data and then acknowledge it */ + mb(); + iowrite32(room, port->membase + MEN_Z135_RX_CTRL); + + copied = tty_insert_flip_string(tport, uart->rxbuf, room); + if (copied != room) + dev_warn(&uart->mdev->dev, + "Only copied %d instead of %d bytes\n", + copied, room); + + port->icount.rx += copied; + + tty_flip_buffer_push(tport); + +} + +/** + * men_z135_handle_tx() - TX tasklet routine + * @arg: Pointer to struct men_z135_port + * + */ +static void men_z135_handle_tx(struct men_z135_port *uart) +{ + struct uart_port *port = &uart->port; + struct circ_buf *xmit = &port->state->xmit; + u32 txc; + u32 wptr; + int qlen; + int n; + int txfree; + int head; + int tail; + int s; + + if (uart_circ_empty(xmit)) + goto out; + + if (uart_tx_stopped(port)) + goto out; + + if (port->x_char) + goto out; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + /* calculate bytes to copy */ + qlen = uart_circ_chars_pending(xmit); + if (qlen <= 0) + goto out; + + wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); + txc = (wptr >> 16) & 0x3ff; + wptr &= 0x3ff; + + if (txc > MEN_Z135_FIFO_WATERMARK) + txc = MEN_Z135_FIFO_WATERMARK; + + txfree = MEN_Z135_FIFO_WATERMARK - txc; + if (txfree <= 0) { + pr_err("Not enough room in TX FIFO have %d, need %d\n", + txfree, qlen); + goto irq_en; + } + + /* if we're not aligned, it's better to copy only 1 or 2 bytes and + * then the rest. + */ + if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr)) + n = 4 - BYTES_TO_ALIGN(wptr); + else if (qlen > txfree) + n = txfree; + else + n = qlen; + + if (n <= 0) + goto irq_en; + + head = xmit->head & (UART_XMIT_SIZE - 1); + tail = xmit->tail & (UART_XMIT_SIZE - 1); + + s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; + n = min(n, s); + + memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n); + xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1); + mmiowb(); + + iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL); + + port->icount.tx += n; + +irq_en: + if (!uart_circ_empty(xmit)) + men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); + else + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); + +out: + return; + +} + +/** + * men_z135_intr() - Handle legacy IRQs + * @irq: The IRQ number + * @data: Pointer to UART port + * + * Check IIR register to see which tasklet to start. + */ +static irqreturn_t men_z135_intr(int irq, void *data) +{ + struct men_z135_port *uart = (struct men_z135_port *)data; + struct uart_port *port = &uart->port; + int irq_id; + + uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + /* IRQ pending is low active */ + if (IS_IRQ(uart->stat_reg)) + return IRQ_NONE; + + irq_id = IRQ_ID(uart->stat_reg); + switch (irq_id) { + case MEN_Z135_IRQ_ID_MST: + men_z135_handle_modem_status(uart); + break; + case MEN_Z135_IRQ_ID_TSA: + men_z135_handle_tx(uart); + break; + case MEN_Z135_IRQ_ID_CTI: + dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n"); + /* Fallthrough */ + case MEN_Z135_IRQ_ID_RDA: + /* Reading data clears RX IRQ */ + men_z135_handle_rx(uart); + break; + case MEN_Z135_IRQ_ID_RLS: + men_z135_handle_lsr(uart); + break; + default: + dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +/** + * men_z135_request_irq() - Request IRQ for 16z135 core + * @uart: z135 private uart port structure + * + * Request an IRQ for 16z135 to use. First try using MSI, if it fails + * fall back to using legacy interrupts. + */ +static int men_z135_request_irq(struct men_z135_port *uart) +{ + struct device *dev = &uart->mdev->dev; + struct uart_port *port = &uart->port; + int err = 0; + + err = request_irq(port->irq, men_z135_intr, IRQF_SHARED, + "men_z135_intr", uart); + if (err) + dev_err(dev, "Error %d getting interrupt\n", err); + + return err; +} + +/** + * men_z135_tx_empty() - Handle tx_empty call + * @port: The UART port + * + * This function tests whether the TX FIFO and shifter for the port + * described by @port is empty. + */ +static unsigned int men_z135_tx_empty(struct uart_port *port) +{ + u32 wptr; + u16 txc; + + wptr = ioread32(port->membase + MEN_Z135_TX_CTRL); + txc = (wptr >> 16) & 0x3ff; + + if (txc == 0) + return TIOCSER_TEMT; + else + return 0; +} + +/** + * men_z135_set_mctrl() - Set modem control lines + * @port: The UART port + * @mctrl: The modem control lines + * + * This function sets the modem control lines for a port described by @port + * to the state described by @mctrl + */ +static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct men_z135_port *uart = to_men_z135(port); + u32 conf_reg = 0; + + if (mctrl & TIOCM_RTS) + conf_reg |= MEN_Z135_MCR_RTS; + if (mctrl & TIOCM_DTR) + conf_reg |= MEN_Z135_MCR_DTR; + if (mctrl & TIOCM_OUT1) + conf_reg |= MEN_Z135_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + conf_reg |= MEN_Z135_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + conf_reg |= MEN_Z135_MCR_LOOP; + + men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg); +} + +/** + * men_z135_get_mctrl() - Get modem control lines + * @port: The UART port + * + * Retruns the current state of modem control inputs. + */ +static unsigned int men_z135_get_mctrl(struct uart_port *port) +{ + unsigned int mctrl = 0; + u32 stat_reg; + u8 msr; + + stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG); + + msr = ~((stat_reg >> 8) & 0xff); + + if (msr & MEN_Z135_MSR_CTS) + mctrl |= TIOCM_CTS; + if (msr & MEN_Z135_MSR_DSR) + mctrl |= TIOCM_DSR; + if (msr & MEN_Z135_MSR_RI) + mctrl |= TIOCM_RI; + if (msr & MEN_Z135_MSR_DCD) + mctrl |= TIOCM_CAR; + + return mctrl; +} + +/** + * men_z135_stop_tx() - Stop transmitting characters + * @port: The UART port + * + * Stop transmitting characters. This might be due to CTS line becomming + * inactive or the tty layer indicating we want to stop transmission due to + * an XOFF character. + */ +static void men_z135_stop_tx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN); +} + +/** + * men_z135_start_tx() - Start transmitting characters + * @port: The UART port + * + * Start transmitting character. This actually doesn't transmit anything, but + * fires off the TX tasklet. + */ +static void men_z135_start_tx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_handle_tx(uart); +} + +/** + * men_z135_stop_rx() - Stop receiving characters + * @port: The UART port + * + * Stop receiving characters; the port is in the process of being closed. + */ +static void men_z135_stop_rx(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN); +} + +/** + * men_z135_enable_ms() - Enable Modem Status + * port: + * + * Enable Modem Status IRQ. + */ +static void men_z135_enable_ms(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + + men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN); +} + +static int men_z135_startup(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + int err; + u32 conf_reg = 0; + + err = men_z135_request_irq(uart); + if (err) + return -ENODEV; + + conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); + + /* Activate all but TX space available IRQ */ + conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN; + conf_reg &= ~(0xff << 16); + conf_reg |= (txlvl << 16); + conf_reg |= (rxlvl << 20); + + iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + + return 0; +} + +static void men_z135_shutdown(struct uart_port *port) +{ + struct men_z135_port *uart = to_men_z135(port); + u32 conf_reg = 0; + + conf_reg |= MEN_Z135_ALL_IRQS; + + men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg); + + free_irq(uart->port.irq, uart); +} + +static void men_z135_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud; + u32 conf_reg; + u32 bd_reg; + u32 uart_freq; + u8 lcr; + + conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG); + lcr = LCR(conf_reg); + + /* byte size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr |= MEN_Z135_WL5; + break; + case CS6: + lcr |= MEN_Z135_WL6; + break; + case CS7: + lcr |= MEN_Z135_WL7; + break; + case CS8: + lcr |= MEN_Z135_WL8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT; + + /* parity */ + if (termios->c_cflag & PARENB) { + lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT; + + if (termios->c_cflag & PARODD) + lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT; + else + lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT; + } else + lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT; + + termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ + + conf_reg |= lcr << MEN_Z135_LCR_SHIFT; + iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG); + + uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ); + if (uart_freq == 0) + uart_freq = MEN_Z135_BASECLK; + + baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16); + + spin_lock(&port->lock); + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + bd_reg = uart_freq / (4 * baud); + iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG); + + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock(&port->lock); +} + +static const char *men_z135_type(struct uart_port *port) +{ + return KBUILD_MODNAME; +} + +static void men_z135_release_port(struct uart_port *port) +{ + iounmap(port->membase); + port->membase = NULL; + + release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); +} + +static int men_z135_request_port(struct uart_port *port) +{ + int size = MEN_Z135_MEM_SIZE; + + if (!request_mem_region(port->mapbase, size, "men_z135_port")) + return -EBUSY; + + port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE); + if (port->membase == NULL) { + release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); + return -ENOMEM; + } + + return 0; +} + +static void men_z135_config_port(struct uart_port *port, int type) +{ + port->type = PORT_MEN_Z135; + men_z135_request_port(port); +} + +static int men_z135_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + return -EINVAL; +} + +static struct uart_ops men_z135_ops = { + .tx_empty = men_z135_tx_empty, + .set_mctrl = men_z135_set_mctrl, + .get_mctrl = men_z135_get_mctrl, + .stop_tx = men_z135_stop_tx, + .start_tx = men_z135_start_tx, + .stop_rx = men_z135_stop_rx, + .enable_ms = men_z135_enable_ms, + .startup = men_z135_startup, + .shutdown = men_z135_shutdown, + .set_termios = men_z135_set_termios, + .type = men_z135_type, + .release_port = men_z135_release_port, + .request_port = men_z135_request_port, + .config_port = men_z135_config_port, + .verify_port = men_z135_verify_port, +}; + +static struct uart_driver men_z135_driver = { + .owner = THIS_MODULE, + .driver_name = KBUILD_MODNAME, + .dev_name = "ttyHSU", + .major = 0, + .minor = 0, + .nr = MEN_Z135_MAX_PORTS, +}; + +/** + * men_z135_probe() - Probe a z135 instance + * @mdev: The MCB device + * @id: The MCB device ID + * + * men_z135_probe does the basic setup of hardware resources and registers the + * new uart port to the tty layer. + */ +static int men_z135_probe(struct mcb_device *mdev, + const struct mcb_device_id *id) +{ + struct men_z135_port *uart; + struct resource *mem; + struct device *dev; + int err; + + dev = &mdev->dev; + + uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL); + if (!uart) + return -ENOMEM; + + uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!uart->rxbuf) + return -ENOMEM; + + mem = &mdev->mem; + + mcb_set_drvdata(mdev, uart); + + uart->port.uartclk = MEN_Z135_BASECLK * 16; + uart->port.fifosize = MEN_Z135_FIFO_SIZE; + uart->port.iotype = UPIO_MEM; + uart->port.ops = &men_z135_ops; + uart->port.irq = mcb_get_irq(mdev); + uart->port.iotype = UPIO_MEM; + uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; + uart->port.line = line++; + uart->port.dev = dev; + uart->port.type = PORT_MEN_Z135; + uart->port.mapbase = mem->start; + uart->port.membase = NULL; + uart->mdev = mdev; + + spin_lock_init(&uart->port.lock); + spin_lock_init(&uart->lock); + + err = uart_add_one_port(&men_z135_driver, &uart->port); + if (err) + goto err; + + return 0; + +err: + free_page((unsigned long) uart->rxbuf); + dev_err(dev, "Failed to add UART: %d\n", err); + + return err; +} + +/** + * men_z135_remove() - Remove a z135 instance from the system + * + * @mdev: The MCB device + */ +static void men_z135_remove(struct mcb_device *mdev) +{ + struct men_z135_port *uart = mcb_get_drvdata(mdev); + + line--; + uart_remove_one_port(&men_z135_driver, &uart->port); + free_page((unsigned long) uart->rxbuf); +} + +static const struct mcb_device_id men_z135_ids[] = { + { .device = 0x87 }, +}; +MODULE_DEVICE_TABLE(mcb, men_z135_ids); + +static struct mcb_driver mcb_driver = { + .driver = { + .name = "z135-uart", + .owner = THIS_MODULE, + }, + .probe = men_z135_probe, + .remove = men_z135_remove, + .id_table = men_z135_ids, +}; + +/** + * men_z135_init() - Driver Registration Routine + * + * men_z135_init is the first routine called when the driver is loaded. All it + * does is register with the legacy MEN Chameleon subsystem. + */ +static int __init men_z135_init(void) +{ + int err; + + err = uart_register_driver(&men_z135_driver); + if (err) { + pr_err("Failed to register UART: %d\n", err); + return err; + } + + err = mcb_register_driver(&mcb_driver); + if (err) { + pr_err("Failed to register MCB driver: %d\n", err); + uart_unregister_driver(&men_z135_driver); + return err; + } + + return 0; +} +module_init(men_z135_init); + +/** + * men_z135_exit() - Driver Exit Routine + * + * men_z135_exit is called just before the driver is removed from memory. + */ +static void __exit men_z135_exit(void) +{ + mcb_unregister_driver(&mcb_driver); + uart_unregister_driver(&men_z135_driver); +} +module_exit(men_z135_exit); + +MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); +MODULE_ALIAS("mcb:16z135"); diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index d3db042f649..445799dc984 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -293,7 +293,7 @@ static void serial_hsu_enable_ms(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -void hsu_dma_tx(struct uart_hsu_port *up) +static void hsu_dma_tx(struct uart_hsu_port *up) { struct circ_buf *xmit = &up->port.state->xmit; struct hsu_dma_buffer *dbuf = &up->txbuf; @@ -340,7 +340,8 @@ void hsu_dma_tx(struct uart_hsu_port *up) } /* The buffer is already cache coherent */ -void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) +static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, + struct hsu_dma_buffer *dbuf) { dbuf->ofs = 0; @@ -386,7 +387,8 @@ static void serial_hsu_stop_tx(struct uart_port *port) /* This is always called in spinlock protected mode, so * modify timeout timer is safe here */ -void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, unsigned long *flags) +static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, + unsigned long *flags) { struct hsu_dma_buffer *dbuf = &up->rxbuf; struct hsu_dma_chan *chan = up->rxc; @@ -975,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* Characters to ignore */ @@ -1183,7 +1185,7 @@ static struct console serial_hsu_console = { #define SERIAL_HSU_CONSOLE NULL #endif -struct uart_ops serial_hsu_pops = { +static struct uart_ops serial_hsu_pops = { .tx_empty = serial_hsu_tx_empty, .set_mctrl = serial_hsu_set_mctrl, .get_mctrl = serial_hsu_get_mctrl, @@ -1451,7 +1453,6 @@ static void serial_hsu_remove(struct pci_dev *pdev) uart_remove_one_port(&serial_hsu_reg, &up->port); } - pci_set_drvdata(pdev, NULL); free_irq(pdev->irq, priv); pci_disable_device(pdev); } @@ -1504,4 +1505,4 @@ module_init(hsu_pci_init); module_exit(hsu_pci_exit); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:medfield-hsu"); +MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 5be1df39f9f..97888f4900e 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -421,6 +421,7 @@ struct psc_fifoc { static struct psc_fifoc __iomem *psc_fifoc; static unsigned int psc_fifoc_irq; +static struct clk *psc_fifoc_clk; static void mpc512x_psc_fifo_init(struct uart_port *port) { @@ -568,36 +569,73 @@ static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port, /* Init PSC FIFO Controller */ static int __init mpc512x_psc_fifoc_init(void) { + int err; struct device_node *np; + struct clk *clk; + + /* default error code, potentially overwritten by clock calls */ + err = -ENODEV; np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-psc-fifo"); if (!np) { pr_err("%s: Can't find FIFOC node\n", __func__); - return -ENODEV; + goto out_err; + } + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + /* backwards compat with device trees that lack clock specs */ + clk = clk_get_sys(np->name, "ipg"); + } + if (IS_ERR(clk)) { + pr_err("%s: Can't lookup FIFO clock\n", __func__); + err = PTR_ERR(clk); + goto out_ofnode_put; } + if (clk_prepare_enable(clk)) { + pr_err("%s: Can't enable FIFO clock\n", __func__); + clk_put(clk); + goto out_ofnode_put; + } + psc_fifoc_clk = clk; psc_fifoc = of_iomap(np, 0); if (!psc_fifoc) { pr_err("%s: Can't map FIFOC\n", __func__); - of_node_put(np); - return -ENODEV; + goto out_clk_disable; } psc_fifoc_irq = irq_of_parse_and_map(np, 0); - of_node_put(np); if (psc_fifoc_irq == 0) { pr_err("%s: Can't get FIFOC irq\n", __func__); - iounmap(psc_fifoc); - return -ENODEV; + goto out_unmap; } + of_node_put(np); return 0; + +out_unmap: + iounmap(psc_fifoc); +out_clk_disable: + clk_disable_unprepare(psc_fifoc_clk); + clk_put(psc_fifoc_clk); +out_ofnode_put: + of_node_put(np); +out_err: + return err; } static void __exit mpc512x_psc_fifoc_uninit(void) { iounmap(psc_fifoc); + + /* disable the clock, errors are not fatal */ + if (psc_fifoc_clk) { + clk_disable_unprepare(psc_fifoc_clk); + clk_put(psc_fifoc_clk); + psc_fifoc_clk = NULL; + } } /* 512x specific interrupt handler. The caller holds the port lock */ @@ -619,29 +657,55 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) } static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM]; +static struct clk *psc_ipg_clk[MPC52xx_PSC_MAXNUM]; /* called from within the .request_port() callback (allocation) */ static int mpc512x_psc_alloc_clock(struct uart_port *port) { int psc_num; - char clk_name[16]; struct clk *clk; int err; psc_num = (port->mapbase & 0xf00) >> 8; - snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); - clk = devm_clk_get(port->dev, clk_name); + + clk = devm_clk_get(port->dev, "mclk"); if (IS_ERR(clk)) { dev_err(port->dev, "Failed to get MCLK!\n"); - return PTR_ERR(clk); + err = PTR_ERR(clk); + goto out_err; } err = clk_prepare_enable(clk); if (err) { dev_err(port->dev, "Failed to enable MCLK!\n"); - return err; + goto out_err; } psc_mclk_clk[psc_num] = clk; + + clk = devm_clk_get(port->dev, "ipg"); + if (IS_ERR(clk)) { + dev_err(port->dev, "Failed to get IPG clock!\n"); + err = PTR_ERR(clk); + goto out_err; + } + err = clk_prepare_enable(clk); + if (err) { + dev_err(port->dev, "Failed to enable IPG clock!\n"); + goto out_err; + } + psc_ipg_clk[psc_num] = clk; + return 0; + +out_err: + if (psc_mclk_clk[psc_num]) { + clk_disable_unprepare(psc_mclk_clk[psc_num]); + psc_mclk_clk[psc_num] = NULL; + } + if (psc_ipg_clk[psc_num]) { + clk_disable_unprepare(psc_ipg_clk[psc_num]); + psc_ipg_clk[psc_num] = NULL; + } + return err; } /* called from within the .release_port() callback (release) */ @@ -656,6 +720,10 @@ static void mpc512x_psc_relse_clock(struct uart_port *port) clk_disable_unprepare(clk); psc_mclk_clk[psc_num] = NULL; } + if (psc_ipg_clk[psc_num]) { + clk_disable_unprepare(psc_ipg_clk[psc_num]); + psc_ipg_clk[psc_num] = NULL; + } } /* implementation of the .clock() callback (enable/disable) */ @@ -1301,7 +1369,6 @@ static struct uart_ops mpc52xx_uart_ops = { .shutdown = mpc52xx_uart_shutdown, .set_termios = mpc52xx_uart_set_termios, /* .pm = mpc52xx_uart_pm, Not supported yet */ -/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ .type = mpc52xx_uart_type, .release_port = mpc52xx_uart_release_port, .request_port = mpc52xx_uart_request_port, @@ -1766,7 +1833,7 @@ mpc52xx_uart_of_remove(struct platform_device *op) static int mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) { - struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); + struct uart_port *port = platform_get_drvdata(op); if (port) uart_suspend_port(&mpc52xx_uart_driver, port); @@ -1777,7 +1844,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) static int mpc52xx_uart_of_resume(struct platform_device *op) { - struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); + struct uart_port *port = platform_get_drvdata(op); if (port) uart_resume_port(&mpc52xx_uart_driver, port); diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 8d702677acc..759c6a6fa74 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -1458,7 +1458,7 @@ static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios, pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE | SDMA_DESC_CMDSTAT_FR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR; /* Characters/events to ignore */ @@ -2030,7 +2030,7 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, { struct mpsc_pdata *pdata; - pdata = (struct mpsc_pdata *)dev_get_platdata(&pd->dev); + pdata = dev_get_platdata(&pd->dev); pi->port.uartclk = pdata->brg_clk_freq; pi->port.iotype = UPIO_MEM; diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index a67e7081f00..db0448ae59d 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -43,6 +43,7 @@ #include <linux/kthread.h> #include <linux/spi/spi.h> +#include <linux/pm.h> #include "mrst_max3110.h" @@ -61,6 +62,7 @@ struct uart_max3110 { struct task_struct *main_thread; struct task_struct *read_thread; struct mutex thread_mutex; + struct mutex io_mutex; u32 baud; u16 cur_conf; @@ -90,6 +92,7 @@ static int max3110_write_then_read(struct uart_max3110 *max, struct spi_transfer x; int ret; + mutex_lock(&max->io_mutex); spi_message_init(&message); memset(&x, 0, sizeof x); x.len = len; @@ -104,6 +107,7 @@ static int max3110_write_then_read(struct uart_max3110 *max, /* Do the i/o */ ret = spi_sync(spi, &message); + mutex_unlock(&max->io_mutex); return ret; } @@ -491,19 +495,9 @@ static int serial_m3110_startup(struct uart_port *port) port->state->port.low_latency = 1; if (max->irq) { - max->read_thread = NULL; - ret = request_irq(max->irq, serial_m3110_irq, - IRQ_TYPE_EDGE_FALLING, "max3110", max); - if (ret) { - max->irq = 0; - pr_err(PR_FMT "unable to allocate IRQ, polling\n"); - } else { - /* Enable RX IRQ only */ - config |= WC_RXA_IRQ_ENABLE; - } - } - - if (max->irq == 0) { + /* Enable RX IRQ only */ + config |= WC_RXA_IRQ_ENABLE; + } else { /* If IRQ is disabled, start a read thread for input data */ max->read_thread = kthread_run(max3110_read_thread, max, "max3110_read"); @@ -517,8 +511,6 @@ static int serial_m3110_startup(struct uart_port *port) ret = max3110_out(max, config); if (ret) { - if (max->irq) - free_irq(max->irq, max); if (max->read_thread) kthread_stop(max->read_thread); max->read_thread = NULL; @@ -540,9 +532,6 @@ static void serial_m3110_shutdown(struct uart_port *port) max->read_thread = NULL; } - if (max->irq) - free_irq(max->irq, max); - /* Disable interrupts from this port */ config = WC_TAG | WC_SW_SHDI; max3110_out(max, config); @@ -749,7 +738,8 @@ static int serial_m3110_suspend(struct device *dev) struct spi_device *spi = to_spi_device(dev); struct uart_max3110 *max = spi_get_drvdata(spi); - disable_irq(max->irq); + if (max->irq > 0) + disable_irq(max->irq); uart_suspend_port(&serial_m3110_reg, &max->port); max3110_out(max, max->cur_conf | WC_SW_SHDI); return 0; @@ -762,7 +752,8 @@ static int serial_m3110_resume(struct device *dev) max3110_out(max, max->cur_conf); uart_resume_port(&serial_m3110_reg, &max->port); - enable_irq(max->irq); + if (max->irq > 0) + enable_irq(max->irq); return 0; } @@ -803,6 +794,7 @@ static int serial_m3110_probe(struct spi_device *spi) max->irq = (u16)spi->irq; mutex_init(&max->thread_mutex); + mutex_init(&max->io_mutex); max->word_7bits = 0; max->parity = 0; @@ -840,6 +832,16 @@ static int serial_m3110_probe(struct spi_device *spi) goto err_kthread; } + if (max->irq) { + ret = request_irq(max->irq, serial_m3110_irq, + IRQ_TYPE_EDGE_FALLING, "max3110", max); + if (ret) { + max->irq = 0; + dev_warn(&spi->dev, + "unable to allocate IRQ, will use polling method\n"); + } + } + spi_set_drvdata(spi, max); pmax = max; @@ -867,6 +869,9 @@ static int serial_m3110_remove(struct spi_device *dev) free_page((unsigned long)max->con_xmit.buf); + if (max->irq) + free_irq(max->irq, max); + if (max->main_thread) kthread_stop(max->main_thread); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index b5d779cd3c2..72000a6d5af 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -39,13 +39,19 @@ #include "msm_serial.h" +enum { + UARTDM_1P1 = 1, + UARTDM_1P2, + UARTDM_1P3, + UARTDM_1P4, +}; + struct msm_port { struct uart_port uart; char name[16]; struct clk *clk; struct clk *pclk; unsigned int imr; - void __iomem *gsbi_base; int is_uartdm; unsigned int old_snap_state; }; @@ -309,6 +315,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port) static void msm_reset(struct uart_port *port) { + struct msm_port *msm_port = UART_TO_MSM(port); + /* reset everything */ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR); msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); @@ -316,6 +324,10 @@ static void msm_reset(struct uart_port *port) msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR); msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); msm_write(port, UART_CR_CMD_SET_RFR, UART_CR); + + /* Disable DM modes */ + if (msm_port->is_uartdm) + msm_write(port, 0, UARTDM_DMEN); } static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -570,7 +582,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, port->read_status_mask = 0; if (termios->c_iflag & INPCK) port->read_status_mask |= UART_SR_PAR_FRAME_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_SR_RX_BREAK; uart_update_timeout(port, termios->c_cflag, baud); @@ -586,9 +598,7 @@ static const char *msm_type(struct uart_port *port) static void msm_release_port(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); - struct msm_port *msm_port = UART_TO_MSM(port); struct resource *uart_resource; - struct resource *gsbi_resource; resource_size_t size; uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -599,28 +609,12 @@ static void msm_release_port(struct uart_port *port) release_mem_region(port->mapbase, size); iounmap(port->membase); port->membase = NULL; - - if (msm_port->gsbi_base) { - writel_relaxed(GSBI_PROTOCOL_IDLE, - msm_port->gsbi_base + GSBI_CONTROL); - - gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (unlikely(!gsbi_resource)) - return; - - size = resource_size(gsbi_resource); - release_mem_region(gsbi_resource->start, size); - iounmap(msm_port->gsbi_base); - msm_port->gsbi_base = NULL; - } } static int msm_request_port(struct uart_port *port) { - struct msm_port *msm_port = UART_TO_MSM(port); struct platform_device *pdev = to_platform_device(port->dev); struct resource *uart_resource; - struct resource *gsbi_resource; resource_size_t size; int ret; @@ -639,30 +633,8 @@ static int msm_request_port(struct uart_port *port) goto fail_release_port; } - gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1); - /* Is this a GSBI-based port? */ - if (gsbi_resource) { - size = resource_size(gsbi_resource); - - if (!request_mem_region(gsbi_resource->start, size, - "msm_serial")) { - ret = -EBUSY; - goto fail_release_port_membase; - } - - msm_port->gsbi_base = ioremap(gsbi_resource->start, size); - if (!msm_port->gsbi_base) { - ret = -EBUSY; - goto fail_release_gsbi; - } - } - return 0; -fail_release_gsbi: - release_mem_region(gsbi_resource->start, size); -fail_release_port_membase: - iounmap(port->membase); fail_release_port: release_mem_region(port->mapbase, size); return ret; @@ -670,7 +642,6 @@ fail_release_port: static void msm_config_port(struct uart_port *port, int flags) { - struct msm_port *msm_port = UART_TO_MSM(port); int ret; if (flags & UART_CONFIG_TYPE) { port->type = PORT_MSM; @@ -678,9 +649,6 @@ static void msm_config_port(struct uart_port *port, int flags) if (ret) return; } - if (msm_port->gsbi_base) - writel_relaxed(GSBI_PROTOCOL_UART, - msm_port->gsbi_base + GSBI_CONTROL); } static int msm_verify_port(struct uart_port *port, struct serial_struct *ser) @@ -711,6 +679,117 @@ static void msm_power(struct uart_port *port, unsigned int state, } } +#ifdef CONFIG_CONSOLE_POLL +static int msm_poll_init(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Enable single character mode on RX FIFO */ + if (msm_port->is_uartdm >= UARTDM_1P4) + msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN); + + return 0; +} + +static int msm_poll_get_char_single(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF; + + if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) + return NO_POLL_CHAR; + else + return msm_read(port, rf_reg) & 0xff; +} + +static int msm_poll_get_char_dm_1p3(struct uart_port *port) +{ + int c; + static u32 slop; + static int count; + unsigned char *sp = (unsigned char *)&slop; + + /* Check if a previous read had more than one char */ + if (count) { + c = sp[sizeof(slop) - count]; + count--; + /* Or if FIFO is empty */ + } else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) { + /* + * If RX packing buffer has less than a word, force stale to + * push contents into RX FIFO + */ + count = msm_read(port, UARTDM_RXFS); + count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK; + if (count) { + msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR); + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count--; + } else { + c = NO_POLL_CHAR; + } + /* FIFO has a word */ + } else { + slop = msm_read(port, UARTDM_RF); + c = sp[0]; + count = sizeof(slop) - 1; + } + + return c; +} + +static int msm_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm == UARTDM_1P3) + c = msm_poll_get_char_dm_1p3(port); + else + c = msm_poll_get_char_single(port); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return c; +} + +static void msm_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + struct msm_port *msm_port = UART_TO_MSM(port); + + /* Disable all interrupts */ + imr = msm_read(port, UART_IMR); + msm_write(port, 0, UART_IMR); + + if (msm_port->is_uartdm) + reset_dm_count(port, 1); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Write a character */ + msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF); + + /* Wait until FIFO is empty */ + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) + cpu_relax(); + + /* Enable interrupts */ + msm_write(port, imr, UART_IMR); + + return; +} +#endif + static struct uart_ops msm_uart_pops = { .tx_empty = msm_tx_empty, .set_mctrl = msm_set_mctrl, @@ -729,6 +808,11 @@ static struct uart_ops msm_uart_pops = { .config_port = msm_config_port, .verify_port = msm_verify_port, .pm = msm_power, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = msm_poll_init, + .poll_get_char = msm_poll_get_char, + .poll_put_char = msm_poll_put_char, +#endif }; static struct msm_port msm_uart_ports[] = { @@ -900,15 +984,19 @@ static struct uart_driver msm_uart_driver = { static atomic_t msm_uart_next_id = ATOMIC_INIT(0); static const struct of_device_id msm_uartdm_table[] = { - { .compatible = "qcom,msm-uartdm" }, + { .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 }, + { .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 }, + { .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 }, + { .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 }, { } }; -static int __init msm_serial_probe(struct platform_device *pdev) +static int msm_serial_probe(struct platform_device *pdev) { struct msm_port *msm_port; struct resource *resource; struct uart_port *port; + const struct of_device_id *id; int irq; if (pdev->id == -1) @@ -923,8 +1011,9 @@ static int __init msm_serial_probe(struct platform_device *pdev) port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); - if (of_match_device(msm_uartdm_table, &pdev->dev)) - msm_port->is_uartdm = 1; + id = of_match_device(msm_uartdm_table, &pdev->dev); + if (id) + msm_port->is_uartdm = (unsigned long)id->data; else msm_port->is_uartdm = 0; @@ -976,6 +1065,7 @@ static struct of_device_id msm_match_table[] = { static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, + .probe = msm_serial_probe, .driver = { .name = "msm_serial", .owner = THIS_MODULE, @@ -991,7 +1081,7 @@ static int __init msm_serial_init(void) if (unlikely(ret)) return ret; - ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe); + ret = platform_driver_register(&msm_platform_driver); if (unlikely(ret)) uart_unregister_driver(&msm_uart_driver); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h index 469fda50ac6..d98d45efdf8 100644 --- a/drivers/tty/serial/msm_serial.h +++ b/drivers/tty/serial/msm_serial.h @@ -59,6 +59,7 @@ #define UART_CR_CMD_RESET_RFR (14 << 4) #define UART_CR_CMD_PROTECTION_EN (16 << 4) #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) #define UART_CR_CMD_RESET_TX_READY (3 << 8) #define UART_CR_TX_DISABLE (1 << 3) #define UART_CR_TX_ENABLE (1 << 2) @@ -108,10 +109,13 @@ #define UART_ISR 0x0014 #define UART_ISR_TX_READY (1 << 7) -#define GSBI_CONTROL 0x0 -#define GSBI_PROTOCOL_CODE 0x30 -#define GSBI_PROTOCOL_UART 0x40 -#define GSBI_PROTOCOL_IDLE 0x0 +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) #define UARTDM_DMRX 0x34 #define UARTDM_NCF_TX 0x40 diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 7fd6aaaacd8..be127d0da32 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -29,7 +29,7 @@ #include <asm/irq.h> #include <asm/parisc-device.h> -#ifdef CONFIG_MAGIC_SYSRQ +#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #include <linux/sysrq.h> #define SUPPORT_SYSRQ #endif @@ -613,7 +613,7 @@ static void __exit mux_exit(void) { /* Delete the Mux timer. */ if(port_cnt > 0) { - del_timer(&mux_timer); + del_timer_sync(&mux_timer); #ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console(&mux_console); #endif diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 10e9d70b5c4..86de4477d98 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -39,6 +39,7 @@ #include <asm/cacheflush.h> #define MXS_AUART_PORTS 5 +#define MXS_AUART_FIFO_SIZE 16 #define AUART_CTRL0 0x00000000 #define AUART_CTRL0_SET 0x00000004 @@ -199,7 +200,7 @@ static void dma_tx_callback(void *param) /* clear the bit used to serialize the DMA tx. */ clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); /* wake up the possible processes. */ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -274,7 +275,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s) mxs_auart_dma_tx(s, i); } else { clear_bit(MXS_AUART_DMA_TX_SYNC, &s->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); } return; } @@ -548,6 +549,9 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s) s->flags |= MXS_AUART_DMA_ENABLED; dev_dbg(s->dev, "enabled the DMA support."); + /* The DMA buffer is now the FIFO the TTY subsystem can use */ + s->port.fifosize = UART_XMIT_SIZE; + return 0; err_out: @@ -600,7 +604,7 @@ static void mxs_auart_settermios(struct uart_port *u, if (termios->c_iflag & INPCK) u->read_status_mask |= AUART_STAT_PERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) u->read_status_mask |= AUART_STAT_BERR; /* @@ -730,9 +734,12 @@ static void mxs_auart_reset(struct uart_port *u) static int mxs_auart_startup(struct uart_port *u) { + int ret; struct mxs_auart_port *s = to_auart_port(u); - clk_prepare_enable(s->clk); + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); @@ -741,6 +748,9 @@ static int mxs_auart_startup(struct uart_port *u) writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, u->membase + AUART_INTR); + /* Reset FIFO size (it could have changed if DMA was enabled) */ + u->fifosize = MXS_AUART_FIFO_SIZE; + /* * Enable fifo so all four bytes of a DMA word are written to * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) @@ -950,7 +960,9 @@ auart_console_setup(struct console *co, char *options) if (!s) return -ENODEV; - clk_prepare_enable(s->clk); + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -1056,7 +1068,7 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.membase = ioremap(r->start, resource_size(r)); s->port.ops = &mxs_auart_ops; s->port.iotype = UPIO_MEM; - s->port.fifosize = 16; + s->port.fifosize = MXS_AUART_FIFO_SIZE; s->port.uartclk = clk_get_rate(s->clk); s->port.type = PORT_IMX; s->port.dev = s->dev = &pdev->dev; diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c index 0a4dd70d29e..7a6745601d4 100644 --- a/drivers/tty/serial/netx-serial.c +++ b/drivers/tty/serial/netx-serial.c @@ -419,7 +419,7 @@ netx_set_termios(struct uart_port *port, struct ktermios *termios, } port->read_status_mask = 0; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SR_BE; if (termios->c_iflag & INPCK) port->read_status_mask |= SR_PE | SR_FE; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 2caf9c6f614..68d4455f3cf 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -9,7 +9,6 @@ * 2 of the License, or (at your option) any later version. * */ -#include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> @@ -174,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) { struct uart_8250_port port8250; memset(&port8250, 0, sizeof(port8250)); + port.type = port_type; port8250.port = port; if (port.fifosize) @@ -183,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev) "auto-flow-control")) port8250.capabilities |= UART_CAP_AFE; + if (of_property_read_bool(ofdev->dev.of_node, + "has-hw-flow-control")) + port8250.port.flags |= UPF_HARD_FLOW; + ret = serial8250_register_8250_port(&port8250); break; } diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 816d1a23f9d..d017cec8a34 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -39,6 +39,7 @@ #include <linux/irq.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/platform_data/serial-omap.h> @@ -134,6 +135,7 @@ struct uart_omap_port { struct uart_port port; struct uart_omap_dma uart_dma; struct device *dev; + int wakeirq; unsigned char ier; unsigned char lcr; @@ -161,10 +163,6 @@ struct uart_omap_port { u8 wakeups_enabled; u32 features; - int DTR_gpio; - int DTR_inverted; - int DTR_active; - struct serial_rs485 rs485; int rts_gpio; @@ -175,15 +173,13 @@ struct uart_omap_port { bool is_suspending; }; -#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); -static struct workqueue_struct *serial_omap_uart_wq; - static inline unsigned int serial_in(struct uart_omap_port *up, int offset) { offset <<= up->port.regshift; @@ -214,10 +210,28 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } +static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, + bool enable) +{ + if (!up->wakeirq) + return; + + if (enable) + enable_irq(up->wakeirq); + else + disable_irq_nosync(up->wakeirq); +} + static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); + if (enable == up->wakeups_enabled) + return; + + serial_omap_enable_wakeirq(up, enable); + up->wakeups_enabled = enable; + if (!pdata || !pdata->enable_wakeup) return; @@ -242,12 +256,12 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) unsigned int n16 = port->uartclk / (16 * baud); int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); - if(baudAbsDiff13 < 0) + if (baudAbsDiff13 < 0) baudAbsDiff13 = -baudAbsDiff13; - if(baudAbsDiff16 < 0) + if (baudAbsDiff16 < 0) baudAbsDiff16 = -baudAbsDiff16; - return (baudAbsDiff13 > baudAbsDiff16); + return (baudAbsDiff13 >= baudAbsDiff16); } /* @@ -258,13 +272,13 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) static unsigned int serial_omap_get_divisor(struct uart_port *port, unsigned int baud) { - unsigned int divisor; + unsigned int mode; if (!serial_omap_baud_is_mode16(port, baud)) - divisor = 13; + mode = 13; else - divisor = 16; - return port->uartclk/(baud * divisor); + mode = 16; + return port->uartclk/(mode * baud); } static void serial_omap_enable_ms(struct uart_port *port) @@ -283,28 +297,40 @@ static void serial_omap_enable_ms(struct uart_port *port) static void serial_omap_stop_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct circ_buf *xmit = &up->port.state->xmit; int res; pm_runtime_get_sync(up->dev); - /* handle rs485 */ + /* Handle RS-485 */ if (up->rs485.flags & SER_RS485_ENABLED) { - /* do nothing if current tx not yet completed */ - res = serial_in(up, UART_LSR) & UART_LSR_TEMT; - if (!res) - return; - - /* if there's no more data to send, turn off rts */ - if (uart_circ_empty(xmit)) { - /* if rts not already disabled */ + if (up->scr & OMAP_UART_SCR_TX_EMPTY) { + /* THR interrupt is fired when both TX FIFO and TX + * shift register are empty. This means there's nothing + * left to transmit now, so make sure the THR interrupt + * is fired when TX FIFO is below the trigger level, + * disable THR interrupts and toggle the RS-485 GPIO + * data direction pin if needed. + */ + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { - if (up->rs485.delay_rts_after_send > 0) { + if (up->rs485.delay_rts_after_send > 0) mdelay(up->rs485.delay_rts_after_send); - } gpio_set_value(up->rts_gpio, res); } + } else { + /* We're asked to stop, but there's still stuff in the + * UART FIFO, so make sure the THR interrupt is fired + * when both TX FIFO and TX shift register are empty. + * The next THR interrupt (if no transmission is started + * in the meantime) will indicate the end of a + * transmission. Therefore we _don't_ disable THR + * interrupts in this situation. + */ + up->scr |= OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + return; } } @@ -315,7 +341,14 @@ static void serial_omap_stop_tx(struct uart_port *port) if ((up->rs485.flags & SER_RS485_ENABLED) && !(up->rs485.flags & SER_RS485_RX_DURING_TX)) { - up->ier = UART_IER_RLSI | UART_IER_RDI; + /* + * Empty the RX FIFO, we are not interested in anything + * received during the half-duplex transmission. + */ + serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR); + /* Re-enable RX interrupts */ + up->ier |= UART_IER_RLSI | UART_IER_RDI; + up->port.read_status_mask |= UART_LSR_DR; serial_out(up, UART_IER, up->ier); } @@ -328,7 +361,7 @@ static void serial_omap_stop_rx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); pm_runtime_get_sync(up->dev); - up->ier &= ~UART_IER_RLSI; + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); pm_runtime_mark_last_busy(up->dev); @@ -359,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { - spin_unlock(&up->port.lock); + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&up->port); - spin_lock(&up->port.lock); - } if (uart_circ_empty(xmit)) serial_omap_stop_tx(&up->port); @@ -384,15 +414,18 @@ static void serial_omap_start_tx(struct uart_port *port) pm_runtime_get_sync(up->dev); - /* handle rs485 */ + /* Handle RS-485 */ if (up->rs485.flags & SER_RS485_ENABLED) { + /* Fire THR interrupts when FIFO is below trigger level */ + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + /* if rts not already enabled */ res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { gpio_set_value(up->rts_gpio, res); - if (up->rs485.delay_rts_before_send > 0) { + if (up->rs485.delay_rts_before_send > 0) mdelay(up->rs485.delay_rts_before_send); - } } } @@ -655,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) serial_out(up, UART_MCR, up->mcr); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); - - if (gpio_is_valid(up->DTR_gpio) && - !!(mctrl & TIOCM_DTR) != up->DTR_active) { - up->DTR_active = !up->DTR_active; - if (gpio_cansleep(up->DTR_gpio)) - schedule_work(&up->qos_work); - else - gpio_set_value(up->DTR_gpio, - up->DTR_active != up->DTR_inverted); - } } static void serial_omap_break_ctl(struct uart_port *port, int break_state) @@ -699,6 +722,17 @@ static int serial_omap_startup(struct uart_port *port) if (retval) return retval; + /* Optional wake-up IRQ */ + if (up->wakeirq) { + retval = request_irq(up->wakeirq, serial_omap_irq, + up->port.irqflags, up->name, up); + if (retval) { + free_irq(up->port.irq, up); + return retval; + } + disable_irq(up->wakeirq); + } + dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); pm_runtime_get_sync(up->dev); @@ -787,6 +821,8 @@ static void serial_omap_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); + if (up->wakeirq) + free_irq(up->wakeirq, up); } static void serial_omap_uart_qos_work(struct work_struct *work) @@ -795,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work) qos_work); pm_qos_update_request(&up->pm_qos_request, up->latency); - if (gpio_is_valid(up->DTR_gpio)) - gpio_set_value_cansleep(up->DTR_gpio, - up->DTR_active != up->DTR_inverted); } static void @@ -938,7 +971,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, */ /* Set receive FIFO threshold to 16 characters and - * transmit FIFO threshold to 16 spaces + * transmit FIFO threshold to 32 spaces */ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; @@ -1060,15 +1093,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } -static int serial_omap_set_wake(struct uart_port *port, unsigned int state) -{ - struct uart_omap_port *up = to_uart_omap_port(port); - - serial_omap_enable_wakeup(up, state); - - return 0; -} - static void serial_omap_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) @@ -1353,6 +1377,15 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) up->ier = mode; serial_out(up, UART_IER, up->ier); + /* If RS-485 is disabled, make sure the THR interrupt is fired when + * TX FIFO is below the trigger level. + */ + if (!(up->rs485.flags & SER_RS485_ENABLED) && + (up->scr & OMAP_UART_SCR_TX_EMPTY)) { + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + } + spin_unlock_irqrestore(&up->port.lock, flags); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); @@ -1365,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) switch (cmd) { case TIOCSRS485: - if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg, + if (copy_from_user(&rs485conf, (void __user *) arg, sizeof(rs485conf))) return -EFAULT; @@ -1373,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) break; case TIOCGRS485: - if (copy_to_user((struct serial_rs485 *) arg, + if (copy_to_user((void __user *) arg, &(to_uart_omap_port(port)->rs485), sizeof(rs485conf))) return -EFAULT; @@ -1401,7 +1434,6 @@ static struct uart_ops serial_omap_pops = { .shutdown = serial_omap_shutdown, .set_termios = serial_omap_set_termios, .pm = serial_omap_pm, - .set_wake = serial_omap_set_wake, .type = serial_omap_type, .release_port = serial_omap_release_port, .request_port = serial_omap_request_port, @@ -1446,6 +1478,11 @@ static int serial_omap_suspend(struct device *dev) uart_suspend_port(&serial_omap_reg, &up->port); flush_work(&up->qos_work); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, true); + else + serial_omap_enable_wakeup(up, false); + return 0; } @@ -1453,6 +1490,9 @@ static int serial_omap_resume(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, false); + uart_resume_port(&serial_omap_reg, &up->port); return 0; @@ -1552,15 +1592,18 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, /* check for tx enable gpio */ up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags); if (gpio_is_valid(up->rts_gpio)) { - ret = gpio_request(up->rts_gpio, "omap-serial"); + ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial"); if (ret < 0) return ret; ret = gpio_direction_output(up->rts_gpio, flags & SER_RS485_RTS_AFTER_SEND); if (ret < 0) return ret; - } else + } else if (up->rts_gpio == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else { up->rts_gpio = -EINVAL; + } if (of_property_read_u32_array(np, "rs485-rts-delay", rs485_delay, 2) == 0) { @@ -1579,62 +1622,46 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, static int serial_omap_probe(struct platform_device *pdev) { - struct uart_omap_port *up; - struct resource *mem, *irq; struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); + struct uart_omap_port *up; + struct resource *mem; + void __iomem *base; + int uartirq = 0; + int wakeirq = 0; int ret; + /* The optional wakeirq may be specified in the board dts file */ if (pdev->dev.of_node) { + uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!uartirq) + return -EPROBE_DEFER; + wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); omap_up_info = of_get_uart_port_info(&pdev->dev); pdev->dev.platform_data = omap_up_info; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; - } - - if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), - pdev->dev.driver->name)) { - dev_err(&pdev->dev, "memory region already claimed\n"); - return -EBUSY; - } - - if (gpio_is_valid(omap_up_info->DTR_gpio) && - omap_up_info->DTR_present) { - ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); - if (ret < 0) - return ret; - ret = gpio_direction_output(omap_up_info->DTR_gpio, - omap_up_info->DTR_inverted); - if (ret < 0) - return ret; + } else { + uartirq = platform_get_irq(pdev, 0); + if (uartirq < 0) + return -EPROBE_DEFER; } up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; - if (gpio_is_valid(omap_up_info->DTR_gpio) && - omap_up_info->DTR_present) { - up->DTR_gpio = omap_up_info->DTR_gpio; - up->DTR_inverted = omap_up_info->DTR_inverted; - } else - up->DTR_gpio = -EINVAL; - up->DTR_active = 0; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); up->dev = &pdev->dev; up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; - up->port.irq = irq->start; + up->port.irq = uartirq; + up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); up->port.regshift = 2; up->port.fifosize = 64; @@ -1658,32 +1685,26 @@ static int serial_omap_probe(struct platform_device *pdev) sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; - up->port.membase = devm_ioremap(&pdev->dev, mem->start, - resource_size(mem)); - if (!up->port.membase) { - dev_err(&pdev->dev, "can't ioremap UART\n"); - ret = -ENOMEM; - goto err_ioremap; - } - + up->port.membase = base; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; - dev_warn(&pdev->dev, "No clock speed specified: using default:" - "%d\n", DEFAULT_CLK_SPEED); + dev_warn(&pdev->dev, + "No clock speed specified: using default: %d\n", + DEFAULT_CLK_SPEED); } up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; pm_qos_add_request(&up->pm_qos_request, PM_QOS_CPU_DMA_LATENCY, up->latency); - serial_omap_uart_wq = create_singlethread_workqueue(up->name); INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); platform_set_drvdata(pdev, up); if (omap_up_info->autosuspend_timeout == 0) omap_up_info->autosuspend_timeout = -1; + device_init_wakeup(up->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, @@ -1710,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev) err_add_port: pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); -err_ioremap: err_rs485: err_port_line: dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", @@ -1726,6 +1746,7 @@ static int serial_omap_remove(struct platform_device *dev) pm_runtime_disable(up->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); + device_init_wakeup(&dev->dev, false); return 0; } @@ -1814,17 +1835,7 @@ static int serial_omap_runtime_suspend(struct device *dev) up->context_loss_cnt = serial_omap_get_context_loss_count(up); - if (device_may_wakeup(dev)) { - if (!up->wakeups_enabled) { - serial_omap_enable_wakeup(up, true); - up->wakeups_enabled = true; - } - } else { - if (up->wakeups_enabled) { - serial_omap_enable_wakeup(up, false); - up->wakeups_enabled = false; - } - } + serial_omap_enable_wakeup(up, true); up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1838,6 +1849,8 @@ static int serial_omap_runtime_resume(struct device *dev) int loss_cnt = serial_omap_get_context_loss_count(up); + serial_omap_enable_wakeup(up, false); + if (loss_cnt < 0) { dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n", loss_cnt); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 44077c0b767..0cb6a8e52bd 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -257,6 +257,8 @@ struct eg20t_port { dma_addr_t rx_buf_dma; struct dentry *debugfs; +#define IRQ_NAME_SIZE 17 + char irq_name[IRQ_NAME_SIZE]; /* protect the eg20t_port private structure and io access to membase */ spinlock_t lock; @@ -1343,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port) return ret; ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED, - KBUILD_MODNAME, priv); + priv->irq_name, priv); if (ret < 0) return ret; @@ -1508,10 +1510,14 @@ static int pch_uart_verify_port(struct uart_port *port, __func__); return -EOPNOTSUPP; #endif - dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); - if (!priv->use_dma) + if (!priv->use_dma) { pch_request_dma(port); - priv->use_dma = 1; + if (priv->chan_rx) + priv->use_dma = 1; + } + dev_info(priv->port.dev, "PCH UART: %s\n", + priv->use_dma ? + "Use DMA Mode" : "No DMA"); } return 0; @@ -1584,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port, wait_for_xmitr(priv, UART_LSR_THRE); /* * Send the character out. - * If a LF, also do CR... */ iowrite8(c, priv->membase + PCH_UART_THR); - if (c == 10) { - wait_for_xmitr(priv, UART_LSR_THRE); - iowrite8(13, priv->membase + PCH_UART_THR); - } /* * Finally, wait for transmitter to become empty @@ -1614,7 +1615,6 @@ static struct uart_ops pch_uart_ops = { .shutdown = pch_uart_shutdown, .set_termios = pch_uart_set_termios, /* .pm = pch_uart_pm, Not supported yet */ -/* .set_wake = pch_uart_set_wake, Not supported yet */ .type = pch_uart_type, .release_port = pch_uart_release_port, .request_port = pch_uart_request_port, @@ -1759,7 +1759,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, int fifosize; int port_type; struct pch_uart_driver_data *board; +#ifdef CONFIG_DEBUG_FS char name[32]; /* for debugfs file name */ +#endif board = &drv_dat[id->driver_data]; port_type = board->port_type; @@ -1813,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, priv->port.line = board->line_no; priv->trigger = PCH_UART_HAL_TRIGGER_M; + snprintf(priv->irq_name, IRQ_NAME_SIZE, + KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d", + priv->port.line); + spin_lock_init(&priv->port.lock); pci_set_drvdata(pdev, priv); @@ -1854,7 +1860,6 @@ static void pch_uart_exit_port(struct eg20t_port *priv) debugfs_remove(priv->debugfs); #endif uart_remove_one_port(&pch_uart_driver, &priv->port); - pci_set_drvdata(priv->pdev, NULL); free_page((unsigned long)priv->rxbuf.buf); } @@ -1908,7 +1913,7 @@ static int pch_uart_pci_resume(struct pci_dev *pdev) #define pch_uart_pci_resume NULL #endif -static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { +static const struct pci_device_id pch_uart_pci_id[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), .driver_data = pch_et20t_uart0}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), @@ -1996,6 +2001,8 @@ module_exit(pch_uart_module_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); +MODULE_DEVICE_TABLE(pci, pch_uart_pci_id); + module_param(default_baud, uint, S_IRUGO); MODULE_PARM_DESC(default_baud, "Default BAUD for initial driver state and console (default 9600)"); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index f87f1a0c8c6..f7ad5b90305 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -57,6 +57,8 @@ #include <linux/bitops.h> #include <linux/sysrq.h> #include <linux/mutex.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/sections.h> #include <asm/io.h> #include <asm/irq.h> @@ -651,6 +653,8 @@ static void pmz_start_tx(struct uart_port *port) } else { struct circ_buf *xmit = &port->state->xmit; + if (uart_circ_empty(xmit)) + goto out; write_zsdata(uap, xmit->buf[xmit->tail]); zssync(uap); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -659,6 +663,7 @@ static void pmz_start_tx(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); } + out: pmz_debug("pmz: start_tx() done.\n"); } @@ -1072,7 +1077,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, uap->curregs[5] |= Tx8; uap->parity_mask = 0xff; break; - }; + } uap->curregs[4] &= ~(SB_MASK); if (cflag & CSTOPB) uap->curregs[4] |= SB2; @@ -1090,7 +1095,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, uap->port.read_status_mask = Rx_OVR; if (iflag & INPCK) uap->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) uap->port.read_status_mask |= BRK_ABRT; uap->port.ignore_status_mask = 0; @@ -2050,6 +2055,9 @@ static int __init pmz_console_init(void) /* Probe ports */ pmz_probe(); + if (pmz_ports_count == 0) + return -ENODEV; + /* TODO: Autoprobe console based on OF */ /* pmz_console.index = i; */ register_console(&pmz_console); diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c index de6c05c6368..2ba24a45c97 100644 --- a/drivers/tty/serial/pnx8xxx_uart.c +++ b/drivers/tty/serial/pnx8xxx_uart.c @@ -477,7 +477,7 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask |= FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) | FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK); diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index f9f20f38376..c638c53cd2b 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -492,7 +492,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* @@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port, wait_for_xmitr(up); /* * Send the character out. - * If a LF, also do CR... */ serial_out(up, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up); - serial_out(up, UART_TX, 13); - } /* * Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 328d6deb6b0..056f91b3a4c 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -810,7 +810,7 @@ static void rp2_remove(struct pci_dev *pdev) rp2_remove_ports(card); } -static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = { +static const struct pci_device_id rp2_pci_tbl[] = { /* RocketPort INFINITY cards */ diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index ba25722a713..753d4525b36 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -647,7 +647,10 @@ void sa1100_register_uart_fns(struct sa1100_port_fns *fns) sa1100_pops.set_mctrl = fns->set_mctrl; sa1100_pops.pm = fns->pm; - sa1100_pops.set_wake = fns->set_wake; + /* + * FIXME: fns->set_wake is unused - this should be called from + * the suspend() callback if device_may_wakeup(dev)) is set. + */ } void __init sa1100_register_uart(int idx, int port) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f3dfa19a1cb..c1d3ebdf3b9 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -53,6 +53,29 @@ #include "samsung.h" +#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \ + defined(CONFIG_DEBUG_LL) && \ + !defined(MODULE) + +extern void printascii(const char *); + +__printf(1, 2) +static void dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vscnprintf(buff, sizeof(buff), fmt, va); + va_end(va); + + printascii(buff); +} + +#else +#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0) +#endif + /* UART name and device definitions */ #define S3C24XX_SERIAL_NAME "ttySAC" @@ -407,7 +430,14 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* todo - possibly remove AFC and do manual CTS */ + unsigned int umcon = rd_regl(port, S3C2410_UMCON); + + if (mctrl & TIOCM_RTS) + umcon |= S3C2410_UMCOM_RTS_LOW; + else + umcon &= ~S3C2410_UMCOM_RTS_LOW; + + wr_regl(port, S3C2410_UMCON, umcon); } static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) @@ -461,8 +491,8 @@ static int s3c24xx_serial_startup(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); int ret; - dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", - port->mapbase, port->membase); + dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n", + port, (unsigned long long)port->mapbase, port->membase); rx_enabled(port) = 1; @@ -507,8 +537,8 @@ static int s3c64xx_serial_startup(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); int ret; - dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n", - port->mapbase, port->membase); + dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n", + port, (unsigned long long)port->mapbase, port->membase); wr_regl(port, S3C64XX_UINTM, 0xf); @@ -774,8 +804,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if (termios->c_cflag & CSTOPB) ulcon |= S3C2410_LCON_STOPB; - umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; - if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C2410_LCON_PODD; @@ -792,6 +820,15 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); + + umcon = rd_regl(port, S3C2410_UMCON); + if (termios->c_cflag & CRTSCTS) { + umcon |= S3C2410_UMCOM_AFC; + /* Disable RTS when RX FIFO contains 63 bytes */ + umcon &= ~S3C2412_UMCON_AFC_8; + } else { + umcon &= ~S3C2410_UMCOM_AFC; + } wr_regl(port, S3C2410_UMCON, umcon); if (ourport->info->has_divslot) @@ -1146,7 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, return -EINVAL; } - dbg("resource %p (%lx..%lx)\n", res, res->start, res->end); + dbg("resource %pR)\n", res); port->membase = devm_ioremap(port->dev, res->start, resource_size(res)); if (!port->membase) { @@ -1189,13 +1226,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, wr_regl(port, S3C64XX_UINTSP, 0xf); } - dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", + dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n", port->mapbase, port->membase, port->irq, ourport->rx_irq, ourport->tx_irq, port->uartclk); /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); - clk_disable_unprepare(ourport->clk); return 0; } @@ -1254,7 +1290,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->baudclk = ERR_PTR(-EINVAL); ourport->info = ourport->drv_data->info; ourport->cfg = (dev_get_platdata(&pdev->dev)) ? - (struct s3c2410_uartcfg *)dev_get_platdata(&pdev->dev) : + dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; ourport->port.fifosize = (ourport->info->fifosize) ? @@ -1269,10 +1305,25 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) if (ret < 0) goto probe_err; + if (!s3c24xx_uart_drv.state) { + ret = uart_register_driver(&s3c24xx_uart_drv); + if (ret < 0) { + pr_err("Failed to register Samsung UART driver\n"); + return ret; + } + } + dbg("%s: adding port\n", __func__); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(pdev, &ourport->port); + /* + * Deactivate the clock enabled in s3c24xx_serial_init_port here, + * so that a potential re-enablement through the pm-callback overlaps + * and keeps the clock enabled in this case. + */ + clk_disable_unprepare(ourport->clk); + #ifdef CONFIG_SAMSUNG_CLOCK ret = device_create_file(&pdev->dev, &dev_attr_clock_source); if (ret < 0) @@ -1301,6 +1352,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev) uart_remove_one_port(&s3c24xx_uart_drv, port); } + uart_unregister_driver(&s3c24xx_uart_drv); + return 0; } @@ -1416,8 +1469,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) static void s3c24xx_serial_put_poll_char(struct uart_port *port, unsigned char c) { - unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + unsigned int ufcon = rd_regl(port, S3C2410_UFCON); + unsigned int ucon = rd_regl(port, S3C2410_UCON); /* not possible to xmit on unconfigured port */ if (!s3c24xx_port_configured(ucon)) @@ -1425,7 +1478,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(cons_uart, S3C2410_UTXH, c); + wr_regb(port, S3C2410_UTXH, c); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1433,22 +1486,23 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, static void s3c24xx_serial_console_putchar(struct uart_port *port, int ch) { - unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON); - unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); - - /* not possible to xmit on unconfigured port */ - if (!s3c24xx_port_configured(ucon)) - return; + unsigned int ufcon = rd_regl(port, S3C2410_UFCON); while (!s3c24xx_serial_console_txrdy(port, ufcon)) - barrier(); - wr_regb(cons_uart, S3C2410_UTXH, ch); + cpu_relax(); + wr_regb(port, S3C2410_UTXH, ch); } static void s3c24xx_serial_console_write(struct console *co, const char *s, unsigned int count) { + unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON); + + /* not possible to xmit on unconfigured port */ + if (!s3c24xx_port_configured(ucon)) + return; + uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); } @@ -1800,35 +1854,7 @@ static struct platform_driver samsung_serial_driver = { }, }; -/* module initialisation code */ - -static int __init s3c24xx_serial_modinit(void) -{ - int ret; - - ret = uart_register_driver(&s3c24xx_uart_drv); - if (ret < 0) { - pr_err("Failed to register Samsung UART driver\n"); - return ret; - } - - ret = platform_driver_register(&samsung_serial_driver); - if (ret < 0) { - pr_err("Failed to register platform driver\n"); - uart_unregister_driver(&s3c24xx_uart_drv); - } - - return ret; -} - -static void __exit s3c24xx_serial_modexit(void) -{ - platform_driver_unregister(&samsung_serial_driver); - uart_unregister_driver(&s3c24xx_uart_drv); -} - -module_init(s3c24xx_serial_modinit); -module_exit(s3c24xx_serial_modexit); +module_platform_driver(samsung_serial_driver); MODULE_ALIAS("platform:samsung-uart"); MODULE_DESCRIPTION("Samsung SoC Serial port driver"); diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index aaa617a6c49..eb071dd19b2 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -1,3 +1,6 @@ +#ifndef __SAMSUNG_H +#define __SAMSUNG_H + /* * Driver for Samsung SoC onboard UARTs. * @@ -63,7 +66,7 @@ struct s3c24xx_uart_port { /* conversion functions */ -#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) +#define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev) /* register access controls */ @@ -77,24 +80,4 @@ struct s3c24xx_uart_port { #define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) -#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \ - defined(CONFIG_DEBUG_LL) && \ - !defined(MODULE) - -extern void printascii(const char *); - -static void dbg(const char *fmt, ...) -{ - va_list va; - char buff[256]; - - va_start(va, fmt); - vsprintf(buff, fmt, va); - va_end(va); - - printascii(buff); -} - -#else -#define dbg(x...) do { } while (0) #endif diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index a7cdec2962d..771f361c47e 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -596,7 +596,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios, if (termios->c_iflag & INPCK) uport->read_status_mask |= M_DUART_FRM_ERR | M_DUART_PARITY_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uport->read_status_mask |= M_DUART_RCVD_BRK; uport->ignore_status_mask = 0; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c new file mode 100644 index 00000000000..1b6a77c4b2c --- /dev/null +++ b/drivers/tty/serial/sc16is7xx.c @@ -0,0 +1,1277 @@ +/* + * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint + * Author: Jon Ringle <jringle@gridpoint.com> + * + * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> + +#define SC16IS7XX_NAME "sc16is7xx" + +/* SC16IS7XX register definitions */ +#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ +#define SC16IS7XX_THR_REG (0x00) /* TX FIFO */ +#define SC16IS7XX_IER_REG (0x01) /* Interrupt enable */ +#define SC16IS7XX_IIR_REG (0x02) /* Interrupt Identification */ +#define SC16IS7XX_FCR_REG (0x02) /* FIFO control */ +#define SC16IS7XX_LCR_REG (0x03) /* Line Control */ +#define SC16IS7XX_MCR_REG (0x04) /* Modem Control */ +#define SC16IS7XX_LSR_REG (0x05) /* Line Status */ +#define SC16IS7XX_MSR_REG (0x06) /* Modem Status */ +#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */ +#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */ +#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */ +#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction + * - only on 75x/76x + */ +#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State + * - only on 75x/76x + */ +#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable + * - only on 75x/76x + */ +#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control + * - only on 75x/76x + */ +#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */ + +/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */ +#define SC16IS7XX_TCR_REG (0x06) /* Transmit control */ +#define SC16IS7XX_TLR_REG (0x07) /* Trigger level */ + +/* Special Register set: Only if ((LCR[7] == 1) && (LCR != 0xBF)) */ +#define SC16IS7XX_DLL_REG (0x00) /* Divisor Latch Low */ +#define SC16IS7XX_DLH_REG (0x01) /* Divisor Latch High */ + +/* Enhanced Register set: Only if (LCR == 0xBF) */ +#define SC16IS7XX_EFR_REG (0x02) /* Enhanced Features */ +#define SC16IS7XX_XON1_REG (0x04) /* Xon1 word */ +#define SC16IS7XX_XON2_REG (0x05) /* Xon2 word */ +#define SC16IS7XX_XOFF1_REG (0x06) /* Xoff1 word */ +#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */ + +/* IER register bits */ +#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */ +#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register + * interrupt */ +#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status + * interrupt */ +#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status + * interrupt */ + +/* IER register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */ +#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */ +#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */ +#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */ + +/* FCR register bits */ +#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */ +#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */ +#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */ +#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */ +#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */ + +/* FCR register bits - write only if (EFR[4] == 1) */ +#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */ +#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */ + +/* IIR register bits */ +#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */ +#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */ +#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */ +#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */ +#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */ +#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */ +#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state + * - only on 75x/76x + */ +#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */ +#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state + * from active (LOW) + * to inactive (HIGH) + */ +/* LCR register bits */ +#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ +#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 + * + * Word length bits table: + * 00 -> 5 bit words + * 01 -> 6 bit words + * 10 -> 7 bit words + * 11 -> 8 bit words + */ +#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit + * + * STOP length bit table: + * 0 -> 1 stop bit + * 1 -> 1-1.5 stop bits if + * word length is 5, + * 2 stop bits otherwise + */ +#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ +#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ +#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ +#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ +#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */ +#define SC16IS7XX_LCR_WORD_LEN_5 (0x00) +#define SC16IS7XX_LCR_WORD_LEN_6 (0x01) +#define SC16IS7XX_LCR_WORD_LEN_7 (0x02) +#define SC16IS7XX_LCR_WORD_LEN_8 (0x03) +#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special + * reg set */ +#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced + * reg set */ + +/* MCR register bits */ +#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement + * - only on 75x/76x + */ +#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */ +#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */ +#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */ +#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any + * - write enabled + * if (EFR[4] == 1) + */ +#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode + * - write enabled + * if (EFR[4] == 1) + */ +#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4 + * - write enabled + * if (EFR[4] == 1) + */ + +/* LSR register bits */ +#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */ +#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */ +#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */ +#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */ +#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */ +#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */ +#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */ +#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */ +#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */ + +/* MSR register bits */ +#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */ +#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready + * or (IO4) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator + * or (IO7) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect + * or (IO6) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_CTS_BIT (1 << 0) /* CTS */ +#define SC16IS7XX_MSR_DSR_BIT (1 << 1) /* DSR (IO4) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_RI_BIT (1 << 2) /* RI (IO7) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_CD_BIT (1 << 3) /* CD (IO6) + * - only on 75x/76x + */ +#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */ + +/* + * TCR register bits + * TCR trigger levels are available from 0 to 60 characters with a granularity + * of four. + * The programmer must program the TCR such that TCR[3:0] > TCR[7:4]. There is + * no built-in hardware check to make sure this condition is met. Also, the TCR + * must be programmed with this condition before auto RTS or software flow + * control is enabled to avoid spurious operation of the device. + */ +#define SC16IS7XX_TCR_RX_HALT(words) ((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TCR_RX_RESUME(words) ((((words) / 4) & 0x0f) << 4) + +/* + * TLR register bits + * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the + * FIFO Control Register (FCR) are used for the transmit and receive FIFO + * trigger levels. Trigger levels from 4 characters to 60 characters are + * available with a granularity of four. + * + * When the trigger level setting in TLR is zero, the SC16IS740/750/760 uses the + * trigger level setting defined in FCR. If TLR has non-zero trigger level value + * the trigger level defined in FCR is discarded. This applies to both transmit + * FIFO and receive FIFO trigger level setting. + * + * When TLR is used for RX trigger level control, FCR[7:6] should be left at the + * default state, that is, '00'. + */ +#define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) +#define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4) + +/* IOControl register bits (Only 750/760) */ +#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */ +#define SC16IS7XX_IOCONTROL_GPIO_BIT (1 << 1) /* Enable GPIO[7:4] */ +#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */ + +/* EFCR register bits */ +#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop + * mode (RS485) */ +#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */ +#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */ +#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */ +#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */ +#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode + * 0 = rate upto 115.2 kbit/s + * - Only 750/760 + * 1 = rate upto 1.152 Mbit/s + * - Only 760 + */ + +/* EFR register bits */ +#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */ +#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */ +#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */ +#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions + * and writing to IER[7:4], + * FCR[5:4], MCR[7:5] + */ +#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */ +#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no transmitter flow + * control + * 01 -> transmitter generates + * XON2 and XOFF2 + * 10 -> transmitter generates + * XON1 and XOFF1 + * 11 -> transmitter generates + * XON1, XON2, XOFF1 and + * XOFF2 + */ +#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */ +#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no received flow + * control + * 01 -> receiver compares + * XON2 and XOFF2 + * 10 -> receiver compares + * XON1 and XOFF1 + * 11 -> receiver compares + * XON1, XON2, XOFF1 and + * XOFF2 + */ + +/* Misc definitions */ +#define SC16IS7XX_FIFO_SIZE (64) +#define SC16IS7XX_REG_SHIFT 2 + +struct sc16is7xx_devtype { + char name[10]; + int nr_gpio; + int nr_uart; +}; + +struct sc16is7xx_one { + struct uart_port port; + struct work_struct tx_work; + struct work_struct md_work; + + struct serial_rs485 rs485; +}; + +struct sc16is7xx_port { + struct uart_driver uart; + struct sc16is7xx_devtype *devtype; + struct regmap *regmap; + struct mutex mutex; + struct clk *clk; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct sc16is7xx_one p[0]; +}; + +#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) + +static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int val = 0; + + regmap_read(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + + return val; +} + +static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + regmap_write(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, val); +} + +static void sc16is7xx_port_update(struct uart_port *port, u8 reg, + u8 mask, u8 val) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + regmap_update_bits(s->regmap, + (reg << SC16IS7XX_REG_SHIFT) | port->line, + mask, val); +} + + +static void sc16is7xx_power(struct uart_port *port, int on) +{ + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_IER_SLEEP_BIT, + on ? 0 : SC16IS7XX_IER_SLEEP_BIT); +} + +static const struct sc16is7xx_devtype sc16is74x_devtype = { + .name = "SC16IS74X", + .nr_gpio = 0, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is750_devtype = { + .name = "SC16IS750", + .nr_gpio = 8, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is752_devtype = { + .name = "SC16IS752", + .nr_gpio = 8, + .nr_uart = 2, +}; + +static const struct sc16is7xx_devtype sc16is760_devtype = { + .name = "SC16IS760", + .nr_gpio = 8, + .nr_uart = 1, +}; + +static const struct sc16is7xx_devtype sc16is762_devtype = { + .name = "SC16IS762", + .nr_gpio = 8, + .nr_uart = 2, +}; + +static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg) +{ + switch (reg >> SC16IS7XX_REG_SHIFT) { + case SC16IS7XX_RHR_REG: + case SC16IS7XX_IIR_REG: + case SC16IS7XX_LSR_REG: + case SC16IS7XX_MSR_REG: + case SC16IS7XX_TXLVL_REG: + case SC16IS7XX_RXLVL_REG: + case SC16IS7XX_IOSTATE_REG: + return true; + default: + break; + } + + return false; +} + +static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg) +{ + switch (reg >> SC16IS7XX_REG_SHIFT) { + case SC16IS7XX_RHR_REG: + return true; + default: + break; + } + + return false; +} + +static int sc16is7xx_set_baud(struct uart_port *port, int baud) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + u8 lcr; + u8 prescaler = 0; + unsigned long clk = port->uartclk, div = clk / 16 / baud; + + if (div > 0xffff) { + prescaler = SC16IS7XX_MCR_CLKSEL_BIT; + div /= 4; + } + + lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + /* Enable enhanced features */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + regcache_cache_bypass(s->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_CLKSEL_BIT, + prescaler); + + /* Open the LCR divisors for configuration */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_A); + + /* Write the new divisor */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256); + sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256); + regcache_cache_bypass(s->regmap, false); + + /* Put LCR back to the normal mode */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + return DIV_ROUND_CLOSEST(clk / 16, div); +} + +static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, + unsigned int iir) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int lsr = 0, ch, flag, bytes_read, i; + bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false; + + if (unlikely(rxlen >= sizeof(s->buf))) { + dev_warn_ratelimited(port->dev, + "Port %i: Possible RX FIFO overrun: %d\n", + port->line, rxlen); + port->icount.buf_overrun++; + /* Ensure sanity of RX level */ + rxlen = sizeof(s->buf); + } + + while (rxlen) { + /* Only read lsr if there are possible errors in FIFO */ + if (read_lsr) { + lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + if (!(lsr & SC16IS7XX_LSR_FIFOE_BIT)) + read_lsr = false; /* No errors left in FIFO */ + } else + lsr = 0; + + if (read_lsr) { + s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); + bytes_read = 1; + } else { + regcache_cache_bypass(s->regmap, true); + regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG, + s->buf, rxlen); + regcache_cache_bypass(s->regmap, false); + bytes_read = rxlen; + } + + lsr &= SC16IS7XX_LSR_BRK_ERROR_MASK; + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(lsr)) { + if (lsr & SC16IS7XX_LSR_BI_BIT) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (lsr & SC16IS7XX_LSR_PE_BIT) + port->icount.parity++; + else if (lsr & SC16IS7XX_LSR_FE_BIT) + port->icount.frame++; + else if (lsr & SC16IS7XX_LSR_OE_BIT) + port->icount.overrun++; + + lsr &= port->read_status_mask; + if (lsr & SC16IS7XX_LSR_BI_BIT) + flag = TTY_BREAK; + else if (lsr & SC16IS7XX_LSR_PE_BIT) + flag = TTY_PARITY; + else if (lsr & SC16IS7XX_LSR_FE_BIT) + flag = TTY_FRAME; + else if (lsr & SC16IS7XX_LSR_OE_BIT) + flag = TTY_OVERRUN; + } + + for (i = 0; i < bytes_read; ++i) { + ch = s->buf[i]; + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (lsr & port->ignore_status_mask) + continue; + + uart_insert_char(port, lsr, SC16IS7XX_LSR_OE_BIT, ch, + flag); + } + rxlen -= bytes_read; + } + + tty_flip_buffer_push(&port->state->port); +} + +static void sc16is7xx_handle_tx(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct circ_buf *xmit = &port->state->xmit; + unsigned int txlen, to_send, i; + + if (unlikely(port->x_char)) { + sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + /* Get length of data pending in circular buffer */ + to_send = uart_circ_chars_pending(xmit); + if (likely(to_send)) { + /* Limit to size of TX FIFO */ + txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + to_send = (to_send > txlen) ? txlen : to_send; + + /* Add data to send */ + port->icount.tx += to_send; + + /* Convert to linear buffer */ + for (i = 0; i < to_send; ++i) { + s->buf[i] = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } + regcache_cache_bypass(s->regmap, true); + regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send); + regcache_cache_bypass(s->regmap, false); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) +{ + struct uart_port *port = &s->p[portno].port; + + do { + unsigned int iir, msr, rxlen; + + iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); + if (iir & SC16IS7XX_IIR_NO_INT_BIT) + break; + + iir &= SC16IS7XX_IIR_ID_MASK; + + switch (iir) { + case SC16IS7XX_IIR_RDI_SRC: + case SC16IS7XX_IIR_RLSE_SRC: + case SC16IS7XX_IIR_RTOI_SRC: + case SC16IS7XX_IIR_XOFFI_SRC: + rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG); + if (rxlen) + sc16is7xx_handle_rx(port, rxlen, iir); + break; + + case SC16IS7XX_IIR_CTSRTS_SRC: + msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG); + uart_handle_cts_change(port, + !!(msr & SC16IS7XX_MSR_CTS_BIT)); + break; + case SC16IS7XX_IIR_THRI_SRC: + mutex_lock(&s->mutex); + sc16is7xx_handle_tx(port); + mutex_unlock(&s->mutex); + break; + default: + dev_err_ratelimited(port->dev, + "Port %i: Unexpected interrupt: %x", + port->line, iir); + break; + } + } while (1); +} + +static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +{ + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + int i; + + for (i = 0; i < s->uart.nr; ++i) + sc16is7xx_port_irq(s, i); + + return IRQ_HANDLED; +} + +static void sc16is7xx_wq_proc(struct work_struct *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); + struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + + mutex_lock(&s->mutex); + sc16is7xx_handle_tx(&one->port); + mutex_unlock(&s->mutex); +} + +static void sc16is7xx_stop_tx(struct uart_port* port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + struct circ_buf *xmit = &one->port.state->xmit; + + /* handle rs485 */ + if (one->rs485.flags & SER_RS485_ENABLED) { + /* do nothing if current tx not yet completed */ + int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) + return; + + if (uart_circ_empty(xmit) && + (one->rs485.delay_rts_after_send > 0)) + mdelay(one->rs485.delay_rts_after_send); + } + + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_IER_THRI_BIT, + 0); +} + +static void sc16is7xx_stop_rx(struct uart_port* port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT; + sc16is7xx_port_update(port, SC16IS7XX_IER_REG, + SC16IS7XX_LSR_DR_BIT, + 0); +} + +static void sc16is7xx_start_tx(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + /* handle rs485 */ + if ((one->rs485.flags & SER_RS485_ENABLED) && + (one->rs485.delay_rts_before_send > 0)) { + mdelay(one->rs485.delay_rts_before_send); + } + + if (!work_pending(&one->tx_work)) + schedule_work(&one->tx_work); +} + +static unsigned int sc16is7xx_tx_empty(struct uart_port *port) +{ + unsigned int lvl, lsr; + + lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); + + return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0; +} + +static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) +{ + /* DCD and DSR are not wired and CTS/RTS is handled automatically + * so just indicate DSR and CAR asserted + */ + return TIOCM_DSR | TIOCM_CAR; +} + +static void sc16is7xx_md_proc(struct work_struct *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work); + + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_LOOP_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + SC16IS7XX_MCR_LOOP_BIT : 0); +} + +static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + schedule_work(&one->md_work); +} + +static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) +{ + sc16is7xx_port_update(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_TXBREAK_BIT, + break_state ? SC16IS7XX_LCR_TXBREAK_BIT : 0); +} + +static void sc16is7xx_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int lcr, flow = 0; + int baud; + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = SC16IS7XX_LCR_WORD_LEN_5; + break; + case CS6: + lcr = SC16IS7XX_LCR_WORD_LEN_6; + break; + case CS7: + lcr = SC16IS7XX_LCR_WORD_LEN_7; + break; + case CS8: + lcr = SC16IS7XX_LCR_WORD_LEN_8; + break; + default: + lcr = SC16IS7XX_LCR_WORD_LEN_8; + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + lcr |= SC16IS7XX_LCR_PARITY_BIT; + if (!(termios->c_cflag & PARODD)) + lcr |= SC16IS7XX_LCR_EVENPARITY_BIT; + } + + /* Stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= SC16IS7XX_LCR_STOPLEN_BIT; /* 2 stops */ + + /* Set read status mask */ + port->read_status_mask = SC16IS7XX_LSR_OE_BIT; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SC16IS7XX_LSR_PE_BIT | + SC16IS7XX_LSR_FE_BIT; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SC16IS7XX_LSR_BI_BIT; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= SC16IS7XX_LSR_BI_BIT; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; + + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + /* Configure flow control */ + regcache_cache_bypass(s->regmap, true); + sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]); + sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]); + if (termios->c_cflag & CRTSCTS) + flow |= SC16IS7XX_EFR_AUTOCTS_BIT | + SC16IS7XX_EFR_AUTORTS_BIT; + if (termios->c_iflag & IXON) + flow |= SC16IS7XX_EFR_SWFLOW3_BIT; + if (termios->c_iflag & IXOFF) + flow |= SC16IS7XX_EFR_SWFLOW1_BIT; + + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow); + regcache_cache_bypass(s->regmap, false); + + /* Update LCR register */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); + + /* Get baud rate generator configuration */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 4 / 0xffff, + port->uartclk / 16); + + /* Setup baudrate generator */ + baud = sc16is7xx_set_baud(port, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); +} + +#if defined(TIOCSRS485) && defined(TIOCGRS485) +static void sc16is7xx_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + one->rs485 = *rs485; + + if (one->rs485.flags & SER_RS485_ENABLED) { + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_AUTO_RS485_BIT, + SC16IS7XX_EFCR_AUTO_RS485_BIT); + } else { + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_AUTO_RS485_BIT, + 0); + } +} +#endif + +static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd, + unsigned long arg) +{ +#if defined(TIOCSRS485) && defined(TIOCGRS485) + struct serial_rs485 rs485; + + switch (cmd) { + case TIOCSRS485: + if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485))) + return -EFAULT; + + sc16is7xx_config_rs485(port, &rs485); + return 0; + case TIOCGRS485: + if (copy_to_user((void __user *)arg, + &(to_sc16is7xx_one(port, port)->rs485), + sizeof(rs485))) + return -EFAULT; + return 0; + default: + break; + } +#endif + + return -ENOIOCTLCMD; +} + +static int sc16is7xx_startup(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + unsigned int val; + + sc16is7xx_power(port, 1); + + /* Reset FIFOs*/ + val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT; + sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val); + udelay(5); + sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, + SC16IS7XX_FCR_FIFO_BIT); + + /* Enable EFR */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + regcache_cache_bypass(s->regmap, true); + + /* Enable write access to enhanced features and internal clock div */ + sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + + /* Enable TCR/TLR */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_TCRTLR_BIT, + SC16IS7XX_MCR_TCRTLR_BIT); + + /* Configure flow control levels */ + /* Flow control halt level 48, resume level 24 */ + sc16is7xx_port_write(port, SC16IS7XX_TCR_REG, + SC16IS7XX_TCR_RX_RESUME(24) | + SC16IS7XX_TCR_RX_HALT(48)); + + regcache_cache_bypass(s->regmap, false); + + /* Now, initialize the UART */ + sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); + + /* Enable the Rx and Tx FIFO */ + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT, + 0); + + /* Enable RX, TX, CTS change interrupts */ + val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT | + SC16IS7XX_IER_CTSI_BIT; + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); + + return 0; +} + +static void sc16is7xx_shutdown(struct uart_port *port) +{ + /* Disable all interrupts */ + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ + sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + + sc16is7xx_power(port, 0); +} + +static const char *sc16is7xx_type(struct uart_port *port) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + + return (port->type == PORT_SC16IS7XX) ? s->devtype->name : NULL; +} + +static int sc16is7xx_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void sc16is7xx_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_SC16IS7XX; +} + +static int sc16is7xx_verify_port(struct uart_port *port, + struct serial_struct *s) +{ + if ((s->type != PORT_UNKNOWN) && (s->type != PORT_SC16IS7XX)) + return -EINVAL; + if (s->irq != port->irq) + return -EINVAL; + + return 0; +} + +static void sc16is7xx_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + sc16is7xx_power(port, (state == UART_PM_STATE_ON) ? 1 : 0); +} + +static void sc16is7xx_null_void(struct uart_port *port) +{ + /* Do nothing */ +} + +static const struct uart_ops sc16is7xx_ops = { + .tx_empty = sc16is7xx_tx_empty, + .set_mctrl = sc16is7xx_set_mctrl, + .get_mctrl = sc16is7xx_get_mctrl, + .stop_tx = sc16is7xx_stop_tx, + .start_tx = sc16is7xx_start_tx, + .stop_rx = sc16is7xx_stop_rx, + .enable_ms = sc16is7xx_null_void, + .break_ctl = sc16is7xx_break_ctl, + .startup = sc16is7xx_startup, + .shutdown = sc16is7xx_shutdown, + .set_termios = sc16is7xx_set_termios, + .type = sc16is7xx_type, + .request_port = sc16is7xx_request_port, + .release_port = sc16is7xx_null_void, + .config_port = sc16is7xx_config_port, + .verify_port = sc16is7xx_verify_port, + .ioctl = sc16is7xx_ioctl, + .pm = sc16is7xx_pm, +}; + +#ifdef CONFIG_GPIOLIB +static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int val; + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG); + + return !!(val & BIT(offset)); +} + +static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), + val ? BIT(offset) : 0); +} + +static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0); + + return 0; +} + +static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int val) +{ + struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port, + gpio); + struct uart_port *port = &s->p[0].port; + + sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset), + val ? BIT(offset) : 0); + sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), + BIT(offset)); + + return 0; +} +#endif + +static int sc16is7xx_probe(struct device *dev, + struct sc16is7xx_devtype *devtype, + struct regmap *regmap, int irq, unsigned long flags) +{ + unsigned long freq, *pfreq = dev_get_platdata(dev); + struct clk *clk; + int i, ret; + struct sc16is7xx_port *s; + + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Alloc port structure */ + s = devm_kzalloc(dev, sizeof(*s) + + sizeof(struct sc16is7xx_one) * devtype->nr_uart, + GFP_KERNEL); + if (!s) { + dev_err(dev, "Error allocating port structure\n"); + return -ENOMEM; + } + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + if (pfreq) + freq = *pfreq; + else + return PTR_ERR(clk); + } else { + freq = clk_get_rate(clk); + } + + s->regmap = regmap; + s->devtype = devtype; + dev_set_drvdata(dev, s); + + /* Register UART driver */ + s->uart.owner = THIS_MODULE; + s->uart.dev_name = "ttySC"; + s->uart.nr = devtype->nr_uart; + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(dev, "Registering UART driver failed\n"); + goto out_clk; + } + +#ifdef CONFIG_GPIOLIB + if (devtype->nr_gpio) { + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = sc16is7xx_gpio_direction_input; + s->gpio.get = sc16is7xx_gpio_get; + s->gpio.direction_output = sc16is7xx_gpio_direction_output; + s->gpio.set = sc16is7xx_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr_gpio; + s->gpio.can_sleep = 1; + ret = gpiochip_add(&s->gpio); + if (ret) + goto out_uart; + } +#endif + + mutex_init(&s->mutex); + + for (i = 0; i < devtype->nr_uart; ++i) { + /* Initialize port data */ + s->p[i].port.line = i; + s->p[i].port.dev = dev; + s->p[i].port.irq = irq; + s->p[i].port.type = PORT_SC16IS7XX; + s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE; + s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY; + s->p[i].port.iotype = UPIO_PORT; + s->p[i].port.uartclk = freq; + s->p[i].port.ops = &sc16is7xx_ops; + /* Disable all interrupts */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); + /* Disable TX/RX */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + /* Initialize queue for start TX */ + INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); + /* Initialize queue for changing mode */ + INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); + /* Register port */ + uart_add_one_port(&s->uart, &s->p[i].port); + /* Go to suspend mode */ + sc16is7xx_power(&s->p[i].port, 0); + } + + /* Setup interrupt */ + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, + IRQF_ONESHOT | flags, dev_name(dev), s); + if (!ret) + return 0; + + mutex_destroy(&s->mutex); + +#ifdef CONFIG_GPIOLIB + if (devtype->nr_gpio) + WARN_ON(gpiochip_remove(&s->gpio)); + +out_uart: +#endif + uart_unregister_driver(&s->uart); + +out_clk: + if (!IS_ERR(s->clk)) + clk_disable_unprepare(s->clk); + + return ret; +} + +static int sc16is7xx_remove(struct device *dev) +{ + struct sc16is7xx_port *s = dev_get_drvdata(dev); + int i, ret = 0; + +#ifdef CONFIG_GPIOLIB + if (s->devtype->nr_gpio) { + ret = gpiochip_remove(&s->gpio); + if (ret) + return ret; + } +#endif + + for (i = 0; i < s->uart.nr; i++) { + cancel_work_sync(&s->p[i].tx_work); + cancel_work_sync(&s->p[i].md_work); + uart_remove_one_port(&s->uart, &s->p[i].port); + sc16is7xx_power(&s->p[i].port, 0); + } + + mutex_destroy(&s->mutex); + uart_unregister_driver(&s->uart); + if (!IS_ERR(s->clk)) + clk_disable_unprepare(s->clk); + + return ret; +} + +static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = { + { .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, }, + { .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, }, + { .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, }, + { .compatible = "nxp,sc16is752", .data = &sc16is752_devtype, }, + { .compatible = "nxp,sc16is760", .data = &sc16is760_devtype, }, + { .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids); + +static struct regmap_config regcfg = { + .reg_bits = 7, + .pad_bits = 1, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = sc16is7xx_regmap_volatile, + .precious_reg = sc16is7xx_regmap_precious, +}; + +static int sc16is7xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct sc16is7xx_devtype *devtype; + unsigned long flags = 0; + struct regmap *regmap; + + if (i2c->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(sc16is7xx_dt_ids, &i2c->dev); + + devtype = (struct sc16is7xx_devtype *)of_id->data; + } else { + devtype = (struct sc16is7xx_devtype *)id->driver_data; + flags = IRQF_TRIGGER_FALLING; + } + + regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | + (devtype->nr_uart - 1); + regmap = devm_regmap_init_i2c(i2c, ®cfg); + + return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags); +} + +static int sc16is7xx_i2c_remove(struct i2c_client *client) +{ + return sc16is7xx_remove(&client->dev); +} + +static const struct i2c_device_id sc16is7xx_i2c_id_table[] = { + { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, }, + { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, }, + { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, }, + { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, }, + { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); + +static struct i2c_driver sc16is7xx_i2c_uart_driver = { + .driver = { + .name = SC16IS7XX_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sc16is7xx_dt_ids), + }, + .probe = sc16is7xx_i2c_probe, + .remove = sc16is7xx_i2c_remove, + .id_table = sc16is7xx_i2c_id_table, +}; +module_i2c_driver(sc16is7xx_i2c_uart_driver); +MODULE_ALIAS("i2c:sc16is7xx"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>"); +MODULE_DESCRIPTION("SC16IS7XX serial driver"); diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c deleted file mode 100644 index 887b4f77074..00000000000 --- a/drivers/tty/serial/sc26xx.c +++ /dev/null @@ -1,749 +0,0 @@ -/* - * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. - * - * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/circ_buf.h> -#include <linux/serial.h> -#include <linux/sysrq.h> -#include <linux/console.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/irq.h> -#include <linux/io.h> - -#warning "Please try migrate to use new driver SCCNXP and report the status" \ - "in the linux-serial mailing list." - -#if defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/serial_core.h> - -#define SC26XX_MAJOR 204 -#define SC26XX_MINOR_START 205 -#define SC26XX_NR 2 - -struct uart_sc26xx_port { - struct uart_port port[2]; - u8 dsr_mask[2]; - u8 cts_mask[2]; - u8 dcd_mask[2]; - u8 ri_mask[2]; - u8 dtr_mask[2]; - u8 rts_mask[2]; - u8 imr; -}; - -/* register common to both ports */ -#define RD_ISR 0x14 -#define RD_IPR 0x34 - -#define WR_ACR 0x10 -#define WR_IMR 0x14 -#define WR_OPCR 0x34 -#define WR_OPR_SET 0x38 -#define WR_OPR_CLR 0x3C - -/* access common register */ -#define READ_SC(p, r) readb((p)->membase + RD_##r) -#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r) - -/* register per port */ -#define RD_PORT_MRx 0x00 -#define RD_PORT_SR 0x04 -#define RD_PORT_RHR 0x0c - -#define WR_PORT_MRx 0x00 -#define WR_PORT_CSR 0x04 -#define WR_PORT_CR 0x08 -#define WR_PORT_THR 0x0c - -/* SR bits */ -#define SR_BREAK (1 << 7) -#define SR_FRAME (1 << 6) -#define SR_PARITY (1 << 5) -#define SR_OVERRUN (1 << 4) -#define SR_TXRDY (1 << 2) -#define SR_RXRDY (1 << 0) - -#define CR_RES_MR (1 << 4) -#define CR_RES_RX (2 << 4) -#define CR_RES_TX (3 << 4) -#define CR_STRT_BRK (6 << 4) -#define CR_STOP_BRK (7 << 4) -#define CR_DIS_TX (1 << 3) -#define CR_ENA_TX (1 << 2) -#define CR_DIS_RX (1 << 1) -#define CR_ENA_RX (1 << 0) - -/* ISR bits */ -#define ISR_RXRDYB (1 << 5) -#define ISR_TXRDYB (1 << 4) -#define ISR_RXRDYA (1 << 1) -#define ISR_TXRDYA (1 << 0) - -/* IMR bits */ -#define IMR_RXRDY (1 << 1) -#define IMR_TXRDY (1 << 0) - -/* access port register */ -static inline u8 read_sc_port(struct uart_port *p, u8 reg) -{ - return readb(p->membase + p->line * 0x20 + reg); -} - -static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) -{ - writeb(val, p->membase + p->line * 0x20 + reg); -} - -#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r) -#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) - -static void sc26xx_enable_irq(struct uart_port *port, int mask) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - up->imr |= mask << (line * 4); - WRITE_SC(port, IMR, up->imr); -} - -static void sc26xx_disable_irq(struct uart_port *port, int mask) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - up->imr &= ~(mask << (line * 4)); - WRITE_SC(port, IMR, up->imr); -} - -static bool receive_chars(struct uart_port *port) -{ - struct tty_port *tport = NULL; - int limit = 10000; - unsigned char ch; - char flag; - u8 status; - - /* FIXME what is this trying to achieve? */ - if (port->state != NULL) /* Unopened serial console */ - tport = &port->state->port; - - while (limit-- > 0) { - status = READ_SC_PORT(port, SR); - if (!(status & SR_RXRDY)) - break; - ch = READ_SC_PORT(port, RHR); - - flag = TTY_NORMAL; - port->icount.rx++; - - if (unlikely(status & (SR_BREAK | SR_FRAME | - SR_PARITY | SR_OVERRUN))) { - if (status & SR_BREAK) { - status &= ~(SR_PARITY | SR_FRAME); - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (status & SR_PARITY) - port->icount.parity++; - else if (status & SR_FRAME) - port->icount.frame++; - if (status & SR_OVERRUN) - port->icount.overrun++; - - status &= port->read_status_mask; - if (status & SR_BREAK) - flag = TTY_BREAK; - else if (status & SR_PARITY) - flag = TTY_PARITY; - else if (status & SR_FRAME) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(port, ch)) - continue; - - if (status & port->ignore_status_mask) - continue; - - tty_insert_flip_char(tport, ch, flag); - } - return !!tport; -} - -static void transmit_chars(struct uart_port *port) -{ - struct circ_buf *xmit; - - if (!port->state) - return; - - xmit = &port->state->xmit; - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - sc26xx_disable_irq(port, IMR_TXRDY); - return; - } - while (!uart_circ_empty(xmit)) { - if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) - break; - - WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static irqreturn_t sc26xx_interrupt(int irq, void *dev_id) -{ - struct uart_sc26xx_port *up = dev_id; - unsigned long flags; - bool push; - u8 isr; - - spin_lock_irqsave(&up->port[0].lock, flags); - - push = false; - isr = READ_SC(&up->port[0], ISR); - if (isr & ISR_TXRDYA) - transmit_chars(&up->port[0]); - if (isr & ISR_RXRDYA) - push = receive_chars(&up->port[0]); - - spin_unlock(&up->port[0].lock); - - if (push) - tty_flip_buffer_push(&up->port[0].state->port); - - spin_lock(&up->port[1].lock); - - push = false; - if (isr & ISR_TXRDYB) - transmit_chars(&up->port[1]); - if (isr & ISR_RXRDYB) - push = receive_chars(&up->port[1]); - - spin_unlock_irqrestore(&up->port[1].lock, flags); - - if (push) - tty_flip_buffer_push(&up->port[1].state->port); - - return IRQ_HANDLED; -} - -/* port->lock is not held. */ -static unsigned int sc26xx_tx_empty(struct uart_port *port) -{ - return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; -} - -/* port->lock held by caller. */ -static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_sc26xx_port *up; - int line = port->line; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - - if (up->dtr_mask[line]) { - if (mctrl & TIOCM_DTR) - WRITE_SC(port, OPR_SET, up->dtr_mask[line]); - else - WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); - } - if (up->rts_mask[line]) { - if (mctrl & TIOCM_RTS) - WRITE_SC(port, OPR_SET, up->rts_mask[line]); - else - WRITE_SC(port, OPR_CLR, up->rts_mask[line]); - } -} - -/* port->lock is held by caller and interrupts are disabled. */ -static unsigned int sc26xx_get_mctrl(struct uart_port *port) -{ - struct uart_sc26xx_port *up; - int line = port->line; - unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; - u8 ipr; - - port -= line; - up = container_of(port, struct uart_sc26xx_port, port[0]); - ipr = READ_SC(port, IPR) ^ 0xff; - - if (up->dsr_mask[line]) { - mctrl &= ~TIOCM_DSR; - mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; - } - if (up->cts_mask[line]) { - mctrl &= ~TIOCM_CTS; - mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; - } - if (up->dcd_mask[line]) { - mctrl &= ~TIOCM_CAR; - mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; - } - if (up->ri_mask[line]) { - mctrl &= ~TIOCM_RNG; - mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; - } - return mctrl; -} - -/* port->lock held by caller. */ -static void sc26xx_stop_tx(struct uart_port *port) -{ - return; -} - -/* port->lock held by caller. */ -static void sc26xx_start_tx(struct uart_port *port) -{ - struct circ_buf *xmit = &port->state->xmit; - - while (!uart_circ_empty(xmit)) { - if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { - sc26xx_enable_irq(port, IMR_TXRDY); - break; - } - WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } -} - -/* port->lock held by caller. */ -static void sc26xx_stop_rx(struct uart_port *port) -{ -} - -/* port->lock held by caller. */ -static void sc26xx_enable_ms(struct uart_port *port) -{ -} - -/* port->lock is not held. */ -static void sc26xx_break_ctl(struct uart_port *port, int break_state) -{ - if (break_state == -1) - WRITE_SC_PORT(port, CR, CR_STRT_BRK); - else - WRITE_SC_PORT(port, CR, CR_STOP_BRK); -} - -/* port->lock is not held. */ -static int sc26xx_startup(struct uart_port *port) -{ - sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); - WRITE_SC(port, OPCR, 0); - - /* reset tx and rx */ - WRITE_SC_PORT(port, CR, CR_RES_RX); - WRITE_SC_PORT(port, CR, CR_RES_TX); - - /* start rx/tx */ - WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); - - /* enable irqs */ - sc26xx_enable_irq(port, IMR_RXRDY); - return 0; -} - -/* port->lock is not held. */ -static void sc26xx_shutdown(struct uart_port *port) -{ - /* disable interrupst */ - sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); - - /* stop tx/rx */ - WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); -} - -/* port->lock is not held. */ -static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); - unsigned int quot = uart_get_divisor(port, baud); - unsigned int iflag, cflag; - unsigned long flags; - u8 mr1, mr2, csr; - - spin_lock_irqsave(&port->lock, flags); - - while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) - udelay(2); - - WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); - - iflag = termios->c_iflag; - cflag = termios->c_cflag; - - port->read_status_mask = SR_OVERRUN; - if (iflag & INPCK) - port->read_status_mask |= SR_PARITY | SR_FRAME; - if (iflag & (BRKINT | PARMRK)) - port->read_status_mask |= SR_BREAK; - - port->ignore_status_mask = 0; - if (iflag & IGNBRK) - port->ignore_status_mask |= SR_BREAK; - if ((cflag & CREAD) == 0) - port->ignore_status_mask |= SR_BREAK | SR_FRAME | - SR_PARITY | SR_OVERRUN; - - switch (cflag & CSIZE) { - case CS5: - mr1 = 0x00; - break; - case CS6: - mr1 = 0x01; - break; - case CS7: - mr1 = 0x02; - break; - default: - case CS8: - mr1 = 0x03; - break; - } - mr2 = 0x07; - if (cflag & CSTOPB) - mr2 = 0x0f; - if (cflag & PARENB) { - if (cflag & PARODD) - mr1 |= (1 << 2); - } else - mr1 |= (2 << 3); - - switch (baud) { - case 50: - csr = 0x00; - break; - case 110: - csr = 0x11; - break; - case 134: - csr = 0x22; - break; - case 200: - csr = 0x33; - break; - case 300: - csr = 0x44; - break; - case 600: - csr = 0x55; - break; - case 1200: - csr = 0x66; - break; - case 2400: - csr = 0x88; - break; - case 4800: - csr = 0x99; - break; - default: - case 9600: - csr = 0xbb; - break; - case 19200: - csr = 0xcc; - break; - } - - WRITE_SC_PORT(port, CR, CR_RES_MR); - WRITE_SC_PORT(port, MRx, mr1); - WRITE_SC_PORT(port, MRx, mr2); - - WRITE_SC(port, ACR, 0x80); - WRITE_SC_PORT(port, CSR, csr); - - /* reset tx and rx */ - WRITE_SC_PORT(port, CR, CR_RES_RX); - WRITE_SC_PORT(port, CR, CR_RES_TX); - - WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); - while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) - udelay(2); - - /* XXX */ - uart_update_timeout(port, cflag, - (port->uartclk / (16 * quot))); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *sc26xx_type(struct uart_port *port) -{ - return "SC26XX"; -} - -static void sc26xx_release_port(struct uart_port *port) -{ -} - -static int sc26xx_request_port(struct uart_port *port) -{ - return 0; -} - -static void sc26xx_config_port(struct uart_port *port, int flags) -{ -} - -static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - return -EINVAL; -} - -static struct uart_ops sc26xx_ops = { - .tx_empty = sc26xx_tx_empty, - .set_mctrl = sc26xx_set_mctrl, - .get_mctrl = sc26xx_get_mctrl, - .stop_tx = sc26xx_stop_tx, - .start_tx = sc26xx_start_tx, - .stop_rx = sc26xx_stop_rx, - .enable_ms = sc26xx_enable_ms, - .break_ctl = sc26xx_break_ctl, - .startup = sc26xx_startup, - .shutdown = sc26xx_shutdown, - .set_termios = sc26xx_set_termios, - .type = sc26xx_type, - .release_port = sc26xx_release_port, - .request_port = sc26xx_request_port, - .config_port = sc26xx_config_port, - .verify_port = sc26xx_verify_port, -}; - -static struct uart_port *sc26xx_port; - -#ifdef CONFIG_SERIAL_SC26XX_CONSOLE -static void sc26xx_console_putchar(struct uart_port *port, char c) -{ - unsigned long flags; - int limit = 1000000; - - spin_lock_irqsave(&port->lock, flags); - - while (limit-- > 0) { - if (READ_SC_PORT(port, SR) & SR_TXRDY) { - WRITE_SC_PORT(port, THR, c); - break; - } - udelay(2); - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -static void sc26xx_console_write(struct console *con, const char *s, unsigned n) -{ - struct uart_port *port = sc26xx_port; - int i; - - for (i = 0; i < n; i++) { - if (*s == '\n') - sc26xx_console_putchar(port, '\r'); - sc26xx_console_putchar(port, *s++); - } -} - -static int __init sc26xx_console_setup(struct console *con, char *options) -{ - struct uart_port *port = sc26xx_port; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (port->type != PORT_SC26XX) - return -1; - - printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, con, baud, parity, bits, flow); -} - -static struct uart_driver sc26xx_reg; -static struct console sc26xx_console = { - .name = "ttySC", - .write = sc26xx_console_write, - .device = uart_console_device, - .setup = sc26xx_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &sc26xx_reg, -}; -#define SC26XX_CONSOLE &sc26xx_console -#else -#define SC26XX_CONSOLE NULL -#endif - -static struct uart_driver sc26xx_reg = { - .owner = THIS_MODULE, - .driver_name = "SC26xx", - .dev_name = "ttySC", - .major = SC26XX_MAJOR, - .minor = SC26XX_MINOR_START, - .nr = SC26XX_NR, - .cons = SC26XX_CONSOLE, -}; - -static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) -{ - unsigned int bit = (flags >> bitpos) & 15; - - return bit ? (1 << (bit - 1)) : 0; -} - -static void sc26xx_init_masks(struct uart_sc26xx_port *up, - int line, unsigned int data) -{ - up->dtr_mask[line] = sc26xx_flags2mask(data, 0); - up->rts_mask[line] = sc26xx_flags2mask(data, 4); - up->dsr_mask[line] = sc26xx_flags2mask(data, 8); - up->cts_mask[line] = sc26xx_flags2mask(data, 12); - up->dcd_mask[line] = sc26xx_flags2mask(data, 16); - up->ri_mask[line] = sc26xx_flags2mask(data, 20); -} - -static int sc26xx_probe(struct platform_device *dev) -{ - struct resource *res; - struct uart_sc26xx_port *up; - unsigned int *sc26xx_data = dev_get_platdata(&dev->dev); - int err; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - up = kzalloc(sizeof *up, GFP_KERNEL); - if (unlikely(!up)) - return -ENOMEM; - - up->port[0].line = 0; - up->port[0].ops = &sc26xx_ops; - up->port[0].type = PORT_SC26XX; - up->port[0].uartclk = (29491200 / 16); /* arbitrary */ - - up->port[0].mapbase = res->start; - up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); - up->port[0].iotype = UPIO_MEM; - up->port[0].irq = platform_get_irq(dev, 0); - - up->port[0].dev = &dev->dev; - - sc26xx_init_masks(up, 0, sc26xx_data[0]); - - sc26xx_port = &up->port[0]; - - up->port[1].line = 1; - up->port[1].ops = &sc26xx_ops; - up->port[1].type = PORT_SC26XX; - up->port[1].uartclk = (29491200 / 16); /* arbitrary */ - - up->port[1].mapbase = up->port[0].mapbase; - up->port[1].membase = up->port[0].membase; - up->port[1].iotype = UPIO_MEM; - up->port[1].irq = up->port[0].irq; - - up->port[1].dev = &dev->dev; - - sc26xx_init_masks(up, 1, sc26xx_data[1]); - - err = uart_register_driver(&sc26xx_reg); - if (err) - goto out_free_port; - - sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; - - err = uart_add_one_port(&sc26xx_reg, &up->port[0]); - if (err) - goto out_unregister_driver; - - err = uart_add_one_port(&sc26xx_reg, &up->port[1]); - if (err) - goto out_remove_port0; - - err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); - if (err) - goto out_remove_ports; - - platform_set_drvdata(dev, up); - return 0; - -out_remove_ports: - uart_remove_one_port(&sc26xx_reg, &up->port[1]); -out_remove_port0: - uart_remove_one_port(&sc26xx_reg, &up->port[0]); - -out_unregister_driver: - uart_unregister_driver(&sc26xx_reg); - -out_free_port: - kfree(up); - sc26xx_port = NULL; - return err; -} - - -static int __exit sc26xx_driver_remove(struct platform_device *dev) -{ - struct uart_sc26xx_port *up = platform_get_drvdata(dev); - - free_irq(up->port[0].irq, up); - - uart_remove_one_port(&sc26xx_reg, &up->port[0]); - uart_remove_one_port(&sc26xx_reg, &up->port[1]); - - uart_unregister_driver(&sc26xx_reg); - - kfree(up); - sc26xx_port = NULL; - - return 0; -} - -static struct platform_driver sc26xx_driver = { - .probe = sc26xx_probe, - .remove = sc26xx_driver_remove, - .driver = { - .name = "SC26xx", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(sc26xx_driver); - -MODULE_AUTHOR("Thomas Bogendörfer"); -MODULE_DESCRIPTION("SC681/SC2692 serial driver"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:SC26xx"); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 49e9bbfe6ca..e84b6a3bdd1 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data) sccnxp_handle_events(s); spin_unlock_irqrestore(&s->lock, flags); - if (!timer_pending(&s->timer)) - mod_timer(&s->timer, jiffies + - usecs_to_jiffies(s->pdata.poll_time_us)); + mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us)); } static irqreturn_t sccnxp_ist(int irq, void *dev_id) @@ -667,13 +665,15 @@ static void sccnxp_set_termios(struct uart_port *port, port->read_status_mask = SR_OVR; if (termios->c_iflag & INPCK) port->read_status_mask |= SR_PE | SR_FE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= SR_BRK; /* Set status ignore mask */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNBRK) port->ignore_status_mask |= SR_BRK; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= SR_PE; if (!(termios->c_cflag & CREAD)) port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; @@ -986,6 +986,7 @@ static int sccnxp_probe(struct platform_device *pdev) return 0; } + uart_unregister_driver(&s->uart); err_out: if (!IS_ERR(s->regulator)) return regulator_disable(s->regulator); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 0489a2bdcdf..d5c2a287b7e 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -34,6 +34,7 @@ #include <linux/of_device.h> #include <linux/pagemap.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/serial_core.h> @@ -44,8 +45,6 @@ #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/clk/tegra.h> - #define TEGRA_UART_TYPE "TEGRA_UART" #define TX_EMPTY_STATUS (UART_LSR_TEMT | UART_LSR_THRE) #define BYTES_TO_ALIGN(x) ((unsigned long)(x) & 0x3) @@ -103,6 +102,7 @@ struct tegra_uart_port { const struct tegra_uart_chip_data *cdata; struct clk *uart_clk; + struct reset_control *rst; unsigned int current_baud; /* Register shadow */ @@ -120,7 +120,6 @@ struct tegra_uart_port { bool rx_timeout; int rx_in_progress; int symb_bit; - int dma_req_sel; struct dma_chan *rx_dma_chan; struct dma_chan *tx_dma_chan; @@ -832,9 +831,9 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) clk_prepare_enable(tup->uart_clk); /* Reset the UART controller to clear all previous status.*/ - tegra_periph_reset_assert(tup->uart_clk); + reset_control_assert(tup->rst); udelay(10); - tegra_periph_reset_deassert(tup->uart_clk); + reset_control_deassert(tup->rst); tup->rx_in_progress = 0; tup->tx_in_progress = 0; @@ -910,15 +909,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_addr_t dma_phys; int ret; struct dma_slave_config dma_sconfig; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_chan = dma_request_channel(mask, NULL, NULL); - if (!dma_chan) { + dma_chan = dma_request_slave_channel_reason(tup->uport.dev, + dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) { + ret = PTR_ERR(dma_chan); dev_err(tup->uport.dev, - "Dma channel is not available, will try later\n"); - return -EPROBE_DEFER; + "DMA channel alloc failed: %d\n", ret); + return ret; } if (dma_to_memory) { @@ -938,7 +936,6 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_buf = tup->uport.state->xmit.buf; } - dma_sconfig.slave_id = tup->dma_req_sel; if (dma_to_memory) { dma_sconfig.src_addr = tup->uport.mapbase; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; @@ -1018,7 +1015,7 @@ static int tegra_uart_startup(struct uart_port *u) goto fail_hw_init; } - ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED, + ret = request_irq(u->irq, tegra_uart_isr, 0, dev_name(u->dev), tup); if (ret < 0) { dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); @@ -1222,17 +1219,8 @@ static int tegra_uart_parse_dt(struct platform_device *pdev, struct tegra_uart_port *tup) { struct device_node *np = pdev->dev.of_node; - u32 of_dma[2]; int port; - if (of_property_read_u32_array(np, "nvidia,dma-request-selector", - of_dma, 2) >= 0) { - tup->dma_req_sel = of_dma[1]; - } else { - dev_err(&pdev->dev, "missing dma requestor in device tree\n"); - return -EINVAL; - } - port = of_alias_get_id(np, "serial"); if (port < 0) { dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); @@ -1320,6 +1308,12 @@ static int tegra_uart_probe(struct platform_device *pdev) return PTR_ERR(tup->uart_clk); } + tup->rst = devm_reset_control_get(&pdev->dev, "serial"); + if (IS_ERR(tup->rst)) { + dev_err(&pdev->dev, "Couldn't get the reset\n"); + return PTR_ERR(tup->rst); + } + u->iotype = UPIO_MEM32; u->irq = platform_get_irq(pdev, 0); u->regshift = 2; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0f02351c923..fbf6c5ad222 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -89,8 +89,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && - !tty->stopped && !tty->hw_stopped) + if (!tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } @@ -138,6 +137,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, return 1; /* + * Make sure the device is in D0 state. + */ + uart_change_pm(state, UART_PM_STATE_ON); + + /* * Initialise and allocate the transmit and temporary * buffer. */ @@ -170,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - - if (tty_port_cts_enabled(port)) { + /* + * if hw support flow control without software intervention, + * then skip the below check + */ + if (tty_port_cts_enabled(port) && + !(uport->flags & UPF_HARD_FLOW)) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -826,25 +834,29 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, * If we fail to request resources for the * new port, try to restore the old settings. */ - if (retval && old_type != PORT_UNKNOWN) { + if (retval) { uport->iobase = old_iobase; uport->type = old_type; uport->hub6 = old_hub6; uport->iotype = old_iotype; uport->regshift = old_shift; uport->mapbase = old_mapbase; - retval = uport->ops->request_port(uport); - /* - * If we failed to restore the old settings, - * we fail like this. - */ - if (retval) - uport->type = PORT_UNKNOWN; - /* - * We failed anyway. - */ - retval = -EBUSY; + if (old_type != PORT_UNKNOWN) { + retval = uport->ops->request_port(uport); + /* + * If we failed to restore the old settings, + * we fail like this. + */ + if (retval) + uport->type = PORT_UNKNOWN; + + /* + * We failed anyway. + */ + retval = -EBUSY; + } + /* Added to return the correct error -Ram Gupta */ goto exit; } @@ -1319,9 +1331,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uport = state->uart_port; port = &state->port; - pr_debug("uart_close(%d) called\n", uport->line); + pr_debug("uart_close(%d) called\n", uport ? uport->line : -1); - if (tty_port_close_start(port, tty, filp) == 0) + if (!port->count || tty_port_close_start(port, tty, filp) == 0) return; /* @@ -1452,6 +1464,8 @@ static void uart_hangup(struct tty_struct *tty) clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); spin_unlock_irqrestore(&port->lock, flags); tty_port_tty_set(port, NULL); + if (!uart_console(state->uart_port)) + uart_change_pm(state, UART_PM_STATE_OFF); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); } @@ -1570,12 +1584,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) } /* - * Make sure the device is in D0 state. - */ - if (port->count == 1) - uart_change_pm(state, UART_PM_STATE_ON); - - /* * Start up the serial port. */ retval = uart_startup(tty, state, 0); @@ -1762,7 +1770,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) } /** - * uart_parse_options - Parse serial port baud/parity/bits/flow contro. + * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. * @parity: pointer to an 'int' variable for the parity. @@ -1830,9 +1838,13 @@ uart_set_options(struct uart_port *port, struct console *co, /* * Ensure that the serial console lock is initialised * early. + * If this port is a console, then the spinlock is already + * initialised. */ - spin_lock_init(&port->lock); - lockdep_set_class(&port->lock, &port_lock_key); + if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); + } memset(&termios, 0, sizeof(struct ktermios)); @@ -2231,6 +2243,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) return; port = state->uart_port; + + if (ch == '\n') + port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); } #endif @@ -2605,7 +2620,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) /* * Register the port whether it's detected or not. This allows - * setserial to be used to alter this ports parameters. + * setserial to be used to alter this port's parameters. */ tty_dev = tty_port_register_device_attr(port, drv->tty_driver, uport->line, uport->dev, port, tty_dev_attr_groups); @@ -2641,6 +2656,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; + struct tty_struct *tty; int ret = 0; BUG_ON(in_interrupt()); @@ -2669,8 +2685,17 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ tty_unregister_device(drv->tty_driver, uport->line); - if (port->tty) + tty = tty_port_tty_get(port); + if (tty) { tty_vhangup(port->tty); + tty_kref_put(tty); + } + + /* + * If the port is used as a console, unregister it + */ + if (uart_console(uport)) + unregister_console(uport->cons); /* * Free the port IO and memory resources, if any. @@ -2754,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) uport->icount.cts++; - if (tty_port_cts_enabled(port)) { + /* skip below code if the hw flow control is supported */ + if (tty_port_cts_enabled(port) && + !(uport->flags & UPF_HARD_FLOW)) { if (tty->hw_stopped) { if (status) { tty->hw_stopped = 0; diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index e1caa99e3d3..5c79bdab985 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -437,7 +437,7 @@ static void ks8695uart_set_termios(struct uart_port *port, struct ktermios *term port->read_status_mask = URLS_URROE; if (termios->c_iflag & INPCK) port->read_status_mask |= (URLS_URFE | URLS_URPE); - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= URLS_URBI; /* diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c new file mode 100644 index 00000000000..bf9560ffe3f --- /dev/null +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -0,0 +1,143 @@ +/* + * Helpers for controlling modem lines via GPIO + * + * Copyright (C) 2014 Paratronic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <uapi/asm-generic/termios.h> + +#include "serial_mctrl_gpio.h" + +struct mctrl_gpios { + struct gpio_desc *gpio[UART_GPIO_MAX]; +}; + +static const struct { + const char *name; + unsigned int mctrl; + bool dir_out; +} mctrl_gpios_desc[UART_GPIO_MAX] = { + { "cts", TIOCM_CTS, false, }, + { "dsr", TIOCM_DSR, false, }, + { "dcd", TIOCM_CD, false, }, + { "rng", TIOCM_RNG, false, }, + { "rts", TIOCM_RTS, true, }, + { "dtr", TIOCM_DTR, true, }, + { "out1", TIOCM_OUT1, true, }, + { "out2", TIOCM_OUT2, true, }, +}; + +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) +{ + enum mctrl_gpio_idx i; + + if (IS_ERR_OR_NULL(gpios)) + return; + + for (i = 0; i < UART_GPIO_MAX; i++) + if (!IS_ERR_OR_NULL(gpios->gpio[i]) && + mctrl_gpios_desc[i].dir_out) + gpiod_set_value(gpios->gpio[i], + !!(mctrl & mctrl_gpios_desc[i].mctrl)); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_set); + +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, + enum mctrl_gpio_idx gidx) +{ + if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx])) + return gpios->gpio[gidx]; + else + return NULL; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod); + +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + enum mctrl_gpio_idx i; + + /* + * return it unchanged if the structure is not allocated + */ + if (IS_ERR_OR_NULL(gpios)) + return *mctrl; + + for (i = 0; i < UART_GPIO_MAX; i++) { + if (!IS_ERR_OR_NULL(gpios->gpio[i]) && + !mctrl_gpios_desc[i].dir_out) { + if (gpiod_get_value(gpios->gpio[i])) + *mctrl |= mctrl_gpios_desc[i].mctrl; + else + *mctrl &= ~mctrl_gpios_desc[i].mctrl; + } + } + + return *mctrl; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_get); + +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +{ + struct mctrl_gpios *gpios; + enum mctrl_gpio_idx i; + int err; + + gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL); + if (!gpios) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < UART_GPIO_MAX; i++) { + gpios->gpio[i] = devm_gpiod_get_index(dev, + mctrl_gpios_desc[i].name, + idx); + + /* + * The GPIOs are maybe not all filled, + * this is not an error. + */ + if (IS_ERR_OR_NULL(gpios->gpio[i])) + continue; + + if (mctrl_gpios_desc[i].dir_out) + err = gpiod_direction_output(gpios->gpio[i], 0); + else + err = gpiod_direction_input(gpios->gpio[i]); + if (err) { + dev_dbg(dev, "Unable to set direction for %s GPIO", + mctrl_gpios_desc[i].name); + devm_gpiod_put(dev, gpios->gpio[i]); + gpios->gpio[i] = NULL; + } + } + + return gpios; +} +EXPORT_SYMBOL_GPL(mctrl_gpio_init); + +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (IS_ERR_OR_NULL(gpios)) + return; + + for (i = 0; i < UART_GPIO_MAX; i++) + if (!IS_ERR_OR_NULL(gpios->gpio[i])) + devm_gpiod_put(dev, gpios->gpio[i]); + devm_kfree(dev, gpios); +} +EXPORT_SYMBOL_GPL(mctrl_gpio_free); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h new file mode 100644 index 00000000000..400ba0494a1 --- /dev/null +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -0,0 +1,110 @@ +/* + * Helpers for controlling modem lines via GPIO + * + * Copyright (C) 2014 Paratronic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SERIAL_MCTRL_GPIO__ +#define __SERIAL_MCTRL_GPIO__ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> + +enum mctrl_gpio_idx { + UART_GPIO_CTS, + UART_GPIO_DSR, + UART_GPIO_DCD, + UART_GPIO_RNG, + UART_GPIO_RI = UART_GPIO_RNG, + UART_GPIO_RTS, + UART_GPIO_DTR, + UART_GPIO_OUT1, + UART_GPIO_OUT2, + UART_GPIO_MAX, +}; + +/* + * Opaque descriptor for modem lines controlled by GPIOs + */ +struct mctrl_gpios; + +#ifdef CONFIG_GPIOLIB + +/* + * Set state of the modem control output lines via GPIOs. + */ +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl); + +/* + * Get state of the modem control output lines from GPIOs. + * The mctrl flags are updated and returned. + */ +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl); + +/* + * Returns the associated struct gpio_desc to the modem line gidx + */ +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, + enum mctrl_gpio_idx gidx); + +/* + * Request and set direction of modem control lines GPIOs. + * devm_* functions are used, so there's no need to call mctrl_gpio_free(). + * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on + * allocation error. + */ +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx); + +/* + * Free the mctrl_gpios structure. + * Normally, this function will not be called, as the GPIOs will + * be disposed of by the resource management code. + */ +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); + +#else /* GPIOLIB */ + +static inline +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) +{ +} + +static inline +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) +{ + return *mctrl; +} + +static inline +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, + enum mctrl_gpio_idx gidx) +{ + return ERR_PTR(-ENOSYS); +} + +static inline +struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +{ + return ERR_PTR(-ENOSYS); +} + +static inline +void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) +{ +} + +#endif /* GPIOLIB */ + +#endif diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 440a962412d..ea8546092c7 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c) wait_for_xmitr(up); /* * Send the character out. - * If a LF, also do CR... */ sio_out(up, TXX9_SITFIFO, c); - if (c == 10) { - wait_for_xmitr(up); - sio_out(up, TXX9_SITFIFO, 13); - } /* * Finally, wait for transmitter to become empty @@ -702,7 +697,7 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios, TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS; if (termios->c_iflag & INPCK) up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= TXX9_SIDISR_UBRK; /* @@ -1220,8 +1215,6 @@ static void pciserial_txx9_remove_one(struct pci_dev *dev) { struct uart_txx9_port *up = pci_get_drvdata(dev); - pci_set_drvdata(dev, NULL); - if (up) { serial_txx9_unregister_port(up->port.line); pci_disable_device(dev); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 537750261aa..88236da0ddf 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -23,35 +23,35 @@ #undef DEBUG -#include <linux/module.h> +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/ctype.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> #include <linux/errno.h> -#include <linux/sh_dma.h> -#include <linux/timer.h> +#include <linux/init.h> #include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/sysrq.h> #include <linux/ioport.h> +#include <linux/major.h> +#include <linux/module.h> #include <linux/mm.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/console.h> -#include <linux/platform_device.h> -#include <linux/serial_sci.h> #include <linux/notifier.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/cpufreq.h> -#include <linux/clk.h> -#include <linux/ctype.h> -#include <linux/err.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> #include <linux/scatterlist.h> +#include <linux/serial.h> +#include <linux/serial_sci.h> +#include <linux/sh_dma.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/string.h> +#include <linux/sysrq.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #ifdef CONFIG_SUPERH #include <asm/sh_bios.h> @@ -59,11 +59,32 @@ #include "sh-sci.h" +/* Offsets into the sci_port->irqs array */ +enum { + SCIx_ERI_IRQ, + SCIx_RXI_IRQ, + SCIx_TXI_IRQ, + SCIx_BRI_IRQ, + SCIx_NR_IRQS, + + SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ +}; + +#define SCIx_IRQ_IS_MUXED(port) \ + ((port)->irqs[SCIx_ERI_IRQ] == \ + (port)->irqs[SCIx_RXI_IRQ]) || \ + ((port)->irqs[SCIx_ERI_IRQ] && \ + ((port)->irqs[SCIx_RXI_IRQ] < 0)) + struct sci_port { struct uart_port port; /* Platform configuration */ struct plat_sci_port *cfg; + int overrun_bit; + unsigned int error_mask; + unsigned int sampling_rate; + /* Break timer */ struct timer_list break_timer; @@ -74,8 +95,8 @@ struct sci_port { /* Function clock */ struct clk *fclk; + int irqs[SCIx_NR_IRQS]; char *irqstr[SCIx_NR_IRQS]; - char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; @@ -407,7 +428,7 @@ static int sci_probe_regmap(struct plat_sci_port *cfg) cfg->regtype = SCIx_HSCIF_REGTYPE; break; default: - printk(KERN_ERR "Can't probe register map for given port\n"); + pr_err("Can't probe register map for given port\n"); return -EINVAL; } @@ -421,9 +442,9 @@ static void sci_port_enable(struct sci_port *sci_port) pm_runtime_get_sync(sci_port->port.dev); - clk_enable(sci_port->iclk); + clk_prepare_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); - clk_enable(sci_port->fclk); + clk_prepare_enable(sci_port->fclk); } static void sci_port_disable(struct sci_port *sci_port) @@ -431,8 +452,16 @@ static void sci_port_disable(struct sci_port *sci_port) if (!sci_port->port.dev) return; - clk_disable(sci_port->fclk); - clk_disable(sci_port->iclk); + /* Cancel the break timer to ensure that the timer handler will not try + * to access the hardware with clocks and power disabled. Reset the + * break flag to make the break debouncing state machine ready for the + * next break. + */ + del_timer_sync(&sci_port->break_timer); + sci_port->break_flag = 0; + + clk_disable_unprepare(sci_port->fclk); + clk_disable_unprepare(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } @@ -557,7 +586,7 @@ static inline int sci_rxd_in(struct uart_port *port) return 1; /* Cast for ARM damage */ - return !!__raw_readb((void __iomem *)s->cfg->port_reg); + return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg); } /* ********************************************************************** * @@ -733,8 +762,6 @@ static void sci_break_timer(unsigned long data) { struct sci_port *port = (struct sci_port *)data; - sci_port_enable(port); - if (sci_rxd_in(&port->port) == 0) { port->break_flag = 1; sci_schedule_break_timer(port); @@ -744,8 +771,6 @@ static void sci_break_timer(unsigned long data) sci_schedule_break_timer(port); } else port->break_flag = 0; - - sci_port_disable(port); } static int sci_handle_errors(struct uart_port *port) @@ -755,19 +780,15 @@ static int sci_handle_errors(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); - /* - * Handle overruns, if supported. - */ - if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) { - if (status & (1 << s->cfg->overrun_bit)) { - port->icount.overrun++; + /* Handle overruns */ + if (status & (1 << s->overrun_bit)) { + port->icount.overrun++; - /* overrun error */ - if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) - copied++; + /* overrun error */ + if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) + copied++; - dev_notice(port->dev, "overrun error"); - } + dev_notice(port->dev, "overrun error\n"); } if (status & SCxSR_FER(port)) { @@ -809,7 +830,7 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; - dev_notice(port->dev, "parity error"); + dev_notice(port->dev, "parity error\n"); } if (copied) @@ -829,7 +850,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; - if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { + if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { serial_port_out(port, SCLSR, 0); port->icount.overrun++; @@ -890,7 +911,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) /* Disable future Rx interrupts */ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { disable_irq_nosync(irq); - scr |= 0x4000; + scr |= SCSCR_RDRQE; } else { scr &= ~SCSCR_RIE; } @@ -1020,8 +1041,7 @@ static int sci_notifier(struct notifier_block *self, sci_port = container_of(self, struct sci_port, freq_transition); - if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)) { + if (phase == CPUFREQ_POSTCHANGE) { struct uart_port *port = &sci_port->port; spin_lock_irqsave(&port->lock, flags); @@ -1075,19 +1095,19 @@ static int sci_request_irq(struct sci_port *port) for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { struct sci_irq_desc *desc; - unsigned int irq; + int irq; if (SCIx_IRQ_IS_MUXED(port)) { i = SCIx_MUX_IRQ; irq = up->irq; } else { - irq = port->cfg->irqs[i]; + irq = port->irqs[i]; /* * Certain port types won't support all of the * available interrupt sources. */ - if (unlikely(!irq)) + if (unlikely(irq < 0)) continue; } @@ -1112,7 +1132,7 @@ static int sci_request_irq(struct sci_port *port) out_noirq: while (--i >= 0) - free_irq(port->cfg->irqs[i], port); + free_irq(port->irqs[i], port); out_nomem: while (--j >= 0) @@ -1130,16 +1150,16 @@ static void sci_free_irq(struct sci_port *port) * IRQ first. */ for (i = 0; i < SCIx_NR_IRQS; i++) { - unsigned int irq = port->cfg->irqs[i]; + int irq = port->irqs[i]; /* * Certain port types won't support all of the available * interrupt sources. */ - if (unlikely(!irq)) + if (unlikely(irq < 0)) continue; - free_irq(port->cfg->irqs[i], port); + free_irq(port->irqs[i], port); kfree(port->irqstr[i]); if (SCIx_IRQ_IS_MUXED(port)) { @@ -1149,67 +1169,6 @@ static void sci_free_irq(struct sci_port *port) } } -static const char *sci_gpio_names[SCIx_NR_FNS] = { - "sck", "rxd", "txd", "cts", "rts", -}; - -static const char *sci_gpio_str(unsigned int index) -{ - return sci_gpio_names[index]; -} - -static void sci_init_gpios(struct sci_port *port) -{ - struct uart_port *up = &port->port; - int i; - - if (!port->cfg) - return; - - for (i = 0; i < SCIx_NR_FNS; i++) { - const char *desc; - int ret; - - if (!port->cfg->gpios[i]) - continue; - - desc = sci_gpio_str(i); - - port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s", - dev_name(up->dev), desc); - - /* - * If we've failed the allocation, we can still continue - * on with a NULL string. - */ - if (!port->gpiostr[i]) - dev_notice(up->dev, "%s string allocation failure\n", - desc); - - ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]); - if (unlikely(ret != 0)) { - dev_notice(up->dev, "failed %s gpio request\n", desc); - - /* - * If we can't get the GPIO for whatever reason, - * no point in keeping the verbose string around. - */ - kfree(port->gpiostr[i]); - } - } -} - -static void sci_free_gpios(struct sci_port *port) -{ - int i; - - for (i = 0; i < SCIx_NR_FNS; i++) - if (port->cfg->gpios[i]) { - gpio_free(port->cfg->gpios[i]); - kfree(port->gpiostr[i]); - } -} - static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = serial_port_in(port, SCxSR); @@ -1240,7 +1199,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1); + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) | + SCFCR_LOOP); } } @@ -1309,7 +1270,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count) } if (room < count) - dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", count - room); if (!room) return room; @@ -1330,7 +1291,8 @@ static void sci_dma_rx_complete(void *arg) unsigned long flags; int count; - dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); + dev_dbg(port->dev, "%s(%d) active #%d\n", + __func__, port->line, s->active_rx); spin_lock_irqsave(&port->lock, flags); @@ -1406,8 +1368,8 @@ static void sci_submit_rx(struct sci_port *s) sci_rx_dma_release(s, true); return; } - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, - s->cookie_rx[i], i); + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", + __func__, s->cookie_rx[i], i); } s->active_rx = s->cookie_rx[0]; @@ -1433,7 +1395,7 @@ static void work_fn_rx(struct work_struct *work) desc = s->desc_rx[new]; if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != - DMA_SUCCESS) { + DMA_COMPLETE) { /* Handle incomplete DMA receive */ struct dma_chan *chan = s->chan_rx; struct shdma_desc *sh_desc = container_of(desc, @@ -1442,7 +1404,7 @@ static void work_fn_rx(struct work_struct *work) int count; chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); - dev_dbg(port->dev, "Read %u bytes with cookie %d\n", + dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); spin_lock_irqsave(&port->lock, flags); @@ -1466,8 +1428,8 @@ static void work_fn_rx(struct work_struct *work) s->active_rx = s->cookie_rx[!new]; - dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, - s->cookie_rx[new], new, s->active_rx); + dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", + __func__, s->cookie_rx[new], new, s->active_rx); } static void work_fn_tx(struct work_struct *work) @@ -1520,8 +1482,8 @@ static void work_fn_tx(struct work_struct *work) return; } - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, - xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); dma_async_issue_pending(chan); } @@ -1536,9 +1498,9 @@ static void sci_start_tx(struct uart_port *port) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { u16 new, scr = serial_port_in(port, SCSCR); if (s->chan_tx) - new = scr | 0x8000; + new = scr | SCSCR_TDRQE; else - new = scr & ~0x8000; + new = scr & ~SCSCR_TDRQE; if (new != scr) serial_port_out(port, SCSCR, new); } @@ -1565,7 +1527,7 @@ static void sci_stop_tx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x8000; + ctrl &= ~SCSCR_TDRQE; ctrl &= ~SCSCR_TIE; @@ -1579,7 +1541,7 @@ static void sci_start_rx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; + ctrl &= ~SCSCR_RDRQE; serial_port_out(port, SCSCR, ctrl); } @@ -1591,7 +1553,7 @@ static void sci_stop_rx(struct uart_port *port) ctrl = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; + ctrl &= ~SCSCR_RDRQE; ctrl &= ~port_rx_irq_mask(port); @@ -1640,8 +1602,8 @@ static bool filter(struct dma_chan *chan, void *slave) { struct sh_dmae_slave *param = slave; - dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, - param->shdma_slave.slave_id); + dev_dbg(chan->device->dev, "%s: slave ID %d\n", + __func__, param->shdma_slave.slave_id); chan->private = ¶m->shdma_slave; return true; @@ -1654,8 +1616,8 @@ static void rx_timer_fn(unsigned long arg) u16 scr = serial_port_in(port, SCSCR); if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~0x4000; - enable_irq(s->cfg->irqs[1]); + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); } serial_port_out(port, SCSCR, scr | SCSCR_RIE); dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1670,8 +1632,7 @@ static void sci_request_dma(struct uart_port *port) dma_cap_mask_t mask; int nent; - dev_dbg(port->dev, "%s: port %d\n", __func__, - port->line); + dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) return; @@ -1691,16 +1652,18 @@ static void sci_request_dma(struct uart_port *port) s->chan_tx = chan; sg_init_table(&s->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK); sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); + UART_XMIT_SIZE, + (uintptr_t)port->state->xmit.buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); if (!nent) sci_tx_dma_release(s, false); else - dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, - sg_dma_len(&s->sg_tx), - port->state->xmit.buf, sg_dma_address(&s->sg_tx)); + dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", + __func__, + sg_dma_len(&s->sg_tx), port->state->xmit.buf, + &sg_dma_address(&s->sg_tx)); s->sg_len_tx = nent; @@ -1740,7 +1703,7 @@ static void sci_request_dma(struct uart_port *port) sg_init_table(sg, 1); sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, - (int)buf[i] & ~PAGE_MASK); + (uintptr_t)buf[i] & ~PAGE_MASK); sg_dma_address(sg) = dma[i]; } @@ -1808,21 +1771,11 @@ static void sci_shutdown(struct uart_port *port) sci_free_irq(s); } -static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, +static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned long freq) { - switch (algo_id) { - case SCBRR_ALGO_1: - return ((freq + 16 * bps) / (16 * bps) - 1); - case SCBRR_ALGO_2: - return ((freq + 16 * bps) / (32 * bps) - 1); - case SCBRR_ALGO_3: - return (((freq * 2) + 16 * bps) / (16 * bps) - 1); - case SCBRR_ALGO_4: - return (((freq * 2) + 16 * bps) / (32 * bps) - 1); - case SCBRR_ALGO_5: - return (((freq * 1000 / 32) / bps) - 1); - } + if (s->sampling_rate) + return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; /* Warn, but use a safe default */ WARN_ON(1); @@ -1903,12 +1856,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, max_baud); if (likely(baud && port->uartclk)) { - if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) { + if (s->cfg->type == PORT_HSCIF) { sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, &cks); } else { - t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, - port->uartclk); + t = sci_scbrr_calc(s, baud, port->uartclk); for (cks = 0; t >= 256 && cks <= 3; cks++) t >>= 2; } @@ -1921,13 +1873,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, smr_val = serial_port_in(port, SCSMR) & 3; if ((termios->c_cflag & CSIZE) == CS7) - smr_val |= 0x40; + smr_val |= SCSMR_CHR; if (termios->c_cflag & PARENB) - smr_val |= 0x20; + smr_val |= SCSMR_PE; if (termios->c_cflag & PARODD) - smr_val |= 0x30; + smr_val |= SCSMR_PE | SCSMR_ODD; if (termios->c_cflag & CSTOPB) - smr_val |= 0x08; + smr_val |= SCSMR_STOP; uart_update_timeout(port, termios->c_cflag, baud); @@ -1935,7 +1887,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, __func__, smr_val, cks, t, s->cfg->scscr); if (t >= 0) { - serial_port_out(port, SCSMR, (smr_val & ~3) | cks); + serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks); serial_port_out(port, SCBRR, t); reg = sci_getreg(port, HSSRR); if (reg->size) @@ -1983,8 +1935,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, if (s->chan_rx) { s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / port->fifosize / 2; - dev_dbg(port->dev, - "DMA Rx t-out %ums, tty t-out %u jiffies\n", + dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", s->rx_timeout * 1000 / HZ, port->timeout); if (s->rx_timeout < msecs_to_jiffies(20)) s->rx_timeout = msecs_to_jiffies(20); @@ -2003,7 +1954,7 @@ static void sci_pm(struct uart_port *port, unsigned int state, struct sci_port *sci_port = to_sci_port(port); switch (state) { - case 3: + case UART_PM_STATE_OFF: sci_port_disable(sci_port); break; default: @@ -2068,7 +2019,7 @@ static int sci_remap_port(struct uart_port *port) * need to do any remapping, just cast the cookie * directly. */ - port->membase = (void __iomem *)port->mapbase; + port->membase = (void __iomem *)(uintptr_t)port->mapbase; } return 0; @@ -2115,10 +2066,6 @@ static void sci_config_port(struct uart_port *port, int flags) static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct sci_port *s = to_sci_port(port); - - if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) - return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ return -EINVAL; @@ -2151,11 +2098,13 @@ static struct uart_ops sci_uart_ops = { }; static int sci_init_single(struct platform_device *dev, - struct sci_port *sci_port, - unsigned int index, - struct plat_sci_port *p) + struct sci_port *sci_port, unsigned int index, + struct plat_sci_port *p, bool early) { struct uart_port *port = &sci_port->port; + const struct resource *res; + unsigned int sampling_rate; + unsigned int i; int ret; sci_port->cfg = p; @@ -2164,31 +2113,76 @@ static int sci_init_single(struct platform_device *dev, port->iotype = UPIO_MEM; port->line = index; + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENOMEM; + + port->mapbase = res->start; + + for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) + sci_port->irqs[i] = platform_get_irq(dev, i); + + /* The SCI generates several interrupts. They can be muxed together or + * connected to different interrupt lines. In the muxed case only one + * interrupt resource is specified. In the non-muxed case three or four + * interrupt resources are specified, as the BRI interrupt is optional. + */ + if (sci_port->irqs[0] < 0) + return -ENXIO; + + if (sci_port->irqs[1] < 0) { + sci_port->irqs[1] = sci_port->irqs[0]; + sci_port->irqs[2] = sci_port->irqs[0]; + sci_port->irqs[3] = sci_port->irqs[0]; + } + + if (p->regtype == SCIx_PROBE_REGTYPE) { + ret = sci_probe_regmap(p); + if (unlikely(ret)) + return ret; + } + switch (p->type) { case PORT_SCIFB: port->fifosize = 256; + sci_port->overrun_bit = 9; + sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; + sampling_rate = 0; + sci_port->overrun_bit = 0; break; case PORT_SCIFA: port->fifosize = 64; + sci_port->overrun_bit = 9; + sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; + if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { + sci_port->overrun_bit = 9; + sampling_rate = 16; + } else { + sci_port->overrun_bit = 0; + sampling_rate = 32; + } break; default: port->fifosize = 1; + sci_port->overrun_bit = 5; + sampling_rate = 32; break; } - if (p->regtype == SCIx_PROBE_REGTYPE) { - ret = sci_probe_regmap(p); - if (unlikely(ret)) - return ret; - } + /* SCIFA on sh7723 and sh7724 need a custom sampling rate that doesn't + * match the SoC datasheet, this should be investigated. Let platform + * data override the sampling rate for now. + */ + sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate + : sampling_rate; - if (dev) { + if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); @@ -2208,8 +2202,6 @@ static int sci_init_single(struct platform_device *dev, port->dev = &dev->dev; - sci_init_gpios(sci_port); - pm_runtime_enable(&dev->dev); } @@ -2220,32 +2212,22 @@ static int sci_init_single(struct platform_device *dev, /* * Establish some sensible defaults for the error detection. */ - if (!p->error_mask) - p->error_mask = (p->type == PORT_SCI) ? + sci_port->error_mask = (p->type == PORT_SCI) ? SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* * Establish sensible defaults for the overrun detection, unless * the part has explicitly disabled support for it. */ - if (p->overrun_bit != SCIx_NOT_SUPPORTED) { - if (p->type == PORT_SCI) - p->overrun_bit = 5; - else if (p->scbrr_algo_id == SCBRR_ALGO_4) - p->overrun_bit = 9; - else - p->overrun_bit = 0; - /* - * Make the error mask inclusive of overrun detection, if - * supported. - */ - p->error_mask |= (1 << p->overrun_bit); - } + /* + * Make the error mask inclusive of overrun detection, if + * supported. + */ + sci_port->error_mask |= 1 << sci_port->overrun_bit; - port->mapbase = p->mapbase; port->type = p->type; - port->flags = p->flags; + port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; /* @@ -2255,7 +2237,7 @@ static int sci_init_single(struct platform_device *dev, * * For the muxed case there's nothing more to do. */ - port->irq = p->irqs[SCIx_RXI_IRQ]; + port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; port->serial_in = sci_serial_in; @@ -2270,8 +2252,6 @@ static int sci_init_single(struct platform_device *dev, static void sci_cleanup_single(struct sci_port *port) { - sci_free_gpios(port); - clk_put(port->iclk); clk_put(port->fclk); @@ -2387,7 +2367,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev) early_serial_console.index = pdev->id; - sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); + sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); serial_console_setup(&early_serial_console, early_serial_buf); @@ -2410,8 +2390,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev) #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -static char banner[] __initdata = - KERN_INFO "SuperH (H)SCI(F) driver initialized\n"; +static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized"; static struct uart_driver sci_uart_driver = { .owner = THIS_MODULE, @@ -2437,6 +2416,83 @@ static int sci_remove(struct platform_device *dev) return 0; } +struct sci_port_info { + unsigned int type; + unsigned int regtype; +}; + +static const struct of_device_id of_sci_match[] = { + { + .compatible = "renesas,scif", + .data = &(const struct sci_port_info) { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_REGTYPE, + }, + }, { + .compatible = "renesas,scifa", + .data = &(const struct sci_port_info) { + .type = PORT_SCIFA, + .regtype = SCIx_SCIFA_REGTYPE, + }, + }, { + .compatible = "renesas,scifb", + .data = &(const struct sci_port_info) { + .type = PORT_SCIFB, + .regtype = SCIx_SCIFB_REGTYPE, + }, + }, { + .compatible = "renesas,hscif", + .data = &(const struct sci_port_info) { + .type = PORT_HSCIF, + .regtype = SCIx_HSCIF_REGTYPE, + }, + }, { + /* Terminator */ + }, +}; +MODULE_DEVICE_TABLE(of, of_sci_match); + +static struct plat_sci_port * +sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct sci_port_info *info; + struct plat_sci_port *p; + int id; + + if (!IS_ENABLED(CONFIG_OF) || !np) + return NULL; + + match = of_match_node(of_sci_match, pdev->dev.of_node); + if (!match) + return NULL; + + info = match->data; + + p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); + if (!p) { + dev_err(&pdev->dev, "failed to allocate DT config data\n"); + return NULL; + } + + /* Get the line number for the aliases node. */ + id = of_alias_get_id(np, "serial"); + if (id < 0) { + dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); + return NULL; + } + + *dev_id = id; + + p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + p->type = info->type; + p->regtype = info->regtype; + p->scscr = SCSCR_RE | SCSCR_TE; + + return p; +} + static int sci_probe_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p, @@ -2446,15 +2502,13 @@ static int sci_probe_single(struct platform_device *dev, /* Sanity check */ if (unlikely(index >= SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", + dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n", index+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); return -EINVAL; } - ret = sci_init_single(dev, sciport, index, p); + ret = sci_init_single(dev, sciport, index, p, false); if (ret) return ret; @@ -2469,8 +2523,9 @@ static int sci_probe_single(struct platform_device *dev, static int sci_probe(struct platform_device *dev) { - struct plat_sci_port *p = dev_get_platdata(&dev->dev); - struct sci_port *sp = &sci_ports[dev->id]; + struct plat_sci_port *p; + struct sci_port *sp; + unsigned int dev_id; int ret; /* @@ -2481,9 +2536,24 @@ static int sci_probe(struct platform_device *dev) if (is_early_platform_device(dev)) return sci_probe_earlyprintk(dev); + if (dev->dev.of_node) { + p = sci_parse_dt(dev, &dev_id); + if (p == NULL) + return -EINVAL; + } else { + p = dev->dev.platform_data; + if (p == NULL) { + dev_err(&dev->dev, "no platform data supplied\n"); + return -EINVAL; + } + + dev_id = dev->id; + } + + sp = &sci_ports[dev_id]; platform_set_drvdata(dev, sp); - ret = sci_probe_single(dev, dev->id, p, sp); + ret = sci_probe_single(dev, dev_id, p, sp); if (ret) return ret; @@ -2492,6 +2562,7 @@ static int sci_probe(struct platform_device *dev) ret = cpufreq_register_notifier(&sp->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); if (unlikely(ret < 0)) { + uart_remove_one_port(&sci_uart_driver, &sp->port); sci_cleanup_single(sp); return ret; } @@ -2535,6 +2606,7 @@ static struct platform_driver sci_driver = { .name = "sh-sci", .owner = THIS_MODULE, .pm = &sci_dev_pm_ops, + .of_match_table = of_match_ptr(of_sci_match), }, }; @@ -2542,7 +2614,7 @@ static int __init sci_init(void) { int ret; - printk(banner); + pr_info("%s\n", banner); ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 5aca7364634..d5db81a0a43 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -9,7 +9,7 @@ #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) -#define SCxSR_ERRORS(port) (to_sci_port(port)->cfg->error_mask) +#define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask) #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 61c1ad03db5..9b4d71cff00 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -24,7 +24,6 @@ #include <linux/dmaengine.h> #include <linux/dma-direction.h> #include <linux/dma-mapping.h> -#include <linux/sirfsoc_dma.h> #include <asm/irq.h> #include <asm/mach/irq.h> @@ -173,7 +172,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { + if (sirfport->tx_dma_chan) { if (sirfport->tx_dma_state == TX_DMA_RUNNING) { dmaengine_pause(sirfport->tx_dma_chan); sirfport->tx_dma_state = TX_DMA_PAUSE; @@ -288,7 +287,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { sirfsoc_uart_pio_tx_chars(sirfport, 1); @@ -310,7 +309,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port) struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { + if (sirfport->rx_dma_chan) { if (!sirfport->is_marco) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & @@ -359,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id) { struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id; struct uart_port *port = &sirfport->port; + spin_lock(&port->lock); if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled) uart_handle_cts_change(port, !gpio_get_value(sirfport->cts_gpio)); + spin_unlock(&port->lock); return IRQ_HANDLED; } @@ -429,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) sirfport->rx_io_count += rx_count; port->icount.rx += rx_count; - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); - return rx_count; } @@ -466,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param) struct circ_buf *xmit = &port->state->xmit; unsigned long flags; + spin_lock_irqsave(&port->lock, flags); xmit->tail = (xmit->tail + sirfport->transfer_size) & (UART_XMIT_SIZE - 1); port->icount.tx += sirfport->transfer_size; @@ -474,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param) if (sirfport->tx_dma_addr) dma_unmap_single(port->dev, sirfport->tx_dma_addr, sirfport->transfer_size, DMA_TO_DEVICE); - spin_lock_irqsave(&sirfport->tx_lock, flags); sirfport->tx_dma_state = TX_DMA_IDLE; sirfsoc_uart_tx_with_dma(sirfport); - spin_unlock_irqrestore(&sirfport->tx_lock, flags); + spin_unlock_irqrestore(&port->lock, flags); } static void sirfsoc_uart_insert_rx_buf_to_tty( @@ -490,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty( inserted = tty_insert_flip_string(tport, sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count); port->icount.rx += inserted; - tty_flip_buffer_push(tport); } static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index) @@ -524,12 +520,14 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; unsigned int count; unsigned long flags; + struct dma_tx_state tx_state; - spin_lock_irqsave(&sirfport->rx_lock, flags); - while (sirfport->rx_completed != sirfport->rx_issued) { + spin_lock_irqsave(&port->lock, flags); + while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, + sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { sirfsoc_uart_insert_rx_buf_to_tty(sirfport, SIRFSOC_RX_DMA_BUF_SIZE); - sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); + sirfport->rx_completed++; sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; } count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head, @@ -541,9 +539,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); - spin_unlock_irqrestore(&sirfport->rx_lock, flags); if (sirfport->rx_io_count == 4) { - spin_lock_irqsave(&sirfport->rx_lock, flags); sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_int_st_reg, uint_st->sirfsoc_rx_done); @@ -554,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) else wr_regl(port, SIRFUART_INT_EN_CLR, uint_en->sirfsoc_rx_done_en); - spin_unlock_irqrestore(&sirfport->rx_lock, flags); - sirfsoc_uart_start_next_rx_dma(port); } else { - spin_lock_irqsave(&sirfport->rx_lock, flags); wr_regl(port, ureg->sirfsoc_int_st_reg, uint_st->sirfsoc_rx_done); if (!sirfport->is_marco) @@ -568,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) else wr_regl(port, ureg->sirfsoc_int_en_reg, uint_en->sirfsoc_rx_done_en); - spin_unlock_irqrestore(&sirfport->rx_lock, flags); } + spin_unlock_irqrestore(&port->lock, flags); + tty_flip_buffer_push(&port->state->port); } static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) @@ -578,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; struct dma_tx_state tx_state; - spin_lock(&sirfport->rx_lock); - dmaengine_tx_status(sirfport->rx_dma_chan, sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state); dmaengine_terminate_all(sirfport->rx_dma_chan); @@ -592,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) else wr_regl(port, SIRFUART_INT_EN_CLR, uint_en->sirfsoc_rx_timeout_en); - spin_unlock(&sirfport->rx_lock); tasklet_schedule(&sirfport->rx_tmo_process_tasklet); } @@ -656,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) intr_status &= port->read_status_mask; uart_insert_char(port, intr_status, uint_en->sirfsoc_rx_oflow_en, 0, flag); - tty_flip_buffer_push(&state->port); } recv_char: if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) && @@ -671,7 +661,7 @@ recv_char: uart_handle_cts_change(port, cts_status); wake_up_interruptible(&state->port.delta_msr_wait); } - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { + if (sirfport->rx_dma_chan) { if (intr_status & uint_st->sirfsoc_rx_timeout) sirfsoc_uart_handle_rx_tmo(sirfport); if (intr_status & uint_st->sirfsoc_rx_done) @@ -681,8 +671,11 @@ recv_char: sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT); } + spin_unlock(&port->lock); + tty_flip_buffer_push(&state->port); + spin_lock(&port->lock); if (intr_status & uint_st->sirfsoc_txfifo_empty) { - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { @@ -699,6 +692,7 @@ recv_char: } } spin_unlock(&port->lock); + return IRQ_HANDLED; } @@ -706,25 +700,37 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param) { struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; struct uart_port *port = &sirfport->port; + struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; unsigned long flags; - spin_lock_irqsave(&sirfport->rx_lock, flags); - while (sirfport->rx_completed != sirfport->rx_issued) { + struct dma_tx_state tx_state; + spin_lock_irqsave(&port->lock, flags); + while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, + sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { sirfsoc_uart_insert_rx_buf_to_tty(sirfport, SIRFSOC_RX_DMA_BUF_SIZE); - sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); + if (rd_regl(port, ureg->sirfsoc_int_en_reg) & + uint_en->sirfsoc_rx_timeout_en) + sirfsoc_rx_submit_one_dma_desc(port, + sirfport->rx_completed++); + else + sirfport->rx_completed++; sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; } - spin_unlock_irqrestore(&sirfport->rx_lock, flags); + spin_unlock_irqrestore(&port->lock, flags); + tty_flip_buffer_push(&port->state->port); } static void sirfsoc_uart_rx_dma_complete_callback(void *param) { struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - spin_lock(&sirfport->rx_lock); + unsigned long flags; + + spin_lock_irqsave(&sirfport->port.lock, flags); sirfport->rx_issued++; sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT; - spin_unlock(&sirfport->rx_lock); tasklet_schedule(&sirfport->rx_dma_complete_tasklet); + spin_unlock_irqrestore(&sirfport->port.lock, flags); } /* submit rx dma task into dmaengine */ @@ -733,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - unsigned long flags; int i; - spin_lock_irqsave(&sirfport->rx_lock, flags); sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); - spin_unlock_irqrestore(&sirfport->rx_lock, flags); for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) sirfsoc_rx_submit_one_dma_desc(port, i); sirfport->rx_completed = sirfport->rx_issued = 0; - spin_lock_irqsave(&sirfport->rx_lock, flags); if (!sirfport->is_marco) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | @@ -752,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) else wr_regl(port, ureg->sirfsoc_int_en_reg, SIRFUART_RX_DMA_INT_EN(port, uint_en)); - spin_unlock_irqrestore(&sirfport->rx_lock, flags); } static void sirfsoc_uart_start_rx(struct uart_port *port) @@ -765,7 +766,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) + if (sirfport->rx_dma_chan) sirfsoc_uart_start_next_rx_dma(port); else { if (!sirfport->is_marco) @@ -895,7 +896,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, if (termios->c_iflag & INPCK) port->read_status_mask |= uint_en->sirfsoc_frm_err_en; } - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { if (termios->c_iflag & IGNPAR) @@ -1001,11 +1002,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) << SIRFSOC_USP_ASYNC_DIV2_OFFSET); } - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) + if (sirfport->tx_dma_chan) wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE); else wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) + if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE); else wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); @@ -1026,91 +1027,14 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, spin_unlock_irqrestore(&port->lock, flags); } -static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port) +static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - dma_cap_mask_t dma_mask; - struct dma_slave_config tx_slv_cfg = { - .dst_maxburst = 2, - }; - - dma_cap_zero(dma_mask); - dma_cap_set(DMA_SLAVE, dma_mask); - sirfport->tx_dma_chan = dma_request_channel(dma_mask, - (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)sirfport->tx_dma_no); - if (!sirfport->tx_dma_chan) { - dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", - sirfport->tx_dma_no); - return -EPROBE_DEFER; - } - dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); - - return 0; -} - -static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - dma_cap_mask_t dma_mask; - int ret; - int i, j; - struct dma_slave_config slv_cfg = { - .src_maxburst = 2, - }; - - dma_cap_zero(dma_mask); - dma_cap_set(DMA_SLAVE, dma_mask); - sirfport->rx_dma_chan = dma_request_channel(dma_mask, - (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)sirfport->rx_dma_no); - if (!sirfport->rx_dma_chan) { - dev_err(port->dev, "Uart Request Dma Channel Fail %d\n", - sirfport->rx_dma_no); - ret = -EPROBE_DEFER; - goto request_err; - } - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { - sirfport->rx_dma_items[i].xmit.buf = - dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); - if (!sirfport->rx_dma_items[i].xmit.buf) { - dev_err(port->dev, "Uart alloc bufa failed\n"); - ret = -ENOMEM; - goto alloc_coherent_err; - } - sirfport->rx_dma_items[i].xmit.head = - sirfport->rx_dma_items[i].xmit.tail = 0; - } - dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); - - return 0; -alloc_coherent_err: - for (j = 0; j < i; j++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[j].xmit.buf, - sirfport->rx_dma_items[j].dma_addr); - dma_release_channel(sirfport->rx_dma_chan); -request_err: - return ret; -} - -static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport) -{ - dmaengine_terminate_all(sirfport->tx_dma_chan); - dma_release_channel(sirfport->tx_dma_chan); -} - -static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport) -{ - int i; - struct uart_port *port = &sirfport->port; - dmaengine_terminate_all(sirfport->rx_dma_chan); - dma_release_channel(sirfport->rx_dma_chan); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[i].xmit.buf, - sirfport->rx_dma_items[i].dma_addr); + if (!state) + clk_prepare_enable(sirfport->clk); + else + clk_disable_unprepare(sirfport->clk); } static int sirfsoc_uart_startup(struct uart_port *port) @@ -1151,18 +1075,12 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port)); wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); - - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) { - ret = sirfsoc_uart_init_rx_dma(port); - if (ret) - goto init_rx_err; + if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, - SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | - SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | - SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); - } - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { - sirfsoc_uart_init_tx_dma(port); + SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | + SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | + SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); + if (sirfport->tx_dma_chan) { sirfport->tx_dma_state = TX_DMA_IDLE; wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk, SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) | @@ -1209,12 +1127,8 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) gpio_set_value(sirfport->rts_gpio, 1); free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport); } - if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) - sirfsoc_uart_uninit_rx_dma(sirfport); - if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) { - sirfsoc_uart_uninit_tx_dma(sirfport); + if (sirfport->tx_dma_chan) sirfport->tx_dma_state = TX_DMA_IDLE; - } } static const char *sirfsoc_uart_type(struct uart_port *port) @@ -1257,6 +1171,7 @@ static struct uart_ops sirfsoc_uart_ops = { .startup = sirfsoc_uart_startup, .shutdown = sirfsoc_uart_shutdown, .set_termios = sirfsoc_uart_set_termios, + .pm = sirfsoc_uart_pm, .type = sirfsoc_uart_type, .release_port = sirfsoc_uart_release_port, .request_port = sirfsoc_uart_request_port, @@ -1289,8 +1204,8 @@ sirfsoc_uart_console_setup(struct console *co, char *options) port->cons = co; /* default console tx/rx transfer using io mode */ - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - sirfport->tx_dma_no = UNVALID_DMA_CHAN; + sirfport->rx_dma_chan = NULL; + sirfport->tx_dma_chan = NULL; return uart_set_options(port, co, baud, parity, bits, flow); } @@ -1302,7 +1217,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line)) cpu_relax(); - wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch); + wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); } static void sirfsoc_uart_console_write(struct console *co, const char *s, @@ -1358,6 +1273,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) struct uart_port *port; struct resource *res; int ret; + int i, j; + struct dma_slave_config slv_cfg = { + .src_maxburst = 2, + }; + struct dma_slave_config tx_slv_cfg = { + .dst_maxburst = 2, + }; const struct of_device_id *match; match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); @@ -1378,27 +1300,10 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node, "sirf,uart-has-rtscts"); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) { + if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,uart-dma-rx-channel", - &sirfport->rx_dma_no)) - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,uart-dma-tx-channel", - &sirfport->tx_dma_no)) - sirfport->tx_dma_no = UNVALID_DMA_CHAN; - } if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) { sirfport->uart_reg->uart_type = SIRF_USP_UART; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,usp-dma-rx-channel", - &sirfport->rx_dma_no)) - sirfport->rx_dma_no = UNVALID_DMA_CHAN; - if (of_property_read_u32(pdev->dev.of_node, - "sirf,usp-dma-tx-channel", - &sirfport->tx_dma_no)) - sirfport->tx_dma_no = UNVALID_DMA_CHAN; if (!sirfport->hw_flow_ctrl) goto usp_no_flow_control; if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL)) @@ -1453,8 +1358,6 @@ usp_no_flow_control: ret = -EFAULT; goto err; } - spin_lock_init(&sirfport->rx_lock); - spin_lock_init(&sirfport->tx_lock); tasklet_init(&sirfport->rx_dma_complete_tasklet, sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport); tasklet_init(&sirfport->rx_tmo_process_tasklet, @@ -1479,7 +1382,6 @@ usp_no_flow_control: ret = PTR_ERR(sirfport->clk); goto err; } - clk_prepare_enable(sirfport->clk); port->uartclk = clk_get_rate(sirfport->clk); port->ops = &sirfsoc_uart_ops; @@ -1492,10 +1394,33 @@ usp_no_flow_control: goto port_err; } - return 0; + sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); + for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { + sirfport->rx_dma_items[i].xmit.buf = + dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); + if (!sirfport->rx_dma_items[i].xmit.buf) { + dev_err(port->dev, "Uart alloc bufa failed\n"); + ret = -ENOMEM; + goto alloc_coherent_err; + } + sirfport->rx_dma_items[i].xmit.head = + sirfport->rx_dma_items[i].xmit.tail = 0; + } + if (sirfport->rx_dma_chan) + dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); + sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); + if (sirfport->tx_dma_chan) + dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); + return 0; +alloc_coherent_err: + for (j = 0; j < i; j++) + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items[j].xmit.buf, + sirfport->rx_dma_items[j].dma_addr); + dma_release_channel(sirfport->rx_dma_chan); port_err: - clk_disable_unprepare(sirfport->clk); clk_put(sirfport->clk); err: return ret; @@ -1505,38 +1430,55 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) { struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); struct uart_port *port = &sirfport->port; - clk_disable_unprepare(sirfport->clk); clk_put(sirfport->clk); uart_remove_one_port(&sirfsoc_uart_drv, port); + if (sirfport->rx_dma_chan) { + int i; + dmaengine_terminate_all(sirfport->rx_dma_chan); + dma_release_channel(sirfport->rx_dma_chan); + for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items[i].xmit.buf, + sirfport->rx_dma_items[i].dma_addr); + } + if (sirfport->tx_dma_chan) { + dmaengine_terminate_all(sirfport->tx_dma_chan); + dma_release_channel(sirfport->tx_dma_chan); + } return 0; } +#ifdef CONFIG_PM_SLEEP static int -sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state) +sirfsoc_uart_suspend(struct device *pdev) { - struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); + struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev); struct uart_port *port = &sirfport->port; uart_suspend_port(&sirfsoc_uart_drv, port); return 0; } -static int sirfsoc_uart_resume(struct platform_device *pdev) +static int sirfsoc_uart_resume(struct device *pdev) { - struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev); + struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev); struct uart_port *port = &sirfport->port; uart_resume_port(&sirfsoc_uart_drv, port); return 0; } +#endif + +static const struct dev_pm_ops sirfsoc_uart_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume) +}; static struct platform_driver sirfsoc_uart_driver = { .probe = sirfsoc_uart_probe, .remove = sirfsoc_uart_remove, - .suspend = sirfsoc_uart_suspend, - .resume = sirfsoc_uart_resume, .driver = { .name = SIRFUART_PORT_NAME, .owner = THIS_MODULE, .of_match_table = sirfsoc_uart_ids, + .pm = &sirfsoc_uart_pm_ops, }, }; diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index fb8d0a00260..69a62ebd3af 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -368,15 +368,6 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_UART_NR 6 #define SIRFSOC_PORT_TYPE 0xa5 -/* Baud Rate Calculation */ -#define SIRF_MIN_SAMPLE_DIV 0xf -#define SIRF_MAX_SAMPLE_DIV 0x3f -#define SIRF_IOCLK_DIV_MAX 0xffff -#define SIRF_SAMPLE_DIV_SHIFT 16 -#define SIRF_IOCLK_DIV_MASK 0xffff -#define SIRF_SAMPLE_DIV_MASK 0x3f0000 -#define SIRF_BAUD_RATE_SUPPORT_NR 18 - /* Uart Common Use Macro*/ #define SIRFSOC_RX_DMA_BUF_SIZE 256 #define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) @@ -401,9 +392,6 @@ struct sirfsoc_uart_register sirfsoc_uart = { /* Indicate how many buffers used */ #define SIRFSOC_RX_LOOP_BUF_CNT 2 -/* Indicate if DMA channel valid */ -#define IS_DMA_CHAN_VALID(x) ((x) != -1) -#define UNVALID_DMA_CHAN -1 /* For Fast Baud Rate Calculation */ struct sirfsoc_baudrate_to_regv { unsigned int baud_rate; @@ -432,14 +420,10 @@ struct sirfsoc_uart_port { /* for SiRFmarco, there are SET/CLR for UART_INT_EN */ bool is_marco; struct sirfsoc_uart_register *uart_reg; - int rx_dma_no; - int tx_dma_no; struct dma_chan *rx_dma_chan; struct dma_chan *tx_dma_chan; dma_addr_t tx_dma_addr; struct dma_async_tx_descriptor *tx_dma_desc; - spinlock_t rx_lock; - spinlock_t tx_lock; struct tasklet_struct rx_dma_complete_tasklet; struct tasklet_struct rx_tmo_process_tasklet; unsigned int rx_io_count; @@ -453,14 +437,9 @@ struct sirfsoc_uart_port { int rx_issued; }; -/* Hardware Flow Control */ -#define SIRFUART_AFC_CTRL_RX_THD 0x70 - /* Register Access Control */ #define portaddr(port, reg) ((port)->membase + (reg)) -#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) -#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) /* UART Port Mask */ diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 21e6e84c0df..f48b1cc07ee 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port) return asc_in(port, ASC_STA) & ASC_STA_TE; } -static inline int asc_txfifo_is_full(struct uart_port *port) +static inline u32 asc_txfifo_is_half_empty(struct uart_port *port) { - return asc_in(port, ASC_STA) & ASC_STA_TF; + return asc_in(port, ASC_STA) & ASC_STA_THE; } static inline const char *asc_port_name(struct uart_port *port) @@ -295,7 +295,7 @@ static void asc_receive_chars(struct uart_port *port) status & ASC_STA_OE) { if (c & ASC_RXBUF_FE) { - if (c == ASC_RXBUF_FE) { + if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) { port->icount.brk++; if (uart_handle_break(port)) continue; @@ -325,7 +325,7 @@ static void asc_receive_chars(struct uart_port *port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, c)) + if (uart_handle_sysrq_char(port, c & 0xff)) continue; uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag); @@ -547,7 +547,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios, ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE; if (termios->c_iflag & INPCK) ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE; /* @@ -628,7 +628,7 @@ static int asc_get_poll_char(struct uart_port *port) static void asc_put_poll_char(struct uart_port *port, unsigned char c) { - while (asc_txfifo_is_full(port)) + while (!asc_txfifo_is_half_empty(port)) cpu_relax(); asc_out(port, ASC_TXBUF, c); } @@ -783,7 +783,7 @@ static void asc_console_putchar(struct uart_port *port, int ch) unsigned int timeout = 1000000; /* Wait for upto 1 second in case flow control is stopping us. */ - while (--timeout && asc_txfifo_is_full(port)) + while (--timeout && !asc_txfifo_is_half_empty(port)) udelay(1); asc_out(port, ASC_TXBUF, ch); diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index cf86e729532..dc697cee248 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -433,13 +433,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign unsigned long flags; int locked = 1; - local_irq_save(flags); - if (port->sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else - spin_lock(&port->lock); + if (port->sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); while (n > 0) { unsigned long ra = __pa(con_write_page); @@ -470,8 +467,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign } if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static inline void sunhv_console_putchar(struct uart_port *port, char c) @@ -492,7 +488,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig unsigned long flags; int i, locked = 1; - local_irq_save(flags); + if (port->sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); if (port->sysrq) { locked = 0; } else if (oops_in_progress) { @@ -507,8 +506,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig } if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static struct console sunhv_console = { diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 5d6136b2a04..2f57df9a71d 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -427,6 +427,9 @@ static void sunsab_start_tx(struct uart_port *port) struct circ_buf *xmit = &up->port.state->xmit; int i; + if (uart_circ_empty(xmit)) + return; + up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR); writeb(up->interrupt_mask1, &up->regs->w.imr1); @@ -719,7 +722,7 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla if (iflag & INPCK) up->port.read_status_mask |= (SAB82532_ISR0_PERR | SAB82532_ISR0_FERR); - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= (SAB82532_ISR1_BRK << 8); /* @@ -844,20 +847,16 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n) unsigned long flags; int locked = 1; - local_irq_save(flags); - if (up->port.sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); + if (up->port.sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&up->port.lock, flags); + else + spin_lock_irqsave(&up->port.lock, flags); uart_console_write(&up->port, s, n, sunsab_console_putchar); sunsab_tec_wait(up); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&up->port.lock, flags); } static int sunsab_console_setup(struct console *con, char *options) @@ -894,7 +893,7 @@ static int sunsab_console_setup(struct console *con, char *options) case B115200: baud = 115200; break; case B230400: baud = 230400; break; case B460800: baud = 460800; break; - }; + } /* * Temporary fix. diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 699cc1b5f6a..5326ae195e5 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -522,7 +522,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) serio_interrupt(&up->serio, ch, 0); #endif break; - }; + } } } while (serial_in(up, UART_LSR) & UART_LSR_DR); } @@ -834,7 +834,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* @@ -1295,13 +1295,10 @@ static void sunsu_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - local_irq_save(flags); - if (up->port.sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); + if (up->port.sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&up->port.lock, flags); + else + spin_lock_irqsave(&up->port.lock, flags); /* * First save the UER then disable the interrupts @@ -1319,8 +1316,7 @@ static void sunsu_console_write(struct console *co, const char *s, serial_out(up, UART_IER, ier); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&up->port.lock, flags); } /* diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 135a1520353..02df3940b95 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -319,7 +319,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, serio_interrupt(&up->serio, ch, 0); #endif break; - }; + } } } @@ -703,6 +703,8 @@ static void sunzilog_start_tx(struct uart_port *port) } else { struct circ_buf *xmit = &port->state->xmit; + if (uart_circ_empty(xmit)) + return; writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -897,7 +899,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->curregs[R5] |= Tx8; up->parity_mask = 0xff; break; - }; + } up->curregs[R4] &= ~0x0c; if (cflag & CSTOPB) up->curregs[R4] |= SB2; @@ -915,7 +917,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->port.read_status_mask = Rx_OVR; if (iflag & INPCK) up->port.read_status_mask |= CRC_ERR | PAR_ERR; - if (iflag & (BRKINT | PARMRK)) + if (iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= BRK_ABRT; up->port.ignore_status_mask = 0; @@ -1195,20 +1197,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) unsigned long flags; int locked = 1; - local_irq_save(flags); - if (up->port.sysrq) { - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&up->port.lock); - } else - spin_lock(&up->port.lock); + if (up->port.sysrq || oops_in_progress) + locked = spin_trylock_irqsave(&up->port.lock, flags); + else + spin_lock_irqsave(&up->port.lock, flags); uart_console_write(&up->port, s, count, sunzilog_putchar); udelay(2); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&up->port.lock, flags); } static int __init sunzilog_console_setup(struct console *con, char *options) @@ -1239,7 +1237,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) default: case B9600: baud = 9600; break; case B19200: baud = 19200; break; case B38400: baud = 38400; break; - }; + } brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c index f92d7e6bd87..613ccf09dc2 100644 --- a/drivers/tty/serial/tilegx.c +++ b/drivers/tty/serial/tilegx.c @@ -359,8 +359,8 @@ static int tilegx_startup(struct uart_port *port) } /* Create our IRQs. */ - port->irq = create_irq(); - if (port->irq < 0) + port->irq = irq_alloc_hwirq(-1); + if (!port->irq) goto err_uart_dest; tile_irq_activate(port->irq, TILE_IRQ_PERCPU); @@ -395,7 +395,7 @@ static int tilegx_startup(struct uart_port *port) err_free_irq: free_irq(port->irq, port); err_dest_irq: - destroy_irq(port->irq); + irq_free_hwirq(port->irq); err_uart_dest: gxio_uart_destroy(context); ret = -ENXIO; @@ -435,7 +435,7 @@ static void tilegx_shutdown(struct uart_port *port) if (port->irq > 0) { free_irq(port->irq, port); - destroy_irq(port->irq); + irq_free_hwirq(port->irq); port->irq = 0; } diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 5f90ef24d47..dce27f34937 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -418,14 +418,23 @@ static struct uart_ops ulite_ops = { #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE static void ulite_console_wait_tx(struct uart_port *port) { - int i; u8 val; - - /* Spin waiting for TX fifo to have space available */ - for (i = 0; i < 100000; i++) { + unsigned long timeout; + + /* + * Spin waiting for TX fifo to have space available. + * When using the Microblaze Debug Module this can take up to 1s + */ + timeout = jiffies + msecs_to_jiffies(1000); + while (1) { val = uart_in32(ULITE_STATUS, port); if ((val & ULITE_STATUS_TXFULL) == 0) break; + if (time_after(jiffies, timeout)) { + dev_warn(port->dev, + "timeout waiting for TX buffer empty\n"); + break; + } cpu_relax(); } } diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 88317482b81..1c52074c38d 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -25,6 +25,8 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> @@ -269,7 +271,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) return 1; bdp++; - }; + } } /* @@ -934,7 +936,7 @@ static void qe_uart_set_termios(struct uart_port *port, port->read_status_mask = BD_SC_EMPTY | BD_SC_OV; if (termios->c_iflag & INPCK) port->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= BD_SC_BR; /* diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index a63c14bc9a2..db0c8a4ab03 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -559,7 +559,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new, port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR; if (c_iflag & INPCK) port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (c_iflag & (BRKINT | PARMRK)) + if (c_iflag & (IGNBRK | BRKINT | PARMRK)) port->read_status_mask |= UART_LSR_BI; port->ignore_status_mask = 0; diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 93b697a0de6..15ad6fcda88 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev) if (!mmres || !irqres) return -ENODEV; - if (np) + if (np) { port = of_alias_get_id(np, "serial"); if (port >= VT8500_MAX_PORTS) port = -1; - else + } else { port = -1; + } if (port < 0) { /* calculate the port id */ diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 7e4150aa69c..8809775e2ba 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1,7 +1,7 @@ /* - * Xilinx PS UART driver + * Cadence UART driver (found in Xilinx Zynq) * - * 2011 (c) Xilinx Inc. + * 2011 - 2014 (C) Xilinx Inc. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public @@ -9,103 +9,105 @@ * either version 2 of the License, or (at your option) any * later version. * + * This driver has originally been pushed by Xilinx using a Zynq-branding. This + * still shows in the naming of this file, the kconfig symbols and some symbols + * in the code. */ +#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/platform_device.h> #include <linux/serial.h> +#include <linux/console.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/console.h> #include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> #include <linux/module.h> -#define XUARTPS_TTY_NAME "ttyPS" -#define XUARTPS_NAME "xuartps" -#define XUARTPS_MAJOR 0 /* use dynamic node allocation */ -#define XUARTPS_MINOR 0 /* works best with devtmpfs */ -#define XUARTPS_NR_PORTS 2 -#define XUARTPS_FIFO_SIZE 16 /* FIFO size */ -#define XUARTPS_REGISTER_SPACE 0xFFF +#define CDNS_UART_TTY_NAME "ttyPS" +#define CDNS_UART_NAME "xuartps" +#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */ +#define CDNS_UART_MINOR 0 /* works best with devtmpfs */ +#define CDNS_UART_NR_PORTS 2 +#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ +#define CDNS_UART_REGISTER_SPACE 0xFFF + +#define cdns_uart_readl(offset) ioread32(port->membase + offset) +#define cdns_uart_writel(val, offset) iowrite32(val, port->membase + offset) + +/* Rx Trigger level */ +static int rx_trigger_level = 56; +module_param(rx_trigger_level, uint, S_IRUGO); +MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes"); + +/* Rx Timeout */ +static int rx_timeout = 10; +module_param(rx_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); + +/* Register offsets for the UART. */ +#define CDNS_UART_CR_OFFSET 0x00 /* Control Register */ +#define CDNS_UART_MR_OFFSET 0x04 /* Mode Register */ +#define CDNS_UART_IER_OFFSET 0x08 /* Interrupt Enable */ +#define CDNS_UART_IDR_OFFSET 0x0C /* Interrupt Disable */ +#define CDNS_UART_IMR_OFFSET 0x10 /* Interrupt Mask */ +#define CDNS_UART_ISR_OFFSET 0x14 /* Interrupt Status */ +#define CDNS_UART_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator */ +#define CDNS_UART_RXTOUT_OFFSET 0x1C /* RX Timeout */ +#define CDNS_UART_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level */ +#define CDNS_UART_MODEMCR_OFFSET 0x24 /* Modem Control */ +#define CDNS_UART_MODEMSR_OFFSET 0x28 /* Modem Status */ +#define CDNS_UART_SR_OFFSET 0x2C /* Channel Status */ +#define CDNS_UART_FIFO_OFFSET 0x30 /* FIFO */ +#define CDNS_UART_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider */ +#define CDNS_UART_FLOWDEL_OFFSET 0x38 /* Flow Delay */ +#define CDNS_UART_IRRX_PWIDTH_OFFSET 0x3C /* IR Min Received Pulse Width */ +#define CDNS_UART_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse Width */ +#define CDNS_UART_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level */ + +/* Control Register Bit Definitions */ +#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ +#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */ +#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */ +#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */ +#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */ +#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */ +#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ +#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ +#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ -#define xuartps_readl(offset) ioread32(port->membase + offset) -#define xuartps_writel(val, offset) iowrite32(val, port->membase + offset) - -/********************************Register Map********************************/ -/** UART - * - * Register offsets for the UART. - * - */ -#define XUARTPS_CR_OFFSET 0x00 /* Control Register [8:0] */ -#define XUARTPS_MR_OFFSET 0x04 /* Mode Register [10:0] */ -#define XUARTPS_IER_OFFSET 0x08 /* Interrupt Enable [10:0] */ -#define XUARTPS_IDR_OFFSET 0x0C /* Interrupt Disable [10:0] */ -#define XUARTPS_IMR_OFFSET 0x10 /* Interrupt Mask [10:0] */ -#define XUARTPS_ISR_OFFSET 0x14 /* Interrupt Status [10:0]*/ -#define XUARTPS_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator [15:0] */ -#define XUARTPS_RXTOUT_OFFSET 0x1C /* RX Timeout [7:0] */ -#define XUARTPS_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level [5:0] */ -#define XUARTPS_MODEMCR_OFFSET 0x24 /* Modem Control [5:0] */ -#define XUARTPS_MODEMSR_OFFSET 0x28 /* Modem Status [8:0] */ -#define XUARTPS_SR_OFFSET 0x2C /* Channel Status [11:0] */ -#define XUARTPS_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */ -#define XUARTPS_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider [7:0] */ -#define XUARTPS_FLOWDEL_OFFSET 0x38 /* Flow Delay [15:0] */ -#define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C /* IR Minimum Received Pulse - Width [15:0] */ -#define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 /* IR Transmitted pulse - Width [7:0] */ -#define XUARTPS_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level [5:0] */ - -/** Control Register - * - * The Control register (CR) controls the major functions of the device. - * - * Control Register Bit Definitions - */ -#define XUARTPS_CR_STOPBRK 0x00000100 /* Stop TX break */ -#define XUARTPS_CR_STARTBRK 0x00000080 /* Set TX break */ -#define XUARTPS_CR_TX_DIS 0x00000020 /* TX disabled. */ -#define XUARTPS_CR_TX_EN 0x00000010 /* TX enabled */ -#define XUARTPS_CR_RX_DIS 0x00000008 /* RX disabled. */ -#define XUARTPS_CR_RX_EN 0x00000004 /* RX enabled */ -#define XUARTPS_CR_TXRST 0x00000002 /* TX logic reset */ -#define XUARTPS_CR_RXRST 0x00000001 /* RX logic reset */ -#define XUARTPS_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ - -/** Mode Register - * +/* + * Mode Register: * The mode register (MR) defines the mode of transfer as well as the data * format. If this register is modified during transmission or reception, * data validity cannot be guaranteed. - * - * Mode Register Bit Definitions - * */ -#define XUARTPS_MR_CLKSEL 0x00000001 /* Pre-scalar selection */ -#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */ -#define XUARTPS_MR_CHMODE_NORM 0x00000000 /* Normal mode */ +#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */ +#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */ +#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */ -#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */ -#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ +#define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */ +#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ -#define XUARTPS_MR_PARITY_NONE 0x00000020 /* No parity mode */ -#define XUARTPS_MR_PARITY_MARK 0x00000018 /* Mark parity mode */ -#define XUARTPS_MR_PARITY_SPACE 0x00000010 /* Space parity mode */ -#define XUARTPS_MR_PARITY_ODD 0x00000008 /* Odd parity mode */ -#define XUARTPS_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ +#define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */ +#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */ +#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */ +#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */ +#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ -#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */ -#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */ -#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ +#define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */ +#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */ +#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ -/** Interrupt Registers - * +/* + * Interrupt Registers: * Interrupt control logic uses the interrupt enable register (IER) and the * interrupt disable register (IDR) to set the value of the bits in the * interrupt mask register (IMR). The IMR determines whether to pass an @@ -113,50 +115,65 @@ * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an * interrupt. IMR and ISR are read only, and IER and IDR are write only. * Reading either IER or IDR returns 0x00. - * * All four registers have the same bit definitions. */ -#define XUARTPS_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */ -#define XUARTPS_IXR_PARITY 0x00000080 /* Parity error interrupt */ -#define XUARTPS_IXR_FRAMING 0x00000040 /* Framing error interrupt */ -#define XUARTPS_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */ -#define XUARTPS_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */ -#define XUARTPS_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */ -#define XUARTPS_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */ -#define XUARTPS_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ -#define XUARTPS_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ -#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ -#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ - -/** Channel Status Register - * +#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */ +#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */ +#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */ +#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */ +#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */ +#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */ +#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */ +#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ +#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ +#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ +#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ + +/* Goes in read_status_mask for break detection as the HW doesn't do it*/ +#define CDNS_UART_IXR_BRK 0x80000000 + +/* + * Channel Status Register: * The channel status register (CSR) is provided to enable the control logic * to monitor the status of bits in the channel interrupt status register, * even if these are masked out by the interrupt mask register. */ -#define XUARTPS_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ -#define XUARTPS_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ -#define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */ -#define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */ +#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ +#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ +#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */ +#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */ + +/* baud dividers min/max values */ +#define CDNS_UART_BDIV_MIN 4 +#define CDNS_UART_BDIV_MAX 255 +#define CDNS_UART_CD_MAX 65535 /** - * struct xuartps - device data - * @refclk Reference clock - * @aperclk APB clock + * struct cdns_uart - device data + * @port: Pointer to the UART port + * @uartclk: Reference clock + * @pclk: APB clock + * @baud: Current baud rate + * @clk_rate_change_nb: Notifier block for clock changes */ -struct xuartps { - struct clk *refclk; - struct clk *aperclk; +struct cdns_uart { + struct uart_port *port; + struct clk *uartclk; + struct clk *pclk; + unsigned int baud; + struct notifier_block clk_rate_change_nb; }; +#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ + clk_rate_change_nb); /** - * xuartps_isr - Interrupt handler + * cdns_uart_isr - Interrupt handler * @irq: Irq number * @dev_id: Id of the port * - * Returns IRQHANDLED - **/ -static irqreturn_t xuartps_isr(int irq, void *dev_id) + * Return: IRQHANDLED + */ +static irqreturn_t cdns_uart_isr(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; unsigned long flags; @@ -169,33 +186,76 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) /* Read the interrupt status register to determine which * interrupt(s) is/are active. */ - isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); + isrstatus = cdns_uart_readl(CDNS_UART_ISR_OFFSET); + + /* + * There is no hardware break detection, so we interpret framing + * error with all-zeros data as a break sequence. Most of the time, + * there's another non-zero byte at the end of the sequence. + */ + if (isrstatus & CDNS_UART_IXR_FRAMING) { + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) { + if (!cdns_uart_readl(CDNS_UART_FIFO_OFFSET)) { + port->read_status_mask |= CDNS_UART_IXR_BRK; + isrstatus &= ~CDNS_UART_IXR_FRAMING; + } + } + cdns_uart_writel(CDNS_UART_IXR_FRAMING, CDNS_UART_ISR_OFFSET); + } /* drop byte with parity error if IGNPAR specified */ - if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) - isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); + if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY) + isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT); isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; - if ((isrstatus & XUARTPS_IXR_TOUT) || - (isrstatus & XUARTPS_IXR_RXTRIG)) { + if ((isrstatus & CDNS_UART_IXR_TOUT) || + (isrstatus & CDNS_UART_IXR_RXTRIG)) { /* Receive Timeout Interrupt */ - while ((xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { - data = xuartps_readl(XUARTPS_FIFO_OFFSET); + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { + data = cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + + /* Non-NULL byte after BREAK is garbage (99%) */ + if (data && (port->read_status_mask & + CDNS_UART_IXR_BRK)) { + port->read_status_mask &= ~CDNS_UART_IXR_BRK; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + +#ifdef SUPPORT_SYSRQ + /* + * uart_handle_sysrq_char() doesn't work if + * spinlocked, for some reason + */ + if (port->sysrq) { + spin_unlock(&port->lock); + if (uart_handle_sysrq_char(port, + (unsigned char)data)) { + spin_lock(&port->lock); + continue; + } + spin_lock(&port->lock); + } +#endif + port->icount.rx++; - if (isrstatus & XUARTPS_IXR_PARITY) { + if (isrstatus & CDNS_UART_IXR_PARITY) { port->icount.parity++; status = TTY_PARITY; - } else if (isrstatus & XUARTPS_IXR_FRAMING) { + } else if (isrstatus & CDNS_UART_IXR_FRAMING) { port->icount.frame++; status = TTY_FRAME; - } else if (isrstatus & XUARTPS_IXR_OVERRUN) + } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; + } - uart_insert_char(port, isrstatus, XUARTPS_IXR_OVERRUN, + uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, data, status); } spin_unlock(&port->lock); @@ -204,10 +264,10 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } /* Dispatch an appropriate handler */ - if ((isrstatus & XUARTPS_IXR_TXEMPTY) == XUARTPS_IXR_TXEMPTY) { + if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) { if (uart_circ_empty(&port->state->xmit)) { - xuartps_writel(XUARTPS_IXR_TXEMPTY, - XUARTPS_IDR_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, + CDNS_UART_IDR_OFFSET); } else { numbytes = port->fifosize; /* Break if no more data available in the UART buffer */ @@ -215,12 +275,12 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) if (uart_circ_empty(&port->state->xmit)) break; /* Get the data from the UART circular buffer - * and write it to the xuartps's TX_FIFO + * and write it to the cdns_uart's TX_FIFO * register. */ - xuartps_writel( + cdns_uart_writel( port->state->xmit.buf[port->state->xmit. - tail], XUARTPS_FIFO_OFFSET); + tail], CDNS_UART_FIFO_OFFSET); port->icount.tx++; @@ -228,7 +288,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) * the buffer if it reaches limit. */ port->state->xmit.tail = - (port->state->xmit.tail + 1) & \ + (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } @@ -238,7 +298,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } } - xuartps_writel(isrstatus, XUARTPS_ISR_OFFSET); + cdns_uart_writel(isrstatus, CDNS_UART_ISR_OFFSET); /* be sure to release the lock and tty before leaving */ spin_unlock_irqrestore(&port->lock, flags); @@ -247,97 +307,226 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } /** - * xuartps_set_baud_rate - Calculate and set the baud rate - * @port: Handle to the uart port structure - * @baud: Baud rate to set + * cdns_uart_calc_baud_divs - Calculate baud rate divisors + * @clk: UART module input clock + * @baud: Desired baud rate + * @rbdiv: BDIV value (return value) + * @rcd: CD value (return value) + * @div8: Value for clk_sel bit in mod (return value) + * Return: baud rate, requested baud when possible, or actual baud when there + * was too much error, zero if no valid divisors are found. * - * Returns baud rate, requested baud when possible, or actual baud when there - * was too much error - **/ -static unsigned int xuartps_set_baud_rate(struct uart_port *port, - unsigned int baud) + * Formula to obtain baud rate is + * baud_tx/rx rate = clk/CD * (BDIV + 1) + * input_clk = (Uart User Defined Clock or Apb Clock) + * depends on UCLKEN in MR Reg + * clk = input_clk or input_clk/8; + * depends on CLKS in MR reg + * CD and BDIV depends on values in + * baud rate generate register + * baud rate clock divisor register + */ +static unsigned int cdns_uart_calc_baud_divs(unsigned int clk, + unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8) { - unsigned int sel_clk; - unsigned int calc_baud = 0; - unsigned int brgr_val, brdiv_val; + u32 cd, bdiv; + unsigned int calc_baud; + unsigned int bestbaud = 0; unsigned int bauderror; + unsigned int besterror = ~0; - /* Formula to obtain baud rate is - * baud_tx/rx rate = sel_clk/CD * (BDIV + 1) - * input_clk = (Uart User Defined Clock or Apb Clock) - * depends on UCLKEN in MR Reg - * sel_clk = input_clk or input_clk/8; - * depends on CLKS in MR reg - * CD and BDIV depends on values in - * baud rate generate register - * baud rate clock divisor register - */ - sel_clk = port->uartclk; - if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL) - sel_clk = sel_clk / 8; - - /* Find the best values for baud generation */ - for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) { + if (baud < clk / ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX)) { + *div8 = 1; + clk /= 8; + } else { + *div8 = 0; + } - brgr_val = sel_clk / (baud * (brdiv_val + 1)); - if (brgr_val < 2 || brgr_val > 65535) + for (bdiv = CDNS_UART_BDIV_MIN; bdiv <= CDNS_UART_BDIV_MAX; bdiv++) { + cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1)); + if (cd < 1 || cd > CDNS_UART_CD_MAX) continue; - calc_baud = sel_clk / (brgr_val * (brdiv_val + 1)); + calc_baud = clk / (cd * (bdiv + 1)); if (baud > calc_baud) bauderror = baud - calc_baud; else bauderror = calc_baud - baud; - /* use the values when percent error is acceptable */ - if (((bauderror * 100) / baud) < 3) { - calc_baud = baud; - break; + if (besterror > bauderror) { + *rbdiv = bdiv; + *rcd = cd; + bestbaud = calc_baud; + besterror = bauderror; } } + /* use the values when percent error is acceptable */ + if (((besterror * 100) / baud) < 3) + bestbaud = baud; - /* Set the values for the new baud rate */ - xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET); - xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET); + return bestbaud; +} + +/** + * cdns_uart_set_baud_rate - Calculate and set the baud rate + * @port: Handle to the uart port structure + * @baud: Baud rate to set + * Return: baud rate, requested baud when possible, or actual baud when there + * was too much error, zero if no valid divisors are found. + */ +static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, + unsigned int baud) +{ + unsigned int calc_baud; + u32 cd = 0, bdiv = 0; + u32 mreg; + int div8; + struct cdns_uart *cdns_uart = port->private_data; + + calc_baud = cdns_uart_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, + &div8); + + /* Write new divisors to hardware */ + mreg = cdns_uart_readl(CDNS_UART_MR_OFFSET); + if (div8) + mreg |= CDNS_UART_MR_CLKSEL; + else + mreg &= ~CDNS_UART_MR_CLKSEL; + cdns_uart_writel(mreg, CDNS_UART_MR_OFFSET); + cdns_uart_writel(cd, CDNS_UART_BAUDGEN_OFFSET); + cdns_uart_writel(bdiv, CDNS_UART_BAUDDIV_OFFSET); + cdns_uart->baud = baud; return calc_baud; } -/*----------------------Uart Operations---------------------------*/ +#ifdef CONFIG_COMMON_CLK +/** + * cdns_uart_clk_notitifer_cb - Clock notifier callback + * @nb: Notifier block + * @event: Notify event + * @data: Notifier data + * Return: NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error. + */ +static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + u32 ctrl_reg; + struct uart_port *port; + int locked = 0; + struct clk_notifier_data *ndata = data; + unsigned long flags = 0; + struct cdns_uart *cdns_uart = to_cdns_uart(nb); + + port = cdns_uart->port; + if (port->suspended) + return NOTIFY_OK; + + switch (event) { + case PRE_RATE_CHANGE: + { + u32 bdiv, cd; + int div8; + + /* + * Find out if current baud-rate can be achieved with new clock + * frequency. + */ + if (!cdns_uart_calc_baud_divs(ndata->new_rate, cdns_uart->baud, + &bdiv, &cd, &div8)) { + dev_warn(port->dev, "clock rate change rejected\n"); + return NOTIFY_BAD; + } + + spin_lock_irqsave(&cdns_uart->port->lock, flags); + + /* Disable the TX and RX to set baud rate */ + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + + spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + + return NOTIFY_OK; + } + case POST_RATE_CHANGE: + /* + * Set clk dividers to generate correct baud with new clock + * frequency. + */ + + spin_lock_irqsave(&cdns_uart->port->lock, flags); + + locked = 1; + port->uartclk = ndata->new_rate; + + cdns_uart->baud = cdns_uart_set_baud_rate(cdns_uart->port, + cdns_uart->baud); + /* fall through */ + case ABORT_RATE_CHANGE: + if (!locked) + spin_lock_irqsave(&cdns_uart->port->lock, flags); + + /* Set TX/RX Reset */ + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + + while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) + cpu_relax(); + + /* + * Clear the RX disable and TX disable bits and then set the TX + * enable bit and RX enable bit to enable the transmitter and + * receiver. + */ + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + + spin_unlock_irqrestore(&cdns_uart->port->lock, flags); + + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} +#endif /** - * xuartps_start_tx - Start transmitting bytes + * cdns_uart_start_tx - Start transmitting bytes * @port: Handle to the uart port structure - * - **/ -static void xuartps_start_tx(struct uart_port *port) + */ +static void cdns_uart_start_tx(struct uart_port *port) { unsigned int status, numbytes = port->fifosize; if (uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port)) return; - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); /* Set the TX enable bit and clear the TX disable bit to enable the * transmitter. */ - xuartps_writel((status & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, - XUARTPS_CR_OFFSET); - - while (numbytes-- && ((xuartps_readl(XUARTPS_SR_OFFSET) - & XUARTPS_SR_TXFULL)) != XUARTPS_SR_TXFULL) { + cdns_uart_writel((status & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + CDNS_UART_CR_OFFSET); + while (numbytes-- && ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_TXFULL)) != CDNS_UART_SR_TXFULL) { /* Break if no more data available in the UART buffer */ if (uart_circ_empty(&port->state->xmit)) break; /* Get the data from the UART circular buffer and - * write it to the xuartps's TX_FIFO register. + * write it to the cdns_uart's TX_FIFO register. */ - xuartps_writel( + cdns_uart_writel( port->state->xmit.buf[port->state->xmit.tail], - XUARTPS_FIFO_OFFSET); + CDNS_UART_FIFO_OFFSET); port->icount.tx++; /* Adjust the tail of the UART buffer and wrap @@ -346,173 +535,173 @@ static void xuartps_start_tx(struct uart_port *port) port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_ISR_OFFSET); /* Enable the TX Empty interrupt */ - xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY, CDNS_UART_IER_OFFSET); if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) uart_write_wakeup(port); } /** - * xuartps_stop_tx - Stop TX + * cdns_uart_stop_tx - Stop TX * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_tx(struct uart_port *port) + */ +static void cdns_uart_stop_tx(struct uart_port *port) { unsigned int regval; - regval = xuartps_readl(XUARTPS_CR_OFFSET); - regval |= XUARTPS_CR_TX_DIS; + regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval |= CDNS_UART_CR_TX_DIS; /* Disable the transmitter */ - xuartps_writel(regval, XUARTPS_CR_OFFSET); + cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); } /** - * xuartps_stop_rx - Stop RX + * cdns_uart_stop_rx - Stop RX * @port: Handle to the uart port structure - * - **/ -static void xuartps_stop_rx(struct uart_port *port) + */ +static void cdns_uart_stop_rx(struct uart_port *port) { unsigned int regval; - regval = xuartps_readl(XUARTPS_CR_OFFSET); - regval |= XUARTPS_CR_RX_DIS; + regval = cdns_uart_readl(CDNS_UART_CR_OFFSET); + regval |= CDNS_UART_CR_RX_DIS; /* Disable the receiver */ - xuartps_writel(regval, XUARTPS_CR_OFFSET); + cdns_uart_writel(regval, CDNS_UART_CR_OFFSET); } /** - * xuartps_tx_empty - Check whether TX is empty + * cdns_uart_tx_empty - Check whether TX is empty * @port: Handle to the uart port structure * - * Returns TIOCSER_TEMT on success, 0 otherwise - **/ -static unsigned int xuartps_tx_empty(struct uart_port *port) + * Return: TIOCSER_TEMT on success, 0 otherwise + */ +static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; - status = xuartps_readl(XUARTPS_ISR_OFFSET) & XUARTPS_IXR_TXEMPTY; + status = cdns_uart_readl(CDNS_UART_ISR_OFFSET) & CDNS_UART_IXR_TXEMPTY; return status ? TIOCSER_TEMT : 0; } /** - * xuartps_break_ctl - Based on the input ctl we have to start or stop + * cdns_uart_break_ctl - Based on the input ctl we have to start or stop * transmitting char breaks * @port: Handle to the uart port structure * @ctl: Value based on which start or stop decision is taken - * - **/ -static void xuartps_break_ctl(struct uart_port *port, int ctl) + */ +static void cdns_uart_break_ctl(struct uart_port *port, int ctl) { unsigned int status; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); if (ctl == -1) - xuartps_writel(XUARTPS_CR_STARTBRK | status, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_STARTBRK | status, + CDNS_UART_CR_OFFSET); else { - if ((status & XUARTPS_CR_STOPBRK) == 0) - xuartps_writel(XUARTPS_CR_STOPBRK | status, - XUARTPS_CR_OFFSET); + if ((status & CDNS_UART_CR_STOPBRK) == 0) + cdns_uart_writel(CDNS_UART_CR_STOPBRK | status, + CDNS_UART_CR_OFFSET); } spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_set_termios - termios operations, handling data length, parity, + * cdns_uart_set_termios - termios operations, handling data length, parity, * stop bits, flow control, baud rate * @port: Handle to the uart port structure * @termios: Handle to the input termios structure * @old: Values of the previously saved termios structure - * - **/ -static void xuartps_set_termios(struct uart_port *port, + */ +static void cdns_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int cval = 0; - unsigned int baud; + unsigned int baud, minbaud, maxbaud; unsigned long flags; unsigned int ctrl_reg, mode_reg; spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ - while ((xuartps_readl(XUARTPS_SR_OFFSET) & - XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { - xuartps_readl(XUARTPS_FIFO_OFFSET); + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { + cdns_uart_readl(CDNS_UART_FIFO_OFFSET); } /* Disable the TX and RX to set baud rate */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */ - baud = uart_get_baud_rate(port, termios, old, 0, 10000000); - baud = xuartps_set_baud_rate(port, baud); + /* + * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk + * min and max baud should be calculated here based on port->uartclk. + * this way we get a valid baud and can safely call set_baud() + */ + minbaud = port->uartclk / + ((CDNS_UART_BDIV_MAX + 1) * CDNS_UART_CD_MAX * 8); + maxbaud = port->uartclk / (CDNS_UART_BDIV_MIN + 1); + baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud); + baud = cdns_uart_set_baud_rate(port, baud); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); - /* - * Update the per-port timeout. - */ + /* Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* Set TX/RX Reset */ - xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | - (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), - XUARTPS_CR_OFFSET); - - ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - /* Clear the RX disable and TX disable bits and then set the TX enable + /* + * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - xuartps_writel( - (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) - | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), - XUARTPS_CR_OFFSET); + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); - port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | - XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; + port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT; port->ignore_status_mask = 0; if (termios->c_iflag & INPCK) - port->read_status_mask |= XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING; + port->read_status_mask |= CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING; if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; + port->ignore_status_mask |= CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; /* ignore all characters if CREAD is not set */ if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= XUARTPS_IXR_RXTRIG | - XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN; + port->ignore_status_mask |= CDNS_UART_IXR_RXTRIG | + CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN; - mode_reg = xuartps_readl(XUARTPS_MR_OFFSET); + mode_reg = cdns_uart_readl(CDNS_UART_MR_OFFSET); /* Handling Data Size */ switch (termios->c_cflag & CSIZE) { case CS6: - cval |= XUARTPS_MR_CHARLEN_6_BIT; + cval |= CDNS_UART_MR_CHARLEN_6_BIT; break; case CS7: - cval |= XUARTPS_MR_CHARLEN_7_BIT; + cval |= CDNS_UART_MR_CHARLEN_7_BIT; break; default: case CS8: - cval |= XUARTPS_MR_CHARLEN_8_BIT; + cval |= CDNS_UART_MR_CHARLEN_8_BIT; termios->c_cflag &= ~CSIZE; termios->c_cflag |= CS8; break; @@ -520,124 +709,135 @@ static void xuartps_set_termios(struct uart_port *port, /* Handling Parity and Stop Bits length */ if (termios->c_cflag & CSTOPB) - cval |= XUARTPS_MR_STOPMODE_2_BIT; /* 2 STOP bits */ + cval |= CDNS_UART_MR_STOPMODE_2_BIT; /* 2 STOP bits */ else - cval |= XUARTPS_MR_STOPMODE_1_BIT; /* 1 STOP bit */ + cval |= CDNS_UART_MR_STOPMODE_1_BIT; /* 1 STOP bit */ if (termios->c_cflag & PARENB) { /* Mark or Space parity */ if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) - cval |= XUARTPS_MR_PARITY_MARK; + cval |= CDNS_UART_MR_PARITY_MARK; else - cval |= XUARTPS_MR_PARITY_SPACE; - } else if (termios->c_cflag & PARODD) - cval |= XUARTPS_MR_PARITY_ODD; + cval |= CDNS_UART_MR_PARITY_SPACE; + } else { + if (termios->c_cflag & PARODD) + cval |= CDNS_UART_MR_PARITY_ODD; else - cval |= XUARTPS_MR_PARITY_EVEN; - } else - cval |= XUARTPS_MR_PARITY_NONE; - xuartps_writel(cval , XUARTPS_MR_OFFSET); + cval |= CDNS_UART_MR_PARITY_EVEN; + } + } else { + cval |= CDNS_UART_MR_PARITY_NONE; + } + cval |= mode_reg & 1; + cdns_uart_writel(cval, CDNS_UART_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_startup - Called when an application opens a xuartps port + * cdns_uart_startup - Called when an application opens a cdns_uart port * @port: Handle to the uart port structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_startup(struct uart_port *port) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_startup(struct uart_port *port) { unsigned int retval = 0, status = 0; - retval = request_irq(port->irq, xuartps_isr, 0, XUARTPS_NAME, + retval = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, (void *)port); if (retval) return retval; /* Disable the TX and RX */ - xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + CDNS_UART_CR_OFFSET); /* Set the Control Register with TX/RX Enable, TX/RX Reset, * no break chars. */ - xuartps_writel(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, + CDNS_UART_CR_OFFSET); - status = xuartps_readl(XUARTPS_CR_OFFSET); + status = cdns_uart_readl(CDNS_UART_CR_OFFSET); /* Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. */ - xuartps_writel((status & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) - | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN | - XUARTPS_CR_STOPBRK), XUARTPS_CR_OFFSET); + cdns_uart_writel((status & ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS)) + | (CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN | + CDNS_UART_CR_STOPBRK), CDNS_UART_CR_OFFSET); /* Set the Mode Register with normal mode,8 data bits,1 stop bit, * no parity. */ - xuartps_writel(XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT - | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT, - XUARTPS_MR_OFFSET); + cdns_uart_writel(CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT + | CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT, + CDNS_UART_MR_OFFSET); - /* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */ - xuartps_writel(14, XUARTPS_RXWM_OFFSET); + /* + * Set the RX FIFO Trigger level to use most of the FIFO, but it + * can be tuned with a module parameter + */ + cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); - /* Receive Timeout register is enabled with value of 10 */ - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + /* + * Receive Timeout register is enabled but it + * can be tuned with a module parameter + */ + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ - xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); + cdns_uart_writel(cdns_uart_readl(CDNS_UART_ISR_OFFSET), + CDNS_UART_ISR_OFFSET); /* Set the Interrupt Registers with desired interrupts */ - xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY | - XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN | - XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + cdns_uart_writel(CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_PARITY | + CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN | + CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT, + CDNS_UART_IER_OFFSET); return retval; } /** - * xuartps_shutdown - Called when an application closes a xuartps port + * cdns_uart_shutdown - Called when an application closes a cdns_uart port * @port: Handle to the uart port structure - * - **/ -static void xuartps_shutdown(struct uart_port *port) + */ +static void cdns_uart_shutdown(struct uart_port *port) { int status; /* Disable interrupts */ - status = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(status, XUARTPS_IDR_OFFSET); + status = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(status, CDNS_UART_IDR_OFFSET); /* Disable the TX and RX */ - xuartps_writel(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS, - XUARTPS_CR_OFFSET); + cdns_uart_writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS, + CDNS_UART_CR_OFFSET); free_irq(port->irq, port); } /** - * xuartps_type - Set UART type to xuartps port + * cdns_uart_type - Set UART type to cdns_uart port * @port: Handle to the uart port structure * - * Returns string on success, NULL otherwise - **/ -static const char *xuartps_type(struct uart_port *port) + * Return: string on success, NULL otherwise + */ +static const char *cdns_uart_type(struct uart_port *port) { - return port->type == PORT_XUARTPS ? XUARTPS_NAME : NULL; + return port->type == PORT_XUARTPS ? CDNS_UART_NAME : NULL; } /** - * xuartps_verify_port - Verify the port params + * cdns_uart_verify_port - Verify the port params * @port: Handle to the uart port structure * @ser: Handle to the structure whose members are compared * - * Returns 0 if success otherwise -EINVAL - **/ -static int xuartps_verify_port(struct uart_port *port, + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { if (ser->type != PORT_UNKNOWN && ser->type != PORT_XUARTPS) @@ -654,135 +854,170 @@ static int xuartps_verify_port(struct uart_port *port, } /** - * xuartps_request_port - Claim the memory region attached to xuartps port, - * called when the driver adds a xuartps port via + * cdns_uart_request_port - Claim the memory region attached to cdns_uart port, + * called when the driver adds a cdns_uart port via * uart_add_one_port() * @port: Handle to the uart port structure * - * Returns 0, -ENOMEM if request fails - **/ -static int xuartps_request_port(struct uart_port *port) + * Return: 0 on success, negative errno otherwise. + */ +static int cdns_uart_request_port(struct uart_port *port) { - if (!request_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE, - XUARTPS_NAME)) { + if (!request_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE, + CDNS_UART_NAME)) { return -ENOMEM; } - port->membase = ioremap(port->mapbase, XUARTPS_REGISTER_SPACE); + port->membase = ioremap(port->mapbase, CDNS_UART_REGISTER_SPACE); if (!port->membase) { dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); + release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); return -ENOMEM; } return 0; } /** - * xuartps_release_port - Release the memory region attached to a xuartps - * port, called when the driver removes a xuartps - * port via uart_remove_one_port(). + * cdns_uart_release_port - Release UART port * @port: Handle to the uart port structure * - **/ -static void xuartps_release_port(struct uart_port *port) + * Release the memory region attached to a cdns_uart port. Called when the + * driver removes a cdns_uart port via uart_remove_one_port(). + */ +static void cdns_uart_release_port(struct uart_port *port) { - release_mem_region(port->mapbase, XUARTPS_REGISTER_SPACE); + release_mem_region(port->mapbase, CDNS_UART_REGISTER_SPACE); iounmap(port->membase); port->membase = NULL; } /** - * xuartps_config_port - Configure xuartps, called when the driver adds a - * xuartps port + * cdns_uart_config_port - Configure UART port * @port: Handle to the uart port structure * @flags: If any - * - **/ -static void xuartps_config_port(struct uart_port *port, int flags) + */ +static void cdns_uart_config_port(struct uart_port *port, int flags) { - if (flags & UART_CONFIG_TYPE && xuartps_request_port(port) == 0) + if (flags & UART_CONFIG_TYPE && cdns_uart_request_port(port) == 0) port->type = PORT_XUARTPS; } /** - * xuartps_get_mctrl - Get the modem control state - * + * cdns_uart_get_mctrl - Get the modem control state * @port: Handle to the uart port structure * - * Returns the modem control state - * - **/ -static unsigned int xuartps_get_mctrl(struct uart_port *port) + * Return: the modem control state + */ +static unsigned int cdns_uart_get_mctrl(struct uart_port *port) { return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; } -static void xuartps_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { /* N/A */ } -static void xuartps_enable_ms(struct uart_port *port) +static void cdns_uart_enable_ms(struct uart_port *port) { /* N/A */ } -/** The UART operations structure - */ -static struct uart_ops xuartps_ops = { - .set_mctrl = xuartps_set_mctrl, - .get_mctrl = xuartps_get_mctrl, - .enable_ms = xuartps_enable_ms, - - .start_tx = xuartps_start_tx, /* Start transmitting */ - .stop_tx = xuartps_stop_tx, /* Stop transmission */ - .stop_rx = xuartps_stop_rx, /* Stop reception */ - .tx_empty = xuartps_tx_empty, /* Transmitter busy? */ - .break_ctl = xuartps_break_ctl, /* Start/stop - * transmitting break - */ - .set_termios = xuartps_set_termios, /* Set termios */ - .startup = xuartps_startup, /* App opens xuartps */ - .shutdown = xuartps_shutdown, /* App closes xuartps */ - .type = xuartps_type, /* Set UART type */ - .verify_port = xuartps_verify_port, /* Verification of port - * params - */ - .request_port = xuartps_request_port, /* Claim resources - * associated with a - * xuartps port - */ - .release_port = xuartps_release_port, /* Release resources - * associated with a - * xuartps port - */ - .config_port = xuartps_config_port, /* Configure when driver - * adds a xuartps port - */ +#ifdef CONFIG_CONSOLE_POLL +static int cdns_uart_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + + /* Disable all interrupts */ + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + + /* Check if FIFO is empty */ + if (cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_RXEMPTY) + c = NO_POLL_CHAR; + else /* Read a character */ + c = (unsigned char) cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + + /* Enable interrupts */ + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + + return c; +} + +static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + + /* Disable all interrupts */ + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); + + /* Wait until FIFO is empty */ + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + cpu_relax(); + + /* Write a character */ + cdns_uart_writel(c, CDNS_UART_FIFO_OFFSET); + + /* Wait until FIFO is empty */ + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY)) + cpu_relax(); + + /* Enable interrupts */ + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); + + return; +} +#endif + +static struct uart_ops cdns_uart_ops = { + .set_mctrl = cdns_uart_set_mctrl, + .get_mctrl = cdns_uart_get_mctrl, + .enable_ms = cdns_uart_enable_ms, + .start_tx = cdns_uart_start_tx, + .stop_tx = cdns_uart_stop_tx, + .stop_rx = cdns_uart_stop_rx, + .tx_empty = cdns_uart_tx_empty, + .break_ctl = cdns_uart_break_ctl, + .set_termios = cdns_uart_set_termios, + .startup = cdns_uart_startup, + .shutdown = cdns_uart_shutdown, + .type = cdns_uart_type, + .verify_port = cdns_uart_verify_port, + .request_port = cdns_uart_request_port, + .release_port = cdns_uart_release_port, + .config_port = cdns_uart_config_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = cdns_uart_poll_get_char, + .poll_put_char = cdns_uart_poll_put_char, +#endif }; -static struct uart_port xuartps_port[2]; +static struct uart_port cdns_uart_port[2]; /** - * xuartps_get_port - Configure the port from the platform device resource - * info + * cdns_uart_get_port - Configure the port from platform device resource info + * @id: Port id * - * Returns a pointer to a uart_port or NULL for failure - **/ -static struct uart_port *xuartps_get_port(void) + * Return: a pointer to a uart_port or NULL for failure + */ +static struct uart_port *cdns_uart_get_port(int id) { struct uart_port *port; - int id; - /* Find the next unused port */ - for (id = 0; id < XUARTPS_NR_PORTS; id++) - if (xuartps_port[id].mapbase == 0) - break; + /* Try the given port id if failed use default method */ + if (cdns_uart_port[id].mapbase != 0) { + /* Find the next unused port */ + for (id = 0; id < CDNS_UART_NR_PORTS; id++) + if (cdns_uart_port[id].mapbase == 0) + break; + } - if (id >= XUARTPS_NR_PORTS) + if (id >= CDNS_UART_NR_PORTS) return NULL; - port = &xuartps_port[id]; + port = &cdns_uart_port[id]; /* At this point, we've got an empty uart_port struct, initialize it */ spin_lock_init(&port->lock); @@ -792,52 +1027,48 @@ static struct uart_port *xuartps_get_port(void) port->type = PORT_UNKNOWN; port->iotype = UPIO_MEM32; port->flags = UPF_BOOT_AUTOCONF; - port->ops = &xuartps_ops; - port->fifosize = XUARTPS_FIFO_SIZE; + port->ops = &cdns_uart_ops; + port->fifosize = CDNS_UART_FIFO_SIZE; port->line = id; port->dev = NULL; return port; } -/*-----------------------Console driver operations--------------------------*/ - #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE /** - * xuartps_console_wait_tx - Wait for the TX to be full + * cdns_uart_console_wait_tx - Wait for the TX to be full * @port: Handle to the uart port structure - * - **/ -static void xuartps_console_wait_tx(struct uart_port *port) + */ +static void cdns_uart_console_wait_tx(struct uart_port *port) { - while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY) - != XUARTPS_SR_TXEMPTY) + while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) & CDNS_UART_SR_TXEMPTY) + != CDNS_UART_SR_TXEMPTY) barrier(); } /** - * xuartps_console_putchar - write the character to the FIFO buffer + * cdns_uart_console_putchar - write the character to the FIFO buffer * @port: Handle to the uart port structure * @ch: Character to be written - * - **/ -static void xuartps_console_putchar(struct uart_port *port, int ch) + */ +static void cdns_uart_console_putchar(struct uart_port *port, int ch) { - xuartps_console_wait_tx(port); - xuartps_writel(ch, XUARTPS_FIFO_OFFSET); + cdns_uart_console_wait_tx(port); + cdns_uart_writel(ch, CDNS_UART_FIFO_OFFSET); } /** - * xuartps_console_write - perform write operation - * @port: Handle to the uart port structure + * cdns_uart_console_write - perform write operation + * @co: Console handle * @s: Pointer to character array * @count: No of characters - **/ -static void xuartps_console_write(struct console *co, const char *s, + */ +static void cdns_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &xuartps_port[co->index]; + struct uart_port *port = &cdns_uart_port[co->index]; unsigned long flags; - unsigned int imr; + unsigned int imr, ctrl; int locked = 1; if (oops_in_progress) @@ -846,39 +1077,45 @@ static void xuartps_console_write(struct console *co, const char *s, spin_lock_irqsave(&port->lock, flags); /* save and disable interrupt */ - imr = xuartps_readl(XUARTPS_IMR_OFFSET); - xuartps_writel(imr, XUARTPS_IDR_OFFSET); - - uart_console_write(port, s, count, xuartps_console_putchar); - xuartps_console_wait_tx(port); + imr = cdns_uart_readl(CDNS_UART_IMR_OFFSET); + cdns_uart_writel(imr, CDNS_UART_IDR_OFFSET); - /* restore interrupt state, it seems like there may be a h/w bug - * in that the interrupt enable register should not need to be - * written based on the data sheet + /* + * Make sure that the tx part is enabled. Set the TX enable bit and + * clear the TX disable bit to enable the transmitter. */ - xuartps_writel(~imr, XUARTPS_IDR_OFFSET); - xuartps_writel(imr, XUARTPS_IER_OFFSET); + ctrl = cdns_uart_readl(CDNS_UART_CR_OFFSET); + cdns_uart_writel((ctrl & ~CDNS_UART_CR_TX_DIS) | CDNS_UART_CR_TX_EN, + CDNS_UART_CR_OFFSET); + + uart_console_write(port, s, count, cdns_uart_console_putchar); + cdns_uart_console_wait_tx(port); + + cdns_uart_writel(ctrl, CDNS_UART_CR_OFFSET); + + /* restore interrupt state */ + cdns_uart_writel(imr, CDNS_UART_IER_OFFSET); if (locked) spin_unlock_irqrestore(&port->lock, flags); } /** - * xuartps_console_setup - Initialize the uart to default config + * cdns_uart_console_setup - Initialize the uart to default config * @co: Console handle * @options: Initial settings of uart * - * Returns 0, -ENODEV if no device - **/ -static int __init xuartps_console_setup(struct console *co, char *options) + * Return: 0 on success, negative errno otherwise. + */ +static int __init cdns_uart_console_setup(struct console *co, char *options) { - struct uart_port *port = &xuartps_port[co->index]; + struct uart_port *port = &cdns_uart_port[co->index]; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; - if (co->index < 0 || co->index >= XUARTPS_NR_PORTS) + if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS) return -EINVAL; if (!port->mapbase) { @@ -892,89 +1129,208 @@ static int __init xuartps_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -static struct uart_driver xuartps_uart_driver; +static struct uart_driver cdns_uart_uart_driver; -static struct console xuartps_console = { - .name = XUARTPS_TTY_NAME, - .write = xuartps_console_write, +static struct console cdns_uart_console = { + .name = CDNS_UART_TTY_NAME, + .write = cdns_uart_console_write, .device = uart_console_device, - .setup = xuartps_console_setup, + .setup = cdns_uart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */ - .data = &xuartps_uart_driver, + .data = &cdns_uart_uart_driver, }; /** - * xuartps_console_init - Initialization call + * cdns_uart_console_init - Initialization call * - * Returns 0 on success, negative error otherwise - **/ -static int __init xuartps_console_init(void) + * Return: 0 on success, negative errno otherwise + */ +static int __init cdns_uart_console_init(void) { - register_console(&xuartps_console); + register_console(&cdns_uart_console); return 0; } -console_initcall(xuartps_console_init); +console_initcall(cdns_uart_console_init); #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ -/** Structure Definitions - */ -static struct uart_driver xuartps_uart_driver = { - .owner = THIS_MODULE, /* Owner */ - .driver_name = XUARTPS_NAME, /* Driver name */ - .dev_name = XUARTPS_TTY_NAME, /* Node name */ - .major = XUARTPS_MAJOR, /* Major number */ - .minor = XUARTPS_MINOR, /* Minor number */ - .nr = XUARTPS_NR_PORTS, /* Number of UART ports */ +static struct uart_driver cdns_uart_uart_driver = { + .owner = THIS_MODULE, + .driver_name = CDNS_UART_NAME, + .dev_name = CDNS_UART_TTY_NAME, + .major = CDNS_UART_MAJOR, + .minor = CDNS_UART_MINOR, + .nr = CDNS_UART_NR_PORTS, #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE - .cons = &xuartps_console, /* Console */ + .cons = &cdns_uart_console, #endif }; -/* --------------------------------------------------------------------- - * Platform bus binding +#ifdef CONFIG_PM_SLEEP +/** + * cdns_uart_suspend - suspend event + * @device: Pointer to the device structure + * + * Return: 0 + */ +static int cdns_uart_suspend(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + /* + * Call the API provided in serial_core.c file which handles + * the suspend. + */ + uart_suspend_port(&cdns_uart_uart_driver, port); + if (console_suspend_enabled && !may_wake) { + struct cdns_uart *cdns_uart = port->private_data; + + clk_disable(cdns_uart->uartclk); + clk_disable(cdns_uart->pclk); + } else { + unsigned long flags = 0; + + spin_lock_irqsave(&port->lock, flags); + /* Empty the receive FIFO 1st before making changes */ + while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) & + CDNS_UART_SR_RXEMPTY)) + cdns_uart_readl(CDNS_UART_FIFO_OFFSET); + /* set RX trigger level to 1 */ + cdns_uart_writel(1, CDNS_UART_RXWM_OFFSET); + /* disable RX timeout interrups */ + cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IDR_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return 0; +} + +/** + * cdns_uart_resume - Resume after a previous suspend + * @device: Pointer to the device structure + * + * Return: 0 */ +static int cdns_uart_resume(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + unsigned long flags = 0; + u32 ctrl_reg; + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + if (console_suspend_enabled && !may_wake) { + struct cdns_uart *cdns_uart = port->private_data; + + clk_enable(cdns_uart->pclk); + clk_enable(cdns_uart->uartclk); + + spin_lock_irqsave(&port->lock, flags); + + /* Set TX/RX Reset */ + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + while (cdns_uart_readl(CDNS_UART_CR_OFFSET) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) + cpu_relax(); + + /* restore rx timeout value */ + cdns_uart_writel(rx_timeout, CDNS_UART_RXTOUT_OFFSET); + /* Enable Tx/Rx */ + ctrl_reg = cdns_uart_readl(CDNS_UART_CR_OFFSET); + ctrl_reg &= ~(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS); + ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN; + cdns_uart_writel(ctrl_reg, CDNS_UART_CR_OFFSET); + + spin_unlock_irqrestore(&port->lock, flags); + } else { + spin_lock_irqsave(&port->lock, flags); + /* restore original rx trigger level */ + cdns_uart_writel(rx_trigger_level, CDNS_UART_RXWM_OFFSET); + /* enable RX timeout interrupt */ + cdns_uart_writel(CDNS_UART_IXR_TOUT, CDNS_UART_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return uart_resume_port(&cdns_uart_uart_driver, port); +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, + cdns_uart_resume); + /** - * xuartps_probe - Platform driver probe + * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_probe(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_probe(struct platform_device *pdev) { - int rc; + int rc, id; struct uart_port *port; struct resource *res, *res2; - struct xuartps *xuartps_data; + struct cdns_uart *cdns_uart_data; - xuartps_data = kzalloc(sizeof(*xuartps_data), GFP_KERNEL); - if (!xuartps_data) + cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), + GFP_KERNEL); + if (!cdns_uart_data) return -ENOMEM; - xuartps_data->aperclk = clk_get(&pdev->dev, "aper_clk"); - if (IS_ERR(xuartps_data->aperclk)) { - dev_err(&pdev->dev, "aper_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->aperclk); - goto err_out_free; + cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(cdns_uart_data->pclk)) { + cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); + if (!IS_ERR(cdns_uart_data->pclk)) + dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); + } + if (IS_ERR(cdns_uart_data->pclk)) { + dev_err(&pdev->dev, "pclk clock not found.\n"); + return PTR_ERR(cdns_uart_data->pclk); + } + + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); + if (IS_ERR(cdns_uart_data->uartclk)) { + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk"); + if (!IS_ERR(cdns_uart_data->uartclk)) + dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); } - xuartps_data->refclk = clk_get(&pdev->dev, "ref_clk"); - if (IS_ERR(xuartps_data->refclk)) { - dev_err(&pdev->dev, "ref_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->refclk); - goto err_out_clk_put_aper; + if (IS_ERR(cdns_uart_data->uartclk)) { + dev_err(&pdev->dev, "uart_clk clock not found.\n"); + return PTR_ERR(cdns_uart_data->uartclk); } - rc = clk_prepare_enable(xuartps_data->aperclk); + rc = clk_prepare_enable(cdns_uart_data->pclk); if (rc) { - dev_err(&pdev->dev, "Unable to enable APER clock.\n"); - goto err_out_clk_put; + dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); + return rc; } - rc = clk_prepare_enable(xuartps_data->refclk); + rc = clk_prepare_enable(cdns_uart_data->uartclk); if (rc) { dev_err(&pdev->dev, "Unable to enable device clock.\n"); - goto err_out_clk_dis_aper; + goto err_out_clk_dis_pclk; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -989,13 +1345,25 @@ static int xuartps_probe(struct platform_device *pdev) goto err_out_clk_disable; } +#ifdef CONFIG_COMMON_CLK + cdns_uart_data->clk_rate_change_nb.notifier_call = + cdns_uart_clk_notifier_cb; + if (clk_notifier_register(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); +#endif + /* Look for a serialN alias */ + id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (id < 0) + id = 0; + /* Initialize the port structure */ - port = xuartps_get_port(); + port = cdns_uart_get_port(id); if (!port) { dev_err(&pdev->dev, "Cannot get uart_port structure\n"); rc = -ENODEV; - goto err_out_clk_disable; + goto err_out_notif_unreg; } else { /* Register the port. * This function also registers this device with the tty layer @@ -1004,116 +1372,104 @@ static int xuartps_probe(struct platform_device *pdev) port->mapbase = res->start; port->irq = res2->start; port->dev = &pdev->dev; - port->uartclk = clk_get_rate(xuartps_data->refclk); - port->private_data = xuartps_data; + port->uartclk = clk_get_rate(cdns_uart_data->uartclk); + port->private_data = cdns_uart_data; + cdns_uart_data->port = port; platform_set_drvdata(pdev, port); - rc = uart_add_one_port(&xuartps_uart_driver, port); + rc = uart_add_one_port(&cdns_uart_uart_driver, port); if (rc) { dev_err(&pdev->dev, "uart_add_one_port() failed; err=%i\n", rc); - goto err_out_clk_disable; + goto err_out_notif_unreg; } return 0; } +err_out_notif_unreg: +#ifdef CONFIG_COMMON_CLK + clk_notifier_unregister(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb); +#endif err_out_clk_disable: - clk_disable_unprepare(xuartps_data->refclk); -err_out_clk_dis_aper: - clk_disable_unprepare(xuartps_data->aperclk); -err_out_clk_put: - clk_put(xuartps_data->refclk); -err_out_clk_put_aper: - clk_put(xuartps_data->aperclk); -err_out_free: - kfree(xuartps_data); + clk_disable_unprepare(cdns_uart_data->uartclk); +err_out_clk_dis_pclk: + clk_disable_unprepare(cdns_uart_data->pclk); return rc; } /** - * xuartps_remove - called when the platform driver is unregistered + * cdns_uart_remove - called when the platform driver is unregistered * @pdev: Pointer to the platform device structure * - * Returns 0 on success, negative error otherwise - **/ -static int xuartps_remove(struct platform_device *pdev) + * Return: 0 on success, negative errno otherwise + */ +static int cdns_uart_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct xuartps *xuartps_data = port->private_data; + struct cdns_uart *cdns_uart_data = port->private_data; int rc; - /* Remove the xuartps port from the serial core */ - rc = uart_remove_one_port(&xuartps_uart_driver, port); + /* Remove the cdns_uart port from the serial core */ +#ifdef CONFIG_COMMON_CLK + clk_notifier_unregister(cdns_uart_data->uartclk, + &cdns_uart_data->clk_rate_change_nb); +#endif + rc = uart_remove_one_port(&cdns_uart_uart_driver, port); port->mapbase = 0; - clk_disable_unprepare(xuartps_data->refclk); - clk_disable_unprepare(xuartps_data->aperclk); - clk_put(xuartps_data->refclk); - clk_put(xuartps_data->aperclk); - kfree(xuartps_data); + clk_disable_unprepare(cdns_uart_data->uartclk); + clk_disable_unprepare(cdns_uart_data->pclk); return rc; } /* Match table for of_platform binding */ -static struct of_device_id xuartps_of_match[] = { +static struct of_device_id cdns_uart_of_match[] = { { .compatible = "xlnx,xuartps", }, + { .compatible = "cdns,uart-r1p8", }, {} }; -MODULE_DEVICE_TABLE(of, xuartps_of_match); +MODULE_DEVICE_TABLE(of, cdns_uart_of_match); -static struct platform_driver xuartps_platform_driver = { - .probe = xuartps_probe, /* Probe method */ - .remove = xuartps_remove, /* Detach method */ +static struct platform_driver cdns_uart_platform_driver = { + .probe = cdns_uart_probe, + .remove = cdns_uart_remove, .driver = { .owner = THIS_MODULE, - .name = XUARTPS_NAME, /* Driver name */ - .of_match_table = xuartps_of_match, + .name = CDNS_UART_NAME, + .of_match_table = cdns_uart_of_match, + .pm = &cdns_uart_dev_pm_ops, }, }; -/* --------------------------------------------------------------------- - * Module Init and Exit - */ -/** - * xuartps_init - Initial driver registration call - * - * Returns whether the registration was successful or not - **/ -static int __init xuartps_init(void) +static int __init cdns_uart_init(void) { int retval = 0; - /* Register the xuartps driver with the serial core */ - retval = uart_register_driver(&xuartps_uart_driver); + /* Register the cdns_uart driver with the serial core */ + retval = uart_register_driver(&cdns_uart_uart_driver); if (retval) return retval; /* Register the platform driver */ - retval = platform_driver_register(&xuartps_platform_driver); + retval = platform_driver_register(&cdns_uart_platform_driver); if (retval) - uart_unregister_driver(&xuartps_uart_driver); + uart_unregister_driver(&cdns_uart_uart_driver); return retval; } -/** - * xuartps_exit - Driver unregistration call - **/ -static void __exit xuartps_exit(void) +static void __exit cdns_uart_exit(void) { - /* The order of unregistration is important. Unregister the - * UART driver before the platform driver crashes the system. - */ - /* Unregister the platform driver */ - platform_driver_unregister(&xuartps_platform_driver); + platform_driver_unregister(&cdns_uart_platform_driver); - /* Unregister the xuartps driver */ - uart_unregister_driver(&xuartps_uart_driver); + /* Unregister the cdns_uart driver */ + uart_unregister_driver(&cdns_uart_uart_driver); } -module_init(xuartps_init); -module_exit(xuartps_exit); +module_init(cdns_uart_init); +module_exit(cdns_uart_exit); -MODULE_DESCRIPTION("Driver for PS UART"); +MODULE_DESCRIPTION("Driver for Cadence UART"); MODULE_AUTHOR("Xilinx Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 6a169877109..2b65bb7ffb8 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -923,7 +923,7 @@ static void zs_set_termios(struct uart_port *uport, struct ktermios *termios, uport->read_status_mask = Rx_OVR; if (termios->c_iflag & INPCK) uport->read_status_mask |= FRM_ERR | PAR_ERR; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) uport->read_status_mask |= Rx_BRK; uport->ignore_status_mask = 0; |
