aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/68328serial.c3
-rw-r--r--drivers/tty/serial/8250/8250_core.c27
-rw-r--r--drivers/tty/serial/8250/8250_dw.c19
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c266
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c230
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c119
-rw-r--r--drivers/tty/serial/8250/8250_omap.c65
-rw-r--r--drivers/tty/serial/8250/8250_pci.c41
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c257
-rw-r--r--drivers/tty/serial/8250/Kconfig24
-rw-r--r--drivers/tty/serial/8250/Makefile5
-rw-r--r--drivers/tty/serial/Kconfig74
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/altera_jtaguart.c2
-rw-r--r--drivers/tty/serial/altera_uart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c651
-rw-r--r--drivers/tty/serial/atmel_serial.c22
-rw-r--r--drivers/tty/serial/bfin_uart.c24
-rw-r--r--drivers/tty/serial/crisv10.c106
-rw-r--r--drivers/tty/serial/earlycon.c9
-rw-r--r--drivers/tty/serial/icom.c11
-rw-r--r--drivers/tty/serial/ifx6x60.c19
-rw-r--r--drivers/tty/serial/imx.c18
-rw-r--r--drivers/tty/serial/ioc3_serial.c3
-rw-r--r--drivers/tty/serial/ioc4_serial.c9
-rw-r--r--drivers/tty/serial/kgdb_nmi.c6
-rw-r--r--drivers/tty/serial/mcf.c2
-rw-r--r--drivers/tty/serial/meson_uart.c2
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c2
-rw-r--r--drivers/tty/serial/mpsc.c25
-rw-r--r--drivers/tty/serial/msm_smd_tty.c232
-rw-r--r--drivers/tty/serial/mxs-auart.c2
-rw-r--r--drivers/tty/serial/of_serial.c8
-rw-r--r--drivers/tty/serial/samsung.c4
-rw-r--r--drivers/tty/serial/sc16is7xx.c328
-rw-r--r--drivers/tty/serial/serial-tegra.c158
-rw-r--r--drivers/tty/serial/serial_core.c32
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c7
-rw-r--r--drivers/tty/serial/sh-sci.c136
-rw-r--r--drivers/tty/serial/sh-sci.h140
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c622
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h120
-rw-r--r--drivers/tty/serial/sprd_serial.c2
-rw-r--r--drivers/tty/serial/stm32-usart.c739
-rw-r--r--drivers/tty/serial/xilinx_uartps.c3
47 files changed, 3194 insertions, 1390 deletions
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 5dc9c4bfa66e..748c18f8c8cd 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
int i;
cflag = tty->termios.c_cflag;
- if (!(port = info->port))
+ port = info->port;
+ if (!port)
return;
ustcnt = uart->ustcnt;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 4506e405c8f3..37fff12dd4d0 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -85,19 +85,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define CONFIG_SERIAL_DETECT_IRQ 1
-#endif
-#ifdef CONFIG_SERIAL_8250_MANY_PORTS
-#define CONFIG_SERIAL_MANY_PORTS 1
-#endif
-
-/*
- * HUB6 is always on. This will be removed once the header
- * files have been cleaned.
- */
-#define CONFIG_HUB6 1
-
#include <asm/serial.h>
/*
* SERIAL_PORT_DFNS tells us about built-in ports that have no
@@ -2019,8 +2006,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
if (port->set_mctrl)
- return port->set_mctrl(port, mctrl);
- return serial8250_do_set_mctrl(port, mctrl);
+ port->set_mctrl(port, mctrl);
+ else
+ serial8250_do_set_mctrl(port, mctrl);
}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
@@ -3548,6 +3536,9 @@ static struct console univ8250_console = {
static int __init univ8250_console_init(void)
{
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
register_console(&univ8250_console);
return 0;
@@ -3578,7 +3569,7 @@ int __init early_serial_setup(struct uart_port *port)
{
struct uart_port *p;
- if (port->line >= ARRAY_SIZE(serial8250_ports))
+ if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0)
return -ENODEV;
serial8250_isa_init_ports();
@@ -3850,7 +3841,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.mapbase = up->port.mapbase;
uart->port.mapsize = up->port.mapsize;
uart->port.private_data = up->port.private_data;
- uart->port.fifosize = up->port.fifosize;
uart->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities;
uart->port.throttle = up->port.throttle;
@@ -3945,6 +3935,9 @@ static int __init serial8250_init(void)
{
int ret;
+ if (nr_uarts == 0)
+ return -ENODEV;
+
serial8250_isa_init_ports();
printk(KERN_INFO "Serial: 8250/16550 driver, "
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 176f18f2e3ab..d48b50641e9a 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -377,6 +377,16 @@ static int dw8250_probe_of(struct uart_port *p,
return 0;
}
+static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
+{
+ struct device *dev = param;
+
+ if (dev != chan->device->dev->parent)
+ return false;
+
+ return true;
+}
+
static int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
@@ -389,8 +399,15 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
- up->dma = &data->dma;
+ /* Platforms with iDMA */
+ if (platform_get_resource_byname(to_platform_device(up->port.dev),
+ IORESOURCE_MEM, "lpss_priv")) {
+ data->dma.rx_param = up->port.dev->parent;
+ data->dma.tx_param = up->port.dev->parent;
+ data->dma.fn = dw8250_idma_filter;
+ }
+ up->dma = &data->dma;
up->dma->rxconf.src_maxburst = p->fifosize / 4;
up->dma->txconf.dst_maxburst = p->fifosize / 4;
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 6c0fd8b9d1c3..771dda29a0f8 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -131,7 +131,7 @@ static void __init init_port(struct earlycon_device *device)
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
-static int __init early_serial8250_setup(struct earlycon_device *device,
+int __init early_serial8250_setup(struct earlycon_device *device,
const char *options)
{
if (!(device->port.membase || device->port.iobase))
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
new file mode 100644
index 000000000000..21bf81fe794f
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * Ingenic SoC UART support
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+struct ingenic_uart_data {
+ struct clk *clk_module;
+ struct clk *clk_baud;
+ int line;
+};
+
+#define UART_FCR_UME BIT(4)
+
+static struct earlycon_device *early_device;
+
+static uint8_t __init early_in(struct uart_port *port, int offset)
+{
+ return readl(port->membase + (offset << 2));
+}
+
+static void __init early_out(struct uart_port *port, int offset, uint8_t value)
+{
+ writel(value, port->membase + (offset << 2));
+}
+
+static void __init ingenic_early_console_putc(struct uart_port *port, int c)
+{
+ uint8_t lsr;
+
+ do {
+ lsr = early_in(port, UART_LSR);
+ } while ((lsr & UART_LSR_TEMT) == 0);
+
+ early_out(port, UART_TX, c);
+}
+
+static void __init ingenic_early_console_write(struct console *console,
+ const char *s, unsigned int count)
+{
+ uart_console_write(&early_device->port, s, count,
+ ingenic_early_console_putc);
+}
+
+static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev)
+{
+ void *fdt = initial_boot_params;
+ const __be32 *prop;
+ int offset;
+
+ offset = fdt_path_offset(fdt, "/ext");
+ if (offset < 0)
+ return;
+
+ prop = fdt_getprop(fdt, offset, "clock-frequency", NULL);
+ if (!prop)
+ return;
+
+ dev->port.uartclk = be32_to_cpup(prop);
+}
+
+static int __init ingenic_early_console_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ struct uart_port *port = &dev->port;
+ unsigned int baud, divisor;
+
+ if (!dev->port.membase)
+ return -ENODEV;
+
+ ingenic_early_console_setup_clock(dev);
+
+ baud = dev->baud ?: 115200;
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
+
+ early_out(port, UART_IER, 0);
+ early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+ early_out(port, UART_DLL, 0);
+ early_out(port, UART_DLM, 0);
+ early_out(port, UART_LCR, UART_LCR_WLEN8);
+ early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT |
+ UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO);
+ early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR);
+
+ early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+ early_out(port, UART_DLL, divisor & 0xff);
+ early_out(port, UART_DLM, (divisor >> 8) & 0xff);
+ early_out(port, UART_LCR, UART_LCR_WLEN8);
+
+ early_device = dev;
+ dev->con->write = ingenic_early_console_write;
+
+ return 0;
+}
+
+EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
+ ingenic_early_console_setup);
+
+EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
+ ingenic_early_console_setup);
+
+EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
+OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
+ ingenic_early_console_setup);
+
+static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
+{
+ switch (offset) {
+ case UART_FCR:
+ /* UART module enable */
+ value |= UART_FCR_UME;
+ break;
+
+ case UART_IER:
+ value |= (value & 0x4) << 2;
+ break;
+
+ default:
+ break;
+ }
+
+ writeb(value, p->membase + (offset << p->regshift));
+}
+
+static int ingenic_uart_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct ingenic_uart_data *data;
+ int err, line;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "no registers/irq defined\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.type = PORT_16550;
+ uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
+ uart.port.iotype = UPIO_MEM;
+ uart.port.mapbase = regs->start;
+ uart.port.regshift = 2;
+ uart.port.serial_out = ingenic_uart_serial_out;
+ uart.port.irq = irq->start;
+ uart.port.dev = &pdev->dev;
+
+ /* Check for a fixed line number */
+ line = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (line >= 0)
+ uart.port.line = line;
+
+ uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data->clk_module = devm_clk_get(&pdev->dev, "module");
+ if (IS_ERR(data->clk_module)) {
+ err = PTR_ERR(data->clk_module);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "unable to get module clock: %d\n", err);
+ return err;
+ }
+
+ data->clk_baud = devm_clk_get(&pdev->dev, "baud");
+ if (IS_ERR(data->clk_baud)) {
+ err = PTR_ERR(data->clk_baud);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "unable to get baud clock: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(data->clk_module);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable module clock: %d\n", err);
+ goto out;
+ }
+
+ err = clk_prepare_enable(data->clk_baud);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable baud clock: %d\n", err);
+ goto out_disable_moduleclk;
+ }
+ uart.port.uartclk = clk_get_rate(data->clk_baud);
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0) {
+ err = data->line;
+ goto out_disable_baudclk;
+ }
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+
+out_disable_baudclk:
+ clk_disable_unprepare(data->clk_baud);
+out_disable_moduleclk:
+ clk_disable_unprepare(data->clk_module);
+out:
+ return err;
+}
+
+static int ingenic_uart_remove(struct platform_device *pdev)
+{
+ struct ingenic_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ clk_disable_unprepare(data->clk_module);
+ clk_disable_unprepare(data->clk_baud);
+ return 0;
+}
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "ingenic,jz4740-uart" },
+ { .compatible = "ingenic,jz4775-uart" },
+ { .compatible = "ingenic,jz4780-uart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match);
+
+static struct platform_driver ingenic_uart_platform_driver = {
+ .driver = {
+ .name = "ingenic-uart",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match,
+ },
+ .probe = ingenic_uart_probe,
+ .remove = ingenic_uart_remove,
+};
+
+module_platform_driver(ingenic_uart_platform_driver);
+
+MODULE_AUTHOR("Paul Burton");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ingenic SoC UART driver");
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
new file mode 100644
index 000000000000..99cd478851ff
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -0,0 +1,230 @@
+/*
+ * Serial port driver for NXP LPC18xx/43xx UART
+ *
+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Based on 8250_mtk.c:
+ * Copyright (c) 2014 MundoReader S.L.
+ * Matthias Brugger <matthias.bgg@gmail.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/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+/* Additional LPC18xx/43xx 8250 registers and bits */
+#define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32))
+#define LPC18XX_UART_RS485CTRL_NMMEN BIT(0)
+#define LPC18XX_UART_RS485CTRL_DCTRL BIT(4)
+#define LPC18XX_UART_RS485CTRL_OINV BIT(5)
+#define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32))
+#define LPC18XX_UART_RS485DLY_MAX 255
+
+struct lpc18xx_uart_data {
+ struct uart_8250_dma dma;
+ struct clk *clk_uart;
+ struct clk *clk_reg;
+ int line;
+};
+
+static int lpc18xx_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u32 rs485_ctrl_reg = 0;
+ u32 rs485_dly_reg = 0;
+ unsigned baud_clk;
+
+ if (rs485->flags & SER_RS485_ENABLED)
+ memset(rs485->padding, 0, sizeof(rs485->padding));
+ else
+ memset(rs485, 0, sizeof(*rs485));
+
+ rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
+ LPC18XX_UART_RS485CTRL_DCTRL;
+
+ if (rs485->flags & SER_RS485_RTS_ON_SEND) {
+ rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
+ rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ } else {
+ rs485->flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+ }
+
+ if (rs485->delay_rts_after_send) {
+ baud_clk = port->uartclk / up->dl_read(up);
+ rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send
+ * baud_clk, MSEC_PER_SEC);
+
+ if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX)
+ rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX;
+
+ /* Calculate the resulting delay in ms */
+ rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC)
+ / baud_clk;
+ }
+
+ /* Delay RTS before send not supported */
+ rs485->delay_rts_before_send = 0;
+
+ serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
+ serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);
+
+ port->rs485 = *rs485;
+
+ return 0;
+}
+
+static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
+{
+ /*
+ * For DMA mode one must ensure that the UART_FCR_DMA_SELECT
+ * bit is set when FIFO is enabled. Even if DMA is not used
+ * setting this bit doesn't seem to affect anything.
+ */
+ if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO))
+ value |= UART_FCR_DMA_SELECT;
+
+ offset = offset << p->regshift;
+ writel(value, p->membase + offset);
+}
+
+static int lpc18xx_serial_probe(struct platform_device *pdev)
+{
+ struct lpc18xx_uart_data *data;
+ struct uart_8250_port uart;
+ struct resource *res;
+ int irq, ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "irq not found");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+
+ memset(&uart, 0, sizeof(uart));
+
+ uart.port.membase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!uart.port.membase)
+ return -ENOMEM;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->clk_uart = devm_clk_get(&pdev->dev, "uartclk");
+ if (IS_ERR(data->clk_uart)) {
+ dev_err(&pdev->dev, "uart clock not found\n");
+ return PTR_ERR(data->clk_uart);
+ }
+
+ data->clk_reg = devm_clk_get(&pdev->dev, "reg");
+ if (IS_ERR(data->clk_reg)) {
+ dev_err(&pdev->dev, "reg clock not found\n");
+ return PTR_ERR(data->clk_reg);
+ }
+
+ ret = clk_prepare_enable(data->clk_reg);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable reg clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk_uart);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock\n");
+ goto dis_clk_reg;
+ }
+
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ uart.port.line = ret;
+
+ data->dma.rx_param = data;
+ data->dma.tx_param = data;
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = irq;
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.mapbase = res->start;
+ uart.port.regshift = 2;
+ uart.port.type = PORT_16550A;
+ uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
+ uart.port.uartclk = clk_get_rate(data->clk_uart);
+ uart.port.private_data = data;
+ uart.port.rs485_config = lpc18xx_rs485_config;
+ uart.port.serial_out = lpc18xx_uart_serial_out;
+
+ uart.dma = &data->dma;
+ uart.dma->rxconf.src_maxburst = 1;
+ uart.dma->txconf.dst_maxburst = 1;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port\n");
+ goto dis_uart_clk;
+ }
+
+ data->line = ret;
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_uart_clk:
+ clk_disable_unprepare(data->clk_uart);
+dis_clk_reg:
+ clk_disable_unprepare(data->clk_reg);
+ return ret;
+}
+
+static int lpc18xx_serial_remove(struct platform_device *pdev)
+{
+ struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ clk_disable_unprepare(data->clk_uart);
+ clk_disable_unprepare(data->clk_reg);
+
+ return 0;
+}
+
+static const struct of_device_id lpc18xx_serial_match[] = {
+ { .compatible = "nxp,lpc1850-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc18xx_serial_match);
+
+static struct platform_driver lpc18xx_serial_driver = {
+ .probe = lpc18xx_serial_probe,
+ .remove = lpc18xx_serial_remove,
+ .driver = {
+ .name = "lpc18xx-uart",
+ .of_match_table = lpc18xx_serial_match,
+ },
+};
+module_platform_driver(lpc18xx_serial_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 7a11fac775c4..78883ca64ddd 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -34,6 +34,7 @@
struct mtk8250_data {
int line;
struct clk *uart_clk;
+ struct clk *bus_clk;
};
static void
@@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
tty_termios_encode_baud_rate(termios, baud, baud);
}
+static int mtk8250_runtime_suspend(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(data->uart_clk);
+ clk_disable_unprepare(data->bus_clk);
+
+ return 0;
+}
+
+static int mtk8250_runtime_resume(struct device *dev)
+{
+ struct mtk8250_data *data = dev_get_drvdata(dev);
+ int err;
+
+ err = clk_prepare_enable(data->uart_clk);
+ if (err) {
+ dev_warn(dev, "Can't enable clock\n");
+ return err;
+ }
+
+ err = clk_prepare_enable(data->bus_clk);
+ if (err) {
+ dev_warn(dev, "Can't enable bus clock\n");
+ return err;
+ }
+
+ return 0;
+}
+
static void
mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
@@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
struct mtk8250_data *data)
{
- int err;
- struct device_node *np = pdev->dev.of_node;
-
- data->uart_clk = of_clk_get(np, 0);
+ data->uart_clk = devm_clk_get(&pdev->dev, "baud");
if (IS_ERR(data->uart_clk)) {
- dev_warn(&pdev->dev, "Can't get timer clock\n");
- return PTR_ERR(data->uart_clk);
+ /*
+ * For compatibility with older device trees try unnamed
+ * clk when no baud clk can be found.
+ */
+ data->uart_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->uart_clk)) {
+ dev_warn(&pdev->dev, "Can't get uart clock\n");
+ return PTR_ERR(data->uart_clk);
+ }
+
+ return 0;
}
- err = clk_prepare_enable(data->uart_clk);
- if (err) {
- dev_warn(&pdev->dev, "Can't prepare clock\n");
- clk_put(data->uart_clk);
- return err;
- }
- p->uartclk = clk_get_rate(data->uart_clk);
+ data->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(data->bus_clk))
+ return PTR_ERR(data->bus_clk);
return 0;
}
@@ -190,19 +223,24 @@ static int mtk8250_probe(struct platform_device *pdev)
uart.port.regshift = 2;
uart.port.private_data = data;
uart.port.set_termios = mtk8250_set_termios;
+ uart.port.uartclk = clk_get_rate(data->uart_clk);
/* Disable Rate Fix function */
writel(0x0, uart.port.membase +
(MTK_UART_RATE_FIX << uart.port.regshift));
- data->line = serial8250_register_8250_port(&uart);
- if (data->line < 0)
- return data->line;
-
platform_set_drvdata(pdev, data);
- pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ err = mtk8250_runtime_resume(&pdev->dev);
+ if (err)
+ return err;
+ }
+
+ data->line = serial8250_register_8250_port(&uart);
+ if (data->line < 0)
+ return data->line;
return 0;
}
@@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
serial8250_unregister_port(data->line);
- if (!IS_ERR(data->uart_clk)) {
- clk_disable_unprepare(data->uart_clk);
- clk_put(data->uart_clk);
- }
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
+
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ mtk8250_runtime_suspend(&pdev->dev);
+
return 0;
}
@@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM
-static int mtk8250_runtime_suspend(struct device *dev)
-{
- struct mtk8250_data *data = dev_get_drvdata(dev);
-
- if (!IS_ERR(data->uart_clk))
- clk_disable_unprepare(data->uart_clk);
-
- return 0;
-}
-
-static int mtk8250_runtime_resume(struct device *dev)
-{
- struct mtk8250_data *data = dev_get_drvdata(dev);
-
- if (!IS_ERR(data->uart_clk))
- clk_prepare_enable(data->uart_clk);
-
- return 0;
-}
-#endif
-
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume,
@@ -289,6 +305,21 @@ static struct platform_driver mtk8250_platform_driver = {
};
module_platform_driver(mtk8250_platform_driver);
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init early_mtk8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->port.iotype = UPIO_MEM32;
+
+ return early_serial8250_setup(device, NULL);
+}
+
+OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
+#endif
+
MODULE_AUTHOR("Matthias Brugger");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index dce1a23706e8..978204333c94 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -98,6 +98,7 @@ struct omap8250_priv {
struct pm_qos_request pm_qos_request;
struct work_struct qos_work;
struct uart_8250_dma omap8250_dma;
+ spinlock_t rx_dma_lock;
};
static u32 uart_read(struct uart_8250_port *up, u32 reg)
@@ -726,14 +727,21 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
{
+ struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
struct tty_port *tty_port = &p->port.state->port;
struct dma_tx_state state;
int count;
+ unsigned long flags;
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
+ if (!dma->rx_running)
+ goto unlock;
+
dma->rx_running = 0;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
dmaengine_terminate_all(dma->rxchan);
@@ -742,6 +750,9 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
tty_insert_flip_string(tty_port, dma->rx_buf, count);
p->port.icount.rx += count;
+unlock:
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+
if (!error)
omap_8250_rx_dma(p, 0);
@@ -753,28 +764,45 @@ static void __dma_rx_complete(void *param)
__dma_rx_do_complete(param, false);
}
+static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
+{
+ struct omap8250_priv *priv = p->port.private_data;
+ struct uart_8250_dma *dma = p->dma;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
+ if (!dma->rx_running) {
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+ return;
+ }
+
+ dmaengine_pause(dma->rxchan);
+
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+
+ __dma_rx_do_complete(p, true);
+}
+
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
{
+ struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma;
+ int err = 0;
struct dma_async_tx_descriptor *desc;
+ unsigned long flags;
switch (iir & 0x3f) {
case UART_IIR_RLSI:
/* 8250_core handles errors and break interrupts */
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -EIO;
case UART_IIR_RX_TIMEOUT:
/*
* If RCVR FIFO trigger level was not reached, complete the
* transfer and let 8250_core copy the remaining data.
*/
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -ETIMEDOUT;
case UART_IIR_RDI:
/*
@@ -786,24 +814,25 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
* the DMA won't do anything soon so we have to cancel the DMA
* transfer and purge the FIFO manually.
*/
- if (dma->rx_running) {
- dmaengine_pause(dma->rxchan);
- __dma_rx_do_complete(p, true);
- }
+ omap_8250_rx_dma_flush(p);
return -ETIMEDOUT;
default:
break;
}
+ spin_lock_irqsave(&priv->rx_dma_lock, flags);
+
if (dma->rx_running)
- return 0;
+ goto out;
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- return -EBUSY;
+ if (!desc) {
+ err = -EBUSY;
+ goto out;
+ }
dma->rx_running = 1;
desc->callback = __dma_rx_complete;
@@ -815,7 +844,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
dma->rx_size, DMA_FROM_DEVICE);
dma_async_issue_pending(dma->rxchan);
- return 0;
+out:
+ spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
+ return err;
}
static int omap_8250_tx_dma(struct uart_8250_port *p);
@@ -1129,6 +1160,8 @@ static int omap8250_probe(struct platform_device *pdev)
priv->latency);
INIT_WORK(&priv->qos_work, omap8250_uart_qos_work);
+ spin_lock_init(&priv->rx_dma_lock);
+
device_init_wakeup(&pdev->dev, true);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 46bcebba54b2..e55f18b93fe7 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1823,6 +1823,9 @@ static int pci_eg20t_init(struct pci_dev *dev)
#endif
}
+#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
+#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
+
static int
pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1832,6 +1835,15 @@ pci_xr17c154_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx);
}
+static inline int
+xr17v35x_has_slave(struct serial_private *priv)
+{
+ const int dev_id = priv->dev->device;
+
+ return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) ||
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
+}
+
static int
pci_xr17v35x_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1846,6 +1858,13 @@ pci_xr17v35x_setup(struct serial_private *priv,
port->port.flags |= UPF_EXAR_EFR;
/*
+ * Setup the uart clock for the devices on expansion slot to
+ * half the clock speed of the main chip (which is 125MHz)
+ */
+ if (xr17v35x_has_slave(priv) && idx >= 8)
+ port->port.uartclk = (7812500 * 16 / 2);
+
+ /*
* Setup Multipurpose Input/Output pins.
*/
if (idx == 0) {
@@ -1998,8 +2017,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
-#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
-
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
@@ -2524,6 +2541,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
},
{
.vendor = PCI_VENDOR_ID_EXAR,
+ .device = PCI_DEVICE_ID_EXAR_XR17V4358,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_xr17v35x_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_EXAR,
.device = PCI_DEVICE_ID_EXAR_XR17V8358,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
@@ -3008,6 +3032,7 @@ enum pci_board_num_t {
pbn_exar_XR17V352,
pbn_exar_XR17V354,
pbn_exar_XR17V358,
+ pbn_exar_XR17V4358,
pbn_exar_XR17V8358,
pbn_exar_ibm_saturn,
pbn_pasemi_1682M,
@@ -3695,6 +3720,14 @@ static struct pciserial_board pci_boards[] = {
.reg_shift = 0,
.first_offset = 0,
},
+ [pbn_exar_XR17V4358] = {
+ .flags = FL_BASE0,
+ .num_ports = 12,
+ .base_baud = 7812500,
+ .uart_offset = 0x400,
+ .reg_shift = 0,
+ .first_offset = 0,
+ },
[pbn_exar_XR17V8358] = {
.flags = FL_BASE0,
.num_ports = 16,
@@ -5112,6 +5145,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_exar_XR17V358 },
+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V4358,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0,
+ 0, pbn_exar_XR17V4358 },
{ PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358,
PCI_ANY_ID, PCI_ANY_ID,
0,
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
new file mode 100644
index 000000000000..7d79425c2b09
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "8250.h"
+
+/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
+#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
+
+#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */
+#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */
+#define UNIPHIER_UART_LCR_SHIFT 8
+#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */
+
+struct uniphier8250_priv {
+ int line;
+ struct clk *clk;
+ spinlock_t atomic_write_lock;
+};
+
+/*
+ * The register map is slightly different from that of 8250.
+ * IO callbacks must be overridden for correct access to FCR, LCR, and MCR.
+ */
+static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
+{
+ unsigned int valshift = 0;
+
+ switch (offset) {
+ case UART_LCR:
+ valshift = UNIPHIER_UART_LCR_SHIFT;
+ /* fall through */
+ case UART_MCR:
+ offset = UNIPHIER_UART_LCR_MCR;
+ break;
+ default:
+ break;
+ }
+
+ offset <<= p->regshift;
+
+ /*
+ * The return value must be masked with 0xff because LCR and MCR reside
+ * in the same register that must be accessed by 32-bit write/read.
+ * 8 or 16 bit access to this hardware result in unexpected behavior.
+ */
+ return (readl(p->membase + offset) >> valshift) & 0xff;
+}
+
+static void uniphier_serial_out(struct uart_port *p, int offset, int value)
+{
+ unsigned int valshift = 0;
+ bool normal = false;
+
+ switch (offset) {
+ case UART_FCR:
+ offset = UNIPHIER_UART_CHAR_FCR;
+ break;
+ case UART_LCR:
+ valshift = UNIPHIER_UART_LCR_SHIFT;
+ /* Divisor latch access bit does not exist. */
+ value &= ~(UART_LCR_DLAB << valshift);
+ /* fall through */
+ case UART_MCR:
+ offset = UNIPHIER_UART_LCR_MCR;
+ break;
+ default:
+ normal = true;
+ break;
+ }
+
+ offset <<= p->regshift;
+
+ if (normal) {
+ writel(value, p->membase + offset);
+ } else {
+ /*
+ * Special case: two registers share the same address that
+ * must be 32-bit accessed. As this is not longer atomic safe,
+ * take a lock just in case.
+ */
+ struct uniphier8250_priv *priv = p->private_data;
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&priv->atomic_write_lock, flags);
+ tmp = readl(p->membase + offset);
+ tmp &= ~(0xff << valshift);
+ tmp |= value << valshift;
+ writel(tmp, p->membase + offset);
+ spin_unlock_irqrestore(&priv->atomic_write_lock, flags);
+ }
+}
+
+/*
+ * This hardware does not have the divisor latch access bit.
+ * The divisor latch register exists at different address.
+ * Override dl_read/write callbacks.
+ */
+static int uniphier_serial_dl_read(struct uart_8250_port *up)
+{
+ return readl(up->port.membase + UNIPHIER_UART_DLR);
+}
+
+static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ writel(value, up->port.membase + UNIPHIER_UART_DLR);
+}
+
+static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
+ struct uniphier8250_priv *priv)
+{
+ int ret;
+ u32 prop;
+ struct device_node *np = dev->of_node;
+
+ ret = of_alias_get_id(np, "serial");
+ if (ret < 0) {
+ dev_err(dev, "failed to get alias id\n");
+ return ret;
+ }
+ port->line = priv->line = ret;
+
+ /* Get clk rate through clk driver */
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret < 0)
+ return ret;
+
+ port->uartclk = clk_get_rate(priv->clk);
+
+ /* Check for fifo size */
+ if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ port->fifosize = prop;
+ else
+ port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
+
+ return 0;
+}
+
+static int uniphier_uart_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port up;
+ struct uniphier8250_priv *priv;
+ struct resource *regs;
+ void __iomem *membase;
+ int irq;
+ int ret;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(dev, "failed to get memory resource");
+ return -EINVAL;
+ }
+
+ membase = devm_ioremap(dev, regs->start, resource_size(regs));
+ if (!membase)
+ return -ENOMEM;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number");
+ return irq;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ memset(&up, 0, sizeof(up));
+
+ ret = uniphier_of_serial_setup(dev, &up.port, priv);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_init(&priv->atomic_write_lock);
+
+ up.port.dev = dev;
+ up.port.private_data = priv;
+ up.port.mapbase = regs->start;
+ up.port.mapsize = resource_size(regs);
+ up.port.membase = membase;
+ up.port.irq = irq;
+
+ up.port.type = PORT_16550A;
+ up.port.iotype = UPIO_MEM32;
+ up.port.regshift = 2;
+ up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ up.capabilities = UART_CAP_FIFO;
+
+ up.port.serial_in = uniphier_serial_in;
+ up.port.serial_out = uniphier_serial_out;
+ up.dl_read = uniphier_serial_dl_read;
+ up.dl_write = uniphier_serial_dl_write;
+
+ ret = serial8250_register_8250_port(&up);
+ if (ret < 0) {
+ dev_err(dev, "failed to register 8250 port\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int uniphier_uart_remove(struct platform_device *pdev)
+{
+ struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_uart_match[] = {
+ { .compatible = "socionext,uniphier-uart" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_uart_match);
+
+static struct platform_driver uniphier_uart_platform_driver = {
+ .probe = uniphier_uart_probe,
+ .remove = uniphier_uart_remove,
+ .driver = {
+ .name = "uniphier-uart",
+ .of_match_table = uniphier_uart_match,
+ },
+};
+module_platform_driver(uniphier_uart_platform_driver);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index c35070356528..e1de1181b322 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -336,9 +336,33 @@ config SERIAL_8250_FINTEK
LPC to 4 UART. This device has some RS485 functionality not available
through the PNP driver. If unsure, say N.
+config SERIAL_8250_LPC18XX
+ bool "NXP LPC18xx/43xx serial port support"
+ depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
+ default ARCH_LPC18XX
+ help
+ If you have a LPC18xx/43xx based board and want to use the
+ serial port, say Y to this option. If unsure, say Y.
+
config SERIAL_8250_MT6577
bool "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
serial port, say Y to this option. If unsure, say N.
+
+config SERIAL_8250_UNIPHIER
+ tristate "Support for UniPhier on-chip UART"
+ depends on SERIAL_8250 && ARCH_UNIPHIER
+ help
+ If you have a UniPhier based board and want to use the on-chip
+ serial ports, say Y to this option. If unsure, say N.
+
+config SERIAL_8250_INGENIC
+ bool "Support for Ingenic SoC serial ports"
+ depends on SERIAL_8250_CONSOLE && OF_FLATTREE
+ select LIBFDT
+ select SERIAL_EARLYCON
+ help
+ If you have a system using an Ingenic SoC and wish to make use of
+ its UARTs, say Y to this option. If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 31e7cdc6865c..706295913c34 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -22,4 +22,9 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
+obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
+obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
+
+CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index f8120c1bde14..76e65b714471 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -241,7 +241,6 @@ config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
- select SERIAL_EARLYCON
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
@@ -277,6 +276,7 @@ config SERIAL_SAMSUNG_CONSOLE
bool "Support for console on Samsung SoC serial port"
depends on SERIAL_SAMSUNG=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
@@ -728,7 +728,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support"
- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+ depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS
@@ -1179,15 +1179,42 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
+config SERIAL_SC16IS7XX_CORE
+ tristate
+
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.
+ tristate "SC16IS7xx serial support"
+ select SERIAL_CORE
+ depends on I2C || SPI_MASTER
+ help
+ This selects support for SC16IS7xx serial ports.
+ Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
+ SC16IS760 and SC16IS762. Select supported buses using options below.
+
+config SERIAL_SC16IS7XX_I2C
+ bool "SC16IS7xx for I2C interface"
+ depends on SERIAL_SC16IS7XX
+ depends on I2C
+ select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+ select REGMAP_I2C if I2C
+ default y
+ help
+ Enable SC16IS7xx driver on I2C bus,
+ If required say y, and say n to i2c if not required,
+ Enabled by default to support oldconfig.
+ You must select at least one bus for the driver to be built.
+
+config SERIAL_SC16IS7XX_SPI
+ bool "SC16IS7xx for spi interface"
+ depends on SERIAL_SC16IS7XX
+ depends on SPI_MASTER
+ select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
+ select REGMAP_SPI if SPI_MASTER
+ help
+ Enable SC16IS7xx driver on SPI bus,
+ If required say y, and say n to spi if not required,
+ This is additional support to exsisting driver.
+ You must select at least one bus for the driver to be built.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART"
@@ -1349,7 +1376,7 @@ config SERIAL_ALTERA_UART_CONSOLE
config SERIAL_IFX6X60
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
- depends on GPIOLIB && SPI
+ depends on GPIOLIB && SPI && HAS_DMA
help
Support for the IFX6x60 modem devices on Intel MID platforms.
@@ -1378,14 +1405,6 @@ config SERIAL_PCH_UART_CONSOLE
(the system console is the device which receives all kernel messages and
warnings and which allows logins in single user mode).
-config SERIAL_MSM_SMD
- bool "Enable tty device interface for some SMD ports"
- default n
- depends on MSM_SMD
- help
- Enables userspace clients to read and write to some streaming SMD
- ports via tty device interface for MSM chipset.
-
config SERIAL_MXS_AUART
depends on ARCH_MXS
tristate "MXS AUART support"
@@ -1589,6 +1608,23 @@ config SERIAL_SPRD_CONSOLE
with "earlycon" on the kernel command line. The console is
enabled when early_param is processed.
+config SERIAL_STM32
+ tristate "STMicroelectronics STM32 serial port support"
+ select SERIAL_CORE
+ depends on ARM || COMPILE_TEST
+ help
+ This driver is for the on-chip Serial Controller on
+ STMicroelectronics STM32 MCUs.
+ USART supports Rx & Tx functionality.
+ It support all industry standard baud rates.
+
+ If unsure, say N.
+
+config SERIAL_STM32_CONSOLE
+ bool "Support for console on STM32"
+ depends on SERIAL_STM32=y
+ select SERIAL_CORE_CONSOLE
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index c3ac3d930b33..5ab41119b3dc 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -53,7 +53,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
-obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
+obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
@@ -79,7 +79,6 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
-obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
@@ -93,6 +92,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 0fefdd8931a2..32df2a0cb060 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init);
#define ALTERA_JTAGUART_CONSOLE NULL
-#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
+#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index b2859fe07e14..fd87a6f574e3 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init);
#define ALTERA_UART_CONSOLE NULL
-#endif /* CONFIG_ALTERA_UART_CONSOLE */
+#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */
/*
* Define the altera_uart UART driver structure.
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 763eb20fe321..50cf5b10ceed 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -58,7 +58,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
#include <linux/io.h>
-#include <linux/workqueue.h>
+#include <linux/acpi.h>
#define UART_NR 14
@@ -79,6 +79,8 @@ struct vendor_data {
bool oversampling;
bool dma_threshold;
bool cts_event_workaround;
+ bool always_enabled;
+ bool fixed_options;
unsigned int (*get_fifosize)(struct amba_device *dev);
};
@@ -95,9 +97,19 @@ static struct vendor_data vendor_arm = {
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
+ .always_enabled = false,
+ .fixed_options = false,
.get_fifosize = get_fifosize_arm,
};
+static struct vendor_data vendor_sbsa = {
+ .oversampling = false,
+ .dma_threshold = false,
+ .cts_event_workaround = false,
+ .always_enabled = true,
+ .fixed_options = true,
+};
+
static unsigned int get_fifosize_st(struct amba_device *dev)
{
return 64;
@@ -110,6 +122,8 @@ static struct vendor_data vendor_st = {
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
+ .always_enabled = false,
+ .fixed_options = false,
.get_fifosize = get_fifosize_st,
};
@@ -157,9 +171,8 @@ struct uart_amba_port {
unsigned int lcrh_tx; /* vendor-specific */
unsigned int lcrh_rx; /* vendor-specific */
unsigned int old_cr; /* state during shutdown */
- struct delayed_work tx_softirq_work;
bool autorts;
- unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */
+ unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
@@ -1172,15 +1185,14 @@ static void pl011_stop_tx(struct uart_port *port)
pl011_dma_tx_stop(uap);
}
-static bool pl011_tx_chars(struct uart_amba_port *uap);
+static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
/* Start TX with programmed I/O only (no DMA) */
static void pl011_start_tx_pio(struct uart_amba_port *uap)
{
uap->im |= UART011_TXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
- if (!uap->tx_irq_seen)
- pl011_tx_chars(uap);
+ pl011_tx_chars(uap, false);
}
static void pl011_start_tx(struct uart_port *port)
@@ -1247,15 +1259,11 @@ __acquires(&uap->port.lock)
spin_lock(&uap->port.lock);
}
-/*
- * Transmit a character
- *
- * Returns true if the character was successfully queued to the FIFO.
- * Returns false otherwise.
- */
-static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
+static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
+ bool from_irq)
{
- if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
+ if (unlikely(!from_irq) &&
+ readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
return false; /* unable to transmit character */
writew(c, uap->port.membase + UART01x_DR);
@@ -1264,70 +1272,41 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
return true;
}
-static bool pl011_tx_chars(struct uart_amba_port *uap)
+static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
{
struct circ_buf *xmit = &uap->port.state->xmit;
- int count;
-
- if (unlikely(uap->tx_irq_seen < 2))
- /*
- * Initial FIFO fill level unknown: we must check TXFF
- * after each write, so just try to fill up the FIFO.
- */
- count = uap->fifosize;
- else /* tx_irq_seen >= 2 */
- /*
- * FIFO initially at least half-empty, so we can simply
- * write half the FIFO without polling TXFF.
-
- * Note: the *first* TX IRQ can still race with
- * pl011_start_tx_pio(), which can result in the FIFO
- * being fuller than expected in that case.
- */
- count = uap->fifosize >> 1;
-
- /*
- * If the FIFO is full we're guaranteed a TX IRQ at some later point,
- * and can't transmit immediately in any case:
- */
- if (unlikely(uap->tx_irq_seen < 2 &&
- readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF))
- return false;
+ int count = uap->fifosize >> 1;
if (uap->port.x_char) {
- if (!pl011_tx_char(uap, uap->port.x_char))
- goto done;
+ if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
+ return;
uap->port.x_char = 0;
--count;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
pl011_stop_tx(&uap->port);
- goto done;
+ return;
}
/* If we are using DMA mode, try to send some characters. */
if (pl011_dma_tx_irq(uap))
- goto done;
+ return;
- while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) {
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- if (uart_circ_empty(xmit))
+ do {
+ if (likely(from_irq) && count-- == 0)
break;
- }
+
+ if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ break;
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ } while (!uart_circ_empty(xmit));
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
- if (uart_circ_empty(xmit)) {
+ if (uart_circ_empty(xmit))
pl011_stop_tx(&uap->port);
- goto done;
- }
-
- if (unlikely(!uap->tx_irq_seen))
- schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout);
-
-done:
- return false;
}
static void pl011_modem_status(struct uart_amba_port *uap)
@@ -1354,26 +1333,23 @@ static void pl011_modem_status(struct uart_amba_port *uap)
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
}
-static void pl011_tx_softirq(struct work_struct *work)
+static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
{
- struct delayed_work *dwork = to_delayed_work(work);
- struct uart_amba_port *uap =
- container_of(dwork, struct uart_amba_port, tx_softirq_work);
-
- spin_lock(&uap->port.lock);
- while (pl011_tx_chars(uap)) ;
- spin_unlock(&uap->port.lock);
-}
+ unsigned int dummy_read;
-static void pl011_tx_irq_seen(struct uart_amba_port *uap)
-{
- if (likely(uap->tx_irq_seen > 1))
+ if (!uap->vendor->cts_event_workaround)
return;
- uap->tx_irq_seen++;
- if (uap->tx_irq_seen < 2)
- /* first TX IRQ */
- cancel_delayed_work(&uap->tx_softirq_work);
+ /* workaround to make sure that all bits are unlocked.. */
+ writew(0x00, uap->port.membase + UART011_ICR);
+
+ /*
+ * WA: introduce 26ns(1 uart clk) delay before W1C;
+ * single apb access will incur 2 pclk(133.12Mhz) delay,
+ * so add 2 dummy reads
+ */
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = readw(uap->port.membase + UART011_ICR);
}
static irqreturn_t pl011_int(int irq, void *dev_id)
@@ -1381,25 +1357,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
struct uart_amba_port *uap = dev_id;
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+ u16 imsc;
int handled = 0;
- unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
- status = readw(uap->port.membase + UART011_MIS);
+ imsc = readw(uap->port.membase + UART011_IMSC);
+ status = readw(uap->port.membase + UART011_RIS) & imsc;
if (status) {
do {
- if (uap->vendor->cts_event_workaround) {
- /* workaround to make sure that all bits are unlocked.. */
- writew(0x00, uap->port.membase + UART011_ICR);
-
- /*
- * WA: introduce 26ns(1 uart clk) delay before W1C;
- * single apb access will incur 2 pclk(133.12Mhz) delay,
- * so add 2 dummy reads
- */
- dummy_read = readw(uap->port.membase + UART011_ICR);
- dummy_read = readw(uap->port.membase + UART011_ICR);
- }
+ check_apply_cts_event_workaround(uap);
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
@@ -1414,15 +1380,13 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
- if (status & UART011_TXIS) {
- pl011_tx_irq_seen(uap);
- pl011_tx_chars(uap);
- }
+ if (status & UART011_TXIS)
+ pl011_tx_chars(uap, true);
if (pass_counter-- == 0)
break;
- status = readw(uap->port.membase + UART011_MIS);
+ status = readw(uap->port.membase + UART011_RIS) & imsc;
} while (status != 0);
handled = 1;
}
@@ -1617,6 +1581,32 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
}
}
+static int pl011_allocate_irq(struct uart_amba_port *uap)
+{
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+}
+
+/*
+ * Enable interrupts, only timeouts when using DMA
+ * if initial RX DMA job failed, start in interrupt mode
+ * as well.
+ */
+static void pl011_enable_interrupts(struct uart_amba_port *uap)
+{
+ spin_lock_irq(&uap->port.lock);
+
+ /* Clear out any spuriously appearing RX interrupts */
+ writew(UART011_RTIS | UART011_RXIS,
+ uap->port.membase + UART011_ICR);
+ uap->im = UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ spin_unlock_irq(&uap->port.lock);
+}
+
static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1628,20 +1618,12 @@ static int pl011_startup(struct uart_port *port)
if (retval)
goto clk_dis;
- writew(uap->im, uap->port.membase + UART011_IMSC);
-
- /*
- * Allocate the IRQ
- */
- retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
+ retval = pl011_allocate_irq(uap);
if (retval)
goto clk_dis;
writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
- /* Assume that TX IRQ doesn't work until we see one: */
- uap->tx_irq_seen = 0;
-
spin_lock_irq(&uap->port.lock);
/* restore RTS and DTR */
@@ -1659,20 +1641,7 @@ static int pl011_startup(struct uart_port *port)
/* Startup DMA */
pl011_dma_startup(uap);
- /*
- * Finally, enable interrupts, only timeouts when using DMA
- * if initial RX DMA job failed, start in interrupt mode
- * as well.
- */
- spin_lock_irq(&uap->port.lock);
- /* Clear out any spuriously appearing RX interrupts */
- writew(UART011_RTIS | UART011_RXIS,
- uap->port.membase + UART011_ICR);
- uap->im = UART011_RTIM;
- if (!pl011_dma_rx_running(uap))
- uap->im |= UART011_RXIM;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- spin_unlock_irq(&uap->port.lock);
+ pl011_enable_interrupts(uap);
return 0;
@@ -1681,6 +1650,28 @@ static int pl011_startup(struct uart_port *port)
return retval;
}
+static int sbsa_uart_startup(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ int retval;
+
+ retval = pl011_hwinit(port);
+ if (retval)
+ return retval;
+
+ retval = pl011_allocate_irq(uap);
+ if (retval)
+ return retval;
+
+ /* The SBSA UART does not support any modem status lines. */
+ uap->old_status = 0;
+
+ pl011_enable_interrupts(uap);
+
+ return 0;
+}
+
static void pl011_shutdown_channel(struct uart_amba_port *uap,
unsigned int lcrh)
{
@@ -1691,36 +1682,15 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
writew(val, uap->port.membase + lcrh);
}
-static void pl011_shutdown(struct uart_port *port)
+/*
+ * disable the port. It should not disable RTS and DTR.
+ * Also RTS and DTR state should be preserved to restore
+ * it during startup().
+ */
+static void pl011_disable_uart(struct uart_amba_port *uap)
{
- struct uart_amba_port *uap =
- container_of(port, struct uart_amba_port, port);
unsigned int cr;
- cancel_delayed_work_sync(&uap->tx_softirq_work);
-
- /*
- * disable all interrupts
- */
- spin_lock_irq(&uap->port.lock);
- uap->im = 0;
- writew(uap->im, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
- spin_unlock_irq(&uap->port.lock);
-
- pl011_dma_shutdown(uap);
-
- /*
- * Free the interrupt
- */
- free_irq(uap->port.irq, uap);
-
- /*
- * disable the port
- * disable the port. It should not disable RTS and DTR.
- * Also RTS and DTR state should be preserved to restore
- * it during startup().
- */
uap->autorts = false;
spin_lock_irq(&uap->port.lock);
cr = readw(uap->port.membase + UART011_CR);
@@ -1736,6 +1706,32 @@ static void pl011_shutdown(struct uart_port *port)
pl011_shutdown_channel(uap, uap->lcrh_rx);
if (uap->lcrh_rx != uap->lcrh_tx)
pl011_shutdown_channel(uap, uap->lcrh_tx);
+}
+
+static void pl011_disable_interrupts(struct uart_amba_port *uap)
+{
+ spin_lock_irq(&uap->port.lock);
+
+ /* mask all interrupts and clear all pending ones */
+ uap->im = 0;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ writew(0xffff, uap->port.membase + UART011_ICR);
+
+ spin_unlock_irq(&uap->port.lock);
+}
+
+static void pl011_shutdown(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ pl011_disable_interrupts(uap);
+
+ pl011_dma_shutdown(uap);
+
+ free_irq(uap->port.irq, uap);
+
+ pl011_disable_uart(uap);
/*
* Shut down the clock producer
@@ -1756,6 +1752,51 @@ static void pl011_shutdown(struct uart_port *port)
uap->port.ops->flush_buffer(port);
}
+static void sbsa_uart_shutdown(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ pl011_disable_interrupts(uap);
+
+ free_irq(uap->port.irq, uap);
+
+ if (uap->port.ops->flush_buffer)
+ uap->port.ops->flush_buffer(port);
+}
+
+static void
+pl011_setup_status_masks(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 & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= UART011_DR_BE;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= UART011_DR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART011_DR_OE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_DR_RX;
+}
+
static void
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
@@ -1820,33 +1861,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- 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 & (IGNBRK | BRKINT | PARMRK))
- port->read_status_mask |= UART011_DR_BE;
-
- /*
- * Characters to ignore
- */
- port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
- if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= UART011_DR_BE;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART011_DR_OE;
- }
-
- /*
- * Ignore all characters if CREAD is not set.
- */
- if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= UART_DUMMY_DR_RX;
+ pl011_setup_status_masks(port, termios);
if (UART_ENABLE_MS(port, termios->c_cflag))
pl011_enable_ms(port);
@@ -1901,6 +1916,27 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&port->lock, flags);
}
+static void
+sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+ unsigned long flags;
+
+ tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
+
+ /* The SBSA UART only supports 8n1 without hardware flow control. */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+ termios->c_cflag |= CS8 | CLOCAL;
+
+ spin_lock_irqsave(&port->lock, flags);
+ uart_update_timeout(port, CS8, uap->fixed_baud);
+ pl011_setup_status_masks(port, termios);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
static const char *pl011_type(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1976,6 +2012,37 @@ static struct uart_ops amba_pl011_pops = {
#endif
};
+static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static const struct uart_ops sbsa_uart_pops = {
+ .tx_empty = pl011_tx_empty,
+ .set_mctrl = sbsa_uart_set_mctrl,
+ .get_mctrl = sbsa_uart_get_mctrl,
+ .stop_tx = pl011_stop_tx,
+ .start_tx = pl011_start_tx,
+ .stop_rx = pl011_stop_rx,
+ .startup = sbsa_uart_startup,
+ .shutdown = sbsa_uart_shutdown,
+ .set_termios = sbsa_uart_set_termios,
+ .type = pl011_type,
+ .release_port = pl011_release_port,
+ .request_port = pl011_request_port,
+ .config_port = pl011_config_port,
+ .verify_port = pl011_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = pl011_hwinit,
+ .poll_get_char = pl011_get_poll_char,
+ .poll_put_char = pl011_put_poll_char,
+#endif
+};
+
static struct uart_amba_port *amba_ports[UART_NR];
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
@@ -1994,7 +2061,7 @@ static void
pl011_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int status, old_cr, new_cr;
+ unsigned int status, old_cr = 0, new_cr;
unsigned long flags;
int locked = 1;
@@ -2011,10 +2078,12 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
/*
* First save the CR then disable the interrupts
*/
- old_cr = readw(uap->port.membase + UART011_CR);
- new_cr = old_cr & ~UART011_CR_CTSEN;
- new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- writew(new_cr, uap->port.membase + UART011_CR);
+ if (!uap->vendor->always_enabled) {
+ old_cr = readw(uap->port.membase + UART011_CR);
+ new_cr = old_cr & ~UART011_CR_CTSEN;
+ new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
+ writew(new_cr, uap->port.membase + UART011_CR);
+ }
uart_console_write(&uap->port, s, count, pl011_console_putchar);
@@ -2025,7 +2094,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
do {
status = readw(uap->port.membase + UART01x_FR);
} while (status & UART01x_FR_BUSY);
- writew(old_cr, uap->port.membase + UART011_CR);
+ if (!uap->vendor->always_enabled)
+ writew(old_cr, uap->port.membase + UART011_CR);
if (locked)
spin_unlock(&uap->port.lock);
@@ -2106,10 +2176,15 @@ static int __init pl011_console_setup(struct console *co, char *options)
uap->port.uartclk = clk_get_rate(uap->clk);
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
- else
- pl011_console_get_options(uap, &baud, &parity, &bits);
+ if (uap->vendor->fixed_options) {
+ baud = uap->fixed_baud;
+ } else {
+ if (options)
+ uart_parse_options(options,
+ &baud, &parity, &bits, &flow);
+ else
+ pl011_console_get_options(uap, &baud, &parity, &bits);
+ }
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
@@ -2201,97 +2276,126 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
return ret;
}
-static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+/* unregisters the driver also if no more ports are left */
+static void pl011_unregister_port(struct uart_amba_port *uap)
{
- struct uart_amba_port *uap;
- struct vendor_data *vendor = id->data;
- void __iomem *base;
- int i, ret;
+ int i;
+ bool busy = false;
+
+ 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);
+}
+
+static int pl011_find_free_port(void)
+{
+ int i;
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
if (amba_ports[i] == NULL)
- break;
-
- if (i == ARRAY_SIZE(amba_ports))
- return -EBUSY;
+ return i;
- uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
- GFP_KERNEL);
- if (uap == NULL)
- return -ENOMEM;
+ return -EBUSY;
+}
- i = pl011_probe_dt_alias(i, &dev->dev);
+static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
+ struct resource *mmiobase, int index)
+{
+ void __iomem *base;
- base = devm_ioremap(&dev->dev, dev->res.start,
- resource_size(&dev->res));
+ base = devm_ioremap_resource(dev, mmiobase);
if (!base)
return -ENOMEM;
- uap->clk = devm_clk_get(&dev->dev, NULL);
- if (IS_ERR(uap->clk))
- return PTR_ERR(uap->clk);
+ index = pl011_probe_dt_alias(index, dev);
- uap->vendor = vendor;
- uap->lcrh_rx = vendor->lcrh_rx;
- uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
- uap->fifosize = vendor->get_fifosize(dev);
- uap->port.dev = &dev->dev;
- uap->port.mapbase = dev->res.start;
+ uap->port.dev = dev;
+ uap->port.mapbase = mmiobase->start;
uap->port.membase = base;
uap->port.iotype = UPIO_MEM;
- uap->port.irq = dev->irq[0];
uap->port.fifosize = uap->fifosize;
- uap->port.ops = &amba_pl011_pops;
uap->port.flags = UPF_BOOT_AUTOCONF;
- uap->port.line = i;
- INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
+ uap->port.line = index;
- /* Ensure interrupts from this UART are masked and cleared */
- writew(0, uap->port.membase + UART011_IMSC);
- writew(0xffff, uap->port.membase + UART011_ICR);
+ amba_ports[index] = uap;
- snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+ return 0;
+}
- amba_ports[i] = uap;
+static int pl011_register_port(struct uart_amba_port *uap)
+{
+ int ret;
- amba_set_drvdata(dev, uap);
+ /* Ensure interrupts from this UART are masked and cleared */
+ writew(0, uap->port.membase + UART011_IMSC);
+ writew(0xffff, uap->port.membase + UART011_ICR);
if (!amba_reg.state) {
ret = uart_register_driver(&amba_reg);
if (ret < 0) {
- dev_err(&dev->dev,
+ dev_err(uap->port.dev,
"Failed to register AMBA-PL011 driver\n");
return ret;
}
}
ret = uart_add_one_port(&amba_reg, &uap->port);
- if (ret) {
- amba_ports[i] = NULL;
- uart_unregister_driver(&amba_reg);
- }
+ if (ret)
+ pl011_unregister_port(uap);
return ret;
}
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+{
+ struct uart_amba_port *uap;
+ struct vendor_data *vendor = id->data;
+ int portnr, ret;
+
+ portnr = pl011_find_free_port();
+ if (portnr < 0)
+ return portnr;
+
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
+ if (!uap)
+ return -ENOMEM;
+
+ uap->clk = devm_clk_get(&dev->dev, NULL);
+ if (IS_ERR(uap->clk))
+ return PTR_ERR(uap->clk);
+
+ uap->vendor = vendor;
+ uap->lcrh_rx = vendor->lcrh_rx;
+ uap->lcrh_tx = vendor->lcrh_tx;
+ uap->fifosize = vendor->get_fifosize(dev);
+ uap->port.irq = dev->irq[0];
+ uap->port.ops = &amba_pl011_pops;
+
+ snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
+
+ ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
+ if (ret)
+ return ret;
+
+ amba_set_drvdata(dev, uap);
+
+ return pl011_register_port(uap);
+}
+
static int pl011_remove(struct amba_device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
- bool busy = false;
- int i;
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);
+ pl011_unregister_port(uap);
return 0;
}
@@ -2319,6 +2423,86 @@ static int pl011_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
+static int sbsa_uart_probe(struct platform_device *pdev)
+{
+ struct uart_amba_port *uap;
+ struct resource *r;
+ int portnr, ret;
+ int baudrate;
+
+ /*
+ * Check the mandatory baud rate parameter in the DT node early
+ * so that we can easily exit with the error.
+ */
+ if (pdev->dev.of_node) {
+ struct device_node *np = pdev->dev.of_node;
+
+ ret = of_property_read_u32(np, "current-speed", &baudrate);
+ if (ret)
+ return ret;
+ } else {
+ baudrate = 115200;
+ }
+
+ portnr = pl011_find_free_port();
+ if (portnr < 0)
+ return portnr;
+
+ uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
+ if (!uap)
+ return -ENOMEM;
+
+ uap->vendor = &vendor_sbsa;
+ uap->fifosize = 32;
+ uap->port.irq = platform_get_irq(pdev, 0);
+ uap->port.ops = &sbsa_uart_pops;
+ uap->fixed_baud = baudrate;
+
+ snprintf(uap->type, sizeof(uap->type), "SBSA");
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, uap);
+
+ return pl011_register_port(uap);
+}
+
+static int sbsa_uart_remove(struct platform_device *pdev)
+{
+ struct uart_amba_port *uap = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&amba_reg, &uap->port);
+ pl011_unregister_port(uap);
+ return 0;
+}
+
+static const struct of_device_id sbsa_uart_of_match[] = {
+ { .compatible = "arm,sbsa-uart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
+
+static const struct acpi_device_id sbsa_uart_acpi_match[] = {
+ { "ARMH0011", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
+
+static struct platform_driver arm_sbsa_uart_platform_driver = {
+ .probe = sbsa_uart_probe,
+ .remove = sbsa_uart_remove,
+ .driver = {
+ .name = "sbsa-uart",
+ .of_match_table = of_match_ptr(sbsa_uart_of_match),
+ .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
+ },
+};
+
static struct amba_id pl011_ids[] = {
{
.id = 0x00041011,
@@ -2349,11 +2533,14 @@ static int __init pl011_init(void)
{
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
+ if (platform_driver_register(&arm_sbsa_uart_platform_driver))
+ pr_warn("could not register SBSA UART platform driver\n");
return amba_driver_register(&pl011_driver);
}
static void __exit pl011_exit(void)
{
+ platform_driver_unregister(&arm_sbsa_uart_platform_driver);
amba_driver_unregister(&pl011_driver);
}
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 27dade29646b..2a8f528153e7 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -165,6 +165,7 @@ struct atmel_uart_port {
struct tasklet_struct tasklet;
unsigned int irq_status;
unsigned int irq_status_prev;
+ unsigned int status_change;
struct circ_buf rx_ring;
@@ -315,8 +316,7 @@ static int atmel_config_rs485(struct uart_port *port,
if (rs485conf->flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
- if ((rs485conf->delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
+ UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else {
dev_dbg(port->dev, "Setting UART to RS232\n");
@@ -354,8 +354,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
/* override mode to RS485 if needed, otherwise keep the current mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
- if ((port->rs485.delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode &= ~ATMEL_US_USMODE;
mode |= ATMEL_US_USMODE_RS485;
}
@@ -1177,6 +1176,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
| ATMEL_US_CTSIC)) {
atmel_port->irq_status = status;
+ atmel_port->status_change = atmel_port->irq_status ^
+ atmel_port->irq_status_prev;
+ atmel_port->irq_status_prev = status;
tasklet_schedule(&atmel_port->tasklet);
}
}
@@ -1523,17 +1525,14 @@ static void atmel_tasklet_func(unsigned long data)
{
struct uart_port *port = (struct uart_port *)data;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- unsigned int status;
- unsigned int status_change;
+ unsigned int status = atmel_port->irq_status;
+ unsigned int status_change = atmel_port->status_change;
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
atmel_port->schedule_tx(port);
- status = atmel_port->irq_status;
- status_change = status ^ atmel_port->irq_status_prev;
-
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
| ATMEL_US_DCD | ATMEL_US_CTS)) {
/* TODO: All reads to CSR will clear these interrupts! */
@@ -1548,7 +1547,7 @@ static void atmel_tasklet_func(unsigned long data)
wake_up_interruptible(&port->state->port.delta_msr_wait);
- atmel_port->irq_status_prev = status;
+ atmel_port->status_change = 0;
}
atmel_port->schedule_rx(port);
@@ -2061,8 +2060,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
/* mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
- if ((port->rs485.delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 155781ece050..ae3cf94b146b 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
static void bfin_serial_reset_irda(struct uart_port *port);
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
struct bfin_serial_port *uart = dev_id;
struct uart_port *uport = &uart->port;
unsigned int status = bfin_serial_get_mctrl(uport);
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
UART_CLEAR_SCTS(uart);
if (uport->hw_stopped) {
@@ -700,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port)
# endif
#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0) {
if (request_irq(gpio_to_irq(uart->cts_pin),
bfin_serial_mctrl_cts_int,
@@ -718,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port)
gpio_direction_output(uart->rts_pin, 0);
}
#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0) {
if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
0, "BFIN_UART_MODEM_STATUS", uart)) {
@@ -766,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port)
free_irq(uart->tx_irq, uart);
#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (uart->cts_pin >= 0)
free_irq(gpio_to_irq(uart->cts_pin), uart);
if (uart->rts_pin >= 0)
gpio_free(uart->rts_pin);
#endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+#ifdef SERIAL_BFIN_HARD_CTSRTS
if (uart->cts_pin >= 0)
free_irq(uart->status_irq, uart);
#endif
@@ -788,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int ier, lcr = 0;
unsigned long timeout;
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#ifdef SERIAL_BFIN_CTSRTS
if (old == NULL && uart->cts_pin != -1)
termios->c_cflag |= CRTSCTS;
else if (uart->cts_pin == -1)
@@ -1110,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options)
int baud = 57600;
int bits = 8;
int parity = 'n';
-# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+# if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
int flow = 'r';
# else
int flow = 'n';
@@ -1322,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev)
init_timer(&(uart->rx_dma_timer));
#endif
-#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
- defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
+#if defined(SERIAL_BFIN_CTSRTS) || \
+ defined(SERIAL_BFIN_HARD_CTSRTS)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
uart->cts_pin = -1;
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 0c1825b0b41d..3e4470af5c50 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $";
#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
-#endif
-
/*
* All of the compatibilty code so we can compile serial.c against
* older kernels is hidden in serial_compat.h
@@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = {
static struct fast_timer fast_timers[NR_PORTS];
#endif
-#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
-#define PROCSTAT(x) x
-struct ser_statistics_type {
- int overrun_cnt;
- int early_errors_cnt;
- int ser_ints_ok_cnt;
- int errors_cnt;
- unsigned long int processing_flip;
- unsigned long processing_flip_still_room;
- unsigned long int timeout_flush_cnt;
- int rx_dma_ints;
- int tx_dma_ints;
- int rx_tot;
- int tx_tot;
-};
-
-static struct ser_statistics_type ser_stat[NR_PORTS];
-
-#else
-
-#define PROCSTAT(x)
-
-#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
-
/* RS-485 */
#if defined(CONFIG_ETRAX_RS485)
#ifdef CONFIG_ETRAX_FAST_TIMER
@@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS];
#if defined(CONFIG_ETRAX_RS485_ON_PA)
static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
-static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
-#endif
#endif
/* Info and macros needed for each ports extra control/status signals. */
@@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
-#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED
#endif
-#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED
/* The pins can be mixed on PA and PB */
#define CONTROL_PINS_PORT_NOT_USED(line) \
&dummy_ser[line], &dummy_ser[line], \
@@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
#endif
}
};
-#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
/* All pins are on either PA or PB for each serial port */
#define CONTROL_PINS_PORT_NOT_USED(line) \
@@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
#endif
}
};
-#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
#define E100_RTS_MASK 0x20
#define E100_CTS_MASK 0x40
@@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- rs485_port_g_bit, 1);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
-#endif
info->rs485 = *r;
@@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size)
{
struct etrax_recv_buffer *buffer;
- if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
+ buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC);
+ if (!buffer)
return NULL;
buffer->next = NULL;
@@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl
{
struct etrax_recv_buffer *buffer;
if (info->uses_dma_in) {
- if (!(buffer = alloc_recv_buffer(4)))
+ buffer = alloc_recv_buffer(4);
+ if (!buffer)
return 0;
buffer->length = 1;
@@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info,
append_recv_buffer(info, buffer);
- if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
+ if (!buffer)
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr->buf = virt_to_phys(buffer->buffer);
@@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info)
*/
unsigned char data = info->ioport[REG_DATA];
- PROCSTAT(ser_stat[info->line].errors_cnt++);
DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
@@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info)
/* Set up the receiving descriptors */
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
- if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
+ buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
+ if (!buffer)
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr[i].ctrl = d_int;
@@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id)
/* Read jiffies_usec first,
* we want this time to be as late as possible
*/
- PROCSTAT(ser_stat[info->line].tx_dma_ints++);
info->last_tx_active_usec = GET_JIFFIES_USEC();
info->last_tx_active = jiffies;
transmit_chars_dma(info);
@@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info)
*/
if (!info->forced_eop) {
info->forced_eop = 1;
- PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
FORCE_EOP(info);
}
@@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
DEBUG_LOG(info->line, "#iERR s d %04X\n",
((rstat & SER_ERROR_MASK) << 8) | data);
}
- PROCSTAT(ser_stat[info->line].early_errors_cnt++);
} else { /* It was a valid byte, now let the DMA do the rest */
unsigned long curr_time_u = GET_JIFFIES_USEC();
unsigned long curr_time = jiffies;
@@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
info->break_detected_cnt = 0;
- PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
}
/* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
@@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info)
*R_SERIAL_PRESCALE = divisor;
info->baud = SERIAL_PRESCALE_BASE/divisor;
}
-#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
- else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
- info->custom_divisor == 1) ||
- (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
- info->custom_divisor == 8)) {
- /* ext_clk selected */
- alt_source =
- IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
- IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
- DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
- info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
- }
-#endif
else
{
/* Bad baudbase, we don't support using timer0
@@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %lu....\n", tty_name(tty, buf),
+ printk("throttle %s: %lu....\n", tty_name(tty),
(unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
@@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
+ printk("unthrottle %s: %lu....\n", tty_name(tty),
(unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
@@ -3725,16 +3666,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
#if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- rs485_port_g_bit, 0);
-#endif
-#if defined(CONFIG_ETRAX_RS485_LTC1387)
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
- REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
- CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
-#endif
}
#endif
@@ -4263,15 +4194,6 @@ static int __init rs_init(void)
return -EBUSY;
}
#endif
-#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
- if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
- rs485_port_g_bit)) {
- printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
- "RS485 pin\n");
- put_tty_driver(driver);
- return -EBUSY;
- }
-#endif
#endif
/* Initialize the tty_driver structure */
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index 6dc471e30e79..f09636083426 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -72,6 +72,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
switch (port->iotype) {
case UPIO_MEM32:
+ case UPIO_MEM32BE:
port->regshift = 2; /* fall-through */
case UPIO_MEM:
port->mapbase = addr;
@@ -90,9 +91,11 @@ static int __init parse_options(struct earlycon_device *device, char *options)
strlcpy(device->options, options, length);
}
- if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32)
+ if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 ||
+ port->iotype == UPIO_MEM32BE)
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
- (port->iotype == UPIO_MEM32) ? "32" : "",
+ (port->iotype == UPIO_MEM) ? "" :
+ (port->iotype == UPIO_MEM32) ? "32" : "32be",
(unsigned long long)port->mapbase,
device->options);
else
@@ -133,7 +136,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
*
* Registers the earlycon console matching the earlycon specified
* in the param string @buf. Acceptable param strings are of the form
- * <name>,io|mmio|mmio32,<addr>,<options>
+ * <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
* <name>,0x<addr>,<options>
* <name>,<options>
* <name>
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 45fc323b95e6..ffc7cb2585a6 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev,
return retval;
}
- if ( (retval = pci_request_regions(dev, "icom"))) {
+ retval = pci_request_regions(dev, "icom");
+ if (retval) {
dev_err(&dev->dev, "pci_request_regions FAILED\n");
pci_disable_device(dev);
return retval;
@@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev,
pci_set_master(dev);
- if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
+ retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
+ if (retval) {
dev_err(&dev->dev, "PCI Config read FAILED\n");
return retval;
}
@@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev,
}
/* save off irq and request irq line */
- if ( (retval = request_irq(dev->irq, icom_interrupt,
- IRQF_SHARED, ICOM_DRIVER_NAME,
- (void *) icom_adapter))) {
+ retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
+ if (retval) {
goto probe_exit2;
}
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 590390970996..536a33b99be9 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
ifx_spi_reset_interrupt,
IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
- (void *)ifx_dev);
+ ifx_dev);
if (ret) {
dev_err(&spi->dev, "Unable to get irq %x\n",
gpio_to_irq(ifx_dev->gpio.reset_out));
@@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = ifx_spi_reset(ifx_dev);
ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
- ifx_spi_srdy_interrupt,
- IRQF_TRIGGER_RISING, DRVNAME,
- (void *)ifx_dev);
+ ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME,
+ ifx_dev);
if (ret) {
dev_err(&spi->dev, "Unable to get irq %x",
gpio_to_irq(ifx_dev->gpio.srdy));
@@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
return 0;
error_ret7:
- free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
error_ret6:
gpio_free(ifx_dev->gpio.srdy);
error_ret5:
@@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
/* stop activity */
tasklet_kill(&ifx_dev->io_work_tasklet);
/* free irq */
- free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
- free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
+ free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
gpio_free(ifx_dev->gpio.srdy);
gpio_free(ifx_dev->gpio.mrdy);
@@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void)
/* unregister */
tty_unregister_driver(tty_drv);
put_tty_driver(tty_drv);
- spi_unregister_driver((void *)&ifx_spi_driver);
+ spi_unregister_driver(&ifx_spi_driver);
unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
}
@@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void)
goto err_free_tty;
}
- result = spi_register_driver((void *)&ifx_spi_driver);
+ result = spi_register_driver(&ifx_spi_driver);
if (result) {
pr_err("%s: spi_register_driver failed(%d)",
DRVNAME, result);
@@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void)
return 0;
err_unreg_spi:
- spi_unregister_driver((void *)&ifx_spi_driver);
+ spi_unregister_driver(&ifx_spi_driver);
err_unreg_tty:
tty_unregister_driver(tty_drv);
err_free_tty:
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 88250395b0ce..2c90dc31bfaa 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -239,7 +239,7 @@ static struct imx_uart_data imx_uart_devdata[] = {
},
};
-static struct platform_device_id imx_uart_devtype[] = {
+static const struct platform_device_id imx_uart_devtype[] = {
{
.name = "imx1-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
@@ -853,7 +853,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
#define TXTL 2 /* reset default */
#define RXTL 1 /* reset default */
-static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
{
unsigned int val;
@@ -861,7 +861,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
val |= TXTL << UFCR_TXTL_SHF | RXTL;
writel(val, sport->port.membase + UFCR);
- return 0;
}
#define RX_BUF_SIZE (PAGE_SIZE)
@@ -1122,6 +1121,12 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+ /* Can we enable the DMA support? */
+ if (is_imx6q_uart(sport) && !uart_console(port) &&
+ !sport->dma_is_inited)
+ imx_uart_dma_init(sport);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
/* Reset fifo's and state machines */
i = 100;
@@ -1132,13 +1137,6 @@ static int imx_startup(struct uart_port *port)
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
- /* Can we enable the DMA support? */
- if (is_imx6q_uart(sport) && !uart_console(port) &&
- !sport->dma_is_inited)
- imx_uart_dma_init(sport);
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
/*
* Finally, clear and enable interrupts
*/
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index abd7ea26ed9a..27b5fefac171 100644
--- a/drivers/tty/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
@@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
/* register port with the serial core */
- if ((ret = ioc3_serial_core_attach(is, idd)))
+ ret = ioc3_serial_core_attach(is, idd);
+ if (ret)
goto out4;
Num_of_ioc3_cards++;
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index aa28209f44c1..e5c42fef69d2 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
*/
for (xx = 0; xx < num_intrs; xx++) {
intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
- if ((this_mir = this_ir & intr_info->sd_bits)) {
+ this_mir = this_ir & intr_info->sd_bits;
+ if (this_mir) {
/* Disable owned interrupts, call handler */
handled++;
write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
@@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
/* register port with the serial core - 1 rs232, 1 rs422 */
- if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
+ ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232);
+ if (ret)
goto out4;
- if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
+ ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422);
+ if (ret)
goto out5;
Num_of_ioc4_cards++;
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
index 129dc5be6028..117df151627d 100644
--- a/drivers/tty/serial/kgdb_nmi.c
+++ b/drivers/tty/serial/kgdb_nmi.c
@@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void)
bool kgdb_nmi_poll_knock(void)
{
if (kgdb_nmi_knock < 0)
- return 1;
+ return true;
while (1) {
int ret;
ret = kgdb_nmi_poll_one_knock();
if (ret == NO_POLL_CHAR)
- return 0;
+ return false;
else if (ret == 1)
break;
}
- return 1;
+ return true;
}
/*
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index a9b0ab38a68c..02eb32217685 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -597,7 +597,7 @@ console_initcall(mcf_console_init);
#define MCF_CONSOLE NULL
/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
+#endif /* CONFIG_SERIAL_MCF_CONSOLE */
/****************************************************************************/
/*
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 67c036702629..0fc83c962d10 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port,
static void meson_uart_release_port(struct uart_port *port)
{
if (port->flags & UPF_IOREMAP) {
- iounmap(port->membase);
+ devm_iounmap(port->dev, port->membase);
port->membase = NULL;
}
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 1589f17c1fca..6fc07eb9d74e 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -405,7 +405,7 @@ static struct psc_ops mpc5200b_psc_ops = {
.get_mr1 = mpc52xx_psc_get_mr1,
};
-#endif /* CONFIG_MPC52xx */
+#endif /* CONFIG_PPC_MPC52xx */
#ifdef CONFIG_PPC_MPC512x
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index 856fd5a5fa3c..82bb6d1fe23b 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -913,7 +913,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi)
if (!pi->ready) {
mpsc_init_hw(pi);
- if ((rc = mpsc_alloc_ring_mem(pi)))
+ rc = mpsc_alloc_ring_mem(pi);
+ if (rc)
return rc;
mpsc_init_rings(pi);
pi->ready = 1;
@@ -1895,7 +1896,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev)
int rc = -ENODEV;
if (dev->id == 0) {
- if (!(rc = mpsc_shared_map_regs(dev))) {
+ rc = mpsc_shared_map_regs(dev);
+ if (!rc) {
pdata = (struct mpsc_shared_pdata *)
dev_get_platdata(&dev->dev);
@@ -2081,14 +2083,16 @@ static int mpsc_drv_probe(struct platform_device *dev)
if (dev->id < MPSC_NUM_CTLRS) {
pi = &mpsc_ports[dev->id];
- if (!(rc = mpsc_drv_map_regs(pi, dev))) {
+ rc = mpsc_drv_map_regs(pi, dev);
+ if (!rc) {
mpsc_drv_get_platform_data(pi, dev, dev->id);
pi->port.dev = &dev->dev;
- if (!(rc = mpsc_make_ready(pi))) {
+ rc = mpsc_make_ready(pi);
+ if (!rc) {
spin_lock_init(&pi->tx_lock);
- if (!(rc = uart_add_one_port(&mpsc_reg,
- &pi->port))) {
+ rc = uart_add_one_port(&mpsc_reg, &pi->port);
+ if (!rc) {
rc = 0;
} else {
mpsc_release_port((struct uart_port *)
@@ -2136,9 +2140,12 @@ static int __init mpsc_drv_init(void)
memset(mpsc_ports, 0, sizeof(mpsc_ports));
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
- if (!(rc = uart_register_driver(&mpsc_reg))) {
- if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
- if ((rc = platform_driver_register(&mpsc_driver))) {
+ rc = uart_register_driver(&mpsc_reg);
+ if (!rc) {
+ rc = platform_driver_register(&mpsc_shared_driver);
+ if (!rc) {
+ rc = platform_driver_register(&mpsc_driver);
+ if (rc) {
platform_driver_unregister(&mpsc_shared_driver);
uart_unregister_driver(&mpsc_reg);
}
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
deleted file mode 100644
index 1238ac370bff..000000000000
--- a/drivers/tty/serial/msm_smd_tty.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- * Author: Brian Swetland <swetland@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/module.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-
-#include <mach/msm_smd.h>
-
-#define MAX_SMD_TTYS 32
-
-struct smd_tty_info {
- struct tty_port port;
- smd_channel_t *ch;
-};
-
-struct smd_tty_channel_desc {
- int id;
- const char *name;
-};
-
-static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
-
-static const struct smd_tty_channel_desc smd_default_tty_channels[] = {
- { .id = 0, .name = "SMD_DS" },
- { .id = 27, .name = "SMD_GPSNMEA" },
-};
-
-static const struct smd_tty_channel_desc *smd_tty_channels =
- smd_default_tty_channels;
-static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels);
-
-static void smd_tty_notify(void *priv, unsigned event)
-{
- unsigned char *ptr;
- int avail;
- struct smd_tty_info *info = priv;
- struct tty_struct *tty;
-
- if (event != SMD_EVENT_DATA)
- return;
-
- tty = tty_port_tty_get(&info->port);
- if (!tty)
- return;
-
- for (;;) {
- if (test_bit(TTY_THROTTLED, &tty->flags))
- break;
- avail = smd_read_avail(info->ch);
- if (avail == 0)
- break;
-
- avail = tty_prepare_flip_string(&info->port, &ptr, avail);
-
- if (smd_read(info->ch, ptr, avail) != avail) {
- /* shouldn't be possible since we're in interrupt
- ** context here and nobody else could 'steal' our
- ** characters.
- */
- pr_err("OOPS - smd_tty_buffer mismatch?!");
- }
-
- tty_flip_buffer_push(&info->port);
- }
-
- /* XXX only when writable and necessary */
- tty_wakeup(tty);
- tty_kref_put(tty);
-}
-
-static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
-{
- struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
- port);
- int i, res = 0;
- const char *name = NULL;
-
- for (i = 0; i < smd_tty_channels_len; i++) {
- if (smd_tty_channels[i].id == tty->index) {
- name = smd_tty_channels[i].name;
- break;
- }
- }
- if (!name)
- return -ENODEV;
-
- if (info->ch)
- smd_kick(info->ch);
- else
- res = smd_open(name, &info->ch, info, smd_tty_notify);
-
- if (!res)
- tty->driver_data = info;
-
- return res;
-}
-
-static void smd_tty_port_shutdown(struct tty_port *tport)
-{
- struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
- port);
-
- if (info->ch) {
- smd_close(info->ch);
- info->ch = 0;
- }
-}
-
-static int smd_tty_open(struct tty_struct *tty, struct file *f)
-{
- struct smd_tty_info *info = smd_tty + tty->index;
-
- return tty_port_open(&info->port, tty, f);
-}
-
-static void smd_tty_close(struct tty_struct *tty, struct file *f)
-{
- struct smd_tty_info *info = tty->driver_data;
-
- tty_port_close(&info->port, tty, f);
-}
-
-static int smd_tty_write(struct tty_struct *tty,
- const unsigned char *buf, int len)
-{
- struct smd_tty_info *info = tty->driver_data;
- int avail;
-
- /* if we're writing to a packet channel we will
- ** never be able to write more data than there
- ** is currently space for
- */
- avail = smd_write_avail(info->ch);
- if (len > avail)
- len = avail;
-
- return smd_write(info->ch, buf, len);
-}
-
-static int smd_tty_write_room(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- return smd_write_avail(info->ch);
-}
-
-static int smd_tty_chars_in_buffer(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- return smd_read_avail(info->ch);
-}
-
-static void smd_tty_unthrottle(struct tty_struct *tty)
-{
- struct smd_tty_info *info = tty->driver_data;
- smd_kick(info->ch);
-}
-
-static const struct tty_port_operations smd_tty_port_ops = {
- .shutdown = smd_tty_port_shutdown,
- .activate = smd_tty_port_activate,
-};
-
-static const struct tty_operations smd_tty_ops = {
- .open = smd_tty_open,
- .close = smd_tty_close,
- .write = smd_tty_write,
- .write_room = smd_tty_write_room,
- .chars_in_buffer = smd_tty_chars_in_buffer,
- .unthrottle = smd_tty_unthrottle,
-};
-
-static struct tty_driver *smd_tty_driver;
-
-static int __init smd_tty_init(void)
-{
- int ret, i;
-
- smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
- if (smd_tty_driver == 0)
- return -ENOMEM;
-
- smd_tty_driver->driver_name = "smd_tty_driver";
- smd_tty_driver->name = "smd";
- smd_tty_driver->major = 0;
- smd_tty_driver->minor_start = 0;
- smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- smd_tty_driver->init_termios = tty_std_termios;
- smd_tty_driver->init_termios.c_iflag = 0;
- smd_tty_driver->init_termios.c_oflag = 0;
- smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
- smd_tty_driver->init_termios.c_lflag = 0;
- smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
- TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(smd_tty_driver, &smd_tty_ops);
-
- ret = tty_register_driver(smd_tty_driver);
- if (ret)
- return ret;
-
- for (i = 0; i < smd_tty_channels_len; i++) {
- struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
- tty_port_init(port);
- port->ops = &smd_tty_port_ops;
- tty_port_register_device(port, smd_tty_driver,
- smd_tty_channels[i].id, NULL);
- }
-
- return 0;
-}
-
-module_init(smd_tty_init);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index f7e5825b55ab..13cf7738fbdc 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -169,7 +169,7 @@ struct mxs_auart_port {
bool ms_irq_enabled;
};
-static struct platform_device_id mxs_auart_devtype[] = {
+static const struct platform_device_id mxs_auart_devtype[] = {
{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
{ /* sentinel */ }
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 137381e649e5..6823df99bd76 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -67,14 +67,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_property_read_u32(np, "clock-frequency", &clk)) {
/* Get clk rate through clk driver if present */
- info->clk = clk_get(&ofdev->dev, NULL);
+ info->clk = devm_clk_get(&ofdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_warn(&ofdev->dev,
"clk or clock-frequency not defined\n");
return PTR_ERR(info->clk);
}
- clk_prepare_enable(info->clk);
+ ret = clk_prepare_enable(info->clk);
+ if (ret < 0)
+ return ret;
+
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -188,7 +191,6 @@ 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)
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index a0ae942d9562..67d0c213b1c7 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -348,7 +348,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
s3c24xx_serial_start_tx_dma(ourport, count);
}
-void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
struct circ_buf *xmit = &port->state->xmit;
@@ -2337,7 +2337,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
#endif
-static struct platform_device_id s3c24xx_serial_driver_ids[] = {
+static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
{
.name = "s3c2410-uart",
.driver_data = S3C2410_SERIAL_DRV_DATA,
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 468354ef7baa..9e6576004a42 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -25,6 +25,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/spi/spi.h>
#include <linux/uaccess.h>
#define SC16IS7XX_NAME "sc16is7xx"
@@ -300,25 +301,38 @@ struct sc16is7xx_devtype {
int nr_uart;
};
+#define SC16IS7XX_RECONF_MD (1 << 0)
+#define SC16IS7XX_RECONF_IER (1 << 1)
+#define SC16IS7XX_RECONF_RS485 (1 << 2)
+
+struct sc16is7xx_one_config {
+ unsigned int flags;
+ u8 ier_clear;
+};
+
struct sc16is7xx_one {
struct uart_port port;
- struct work_struct tx_work;
- struct work_struct md_work;
+ struct kthread_work tx_work;
+ struct kthread_work reg_work;
+ struct sc16is7xx_one_config config;
};
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 kthread_worker kworker;
+ struct task_struct *kworker_task;
+ struct kthread_work irq_work;
struct sc16is7xx_one p[0];
};
+#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e)))
#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
@@ -615,9 +629,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
!!(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,
@@ -628,81 +640,115 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
} while (1);
}
-static irqreturn_t sc16is7xx_ist(int irq, void *dev_id)
+static void sc16is7xx_ist(struct kthread_work *ws)
{
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+ struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
int i;
for (i = 0; i < s->uart.nr; ++i)
sc16is7xx_port_irq(s, i);
+}
+
+static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
+{
+ struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+
+ queue_kthread_work(&s->kworker, &s->irq_work);
return IRQ_HANDLED;
}
-static void sc16is7xx_wq_proc(struct work_struct *ws)
+static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work);
- struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
+ struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
+
+ if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ (port->rs485.delay_rts_before_send > 0))
+ msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&s->mutex);
- sc16is7xx_handle_tx(&one->port);
- mutex_unlock(&s->mutex);
+ sc16is7xx_handle_tx(port);
}
-static void sc16is7xx_stop_tx(struct uart_port* port)
+static void sc16is7xx_reconf_rs485(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- struct circ_buf *xmit = &one->port.state->xmit;
-
- /* handle rs485 */
- if (port->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) &&
- (port->rs485.delay_rts_after_send > 0))
- mdelay(port->rs485.delay_rts_after_send);
+ const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
+ SC16IS7XX_EFCR_RTS_INVERT_BIT;
+ u32 efcr = 0;
+ struct serial_rs485 *rs485 = &port->rs485;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&port->lock, irqflags);
+ if (rs485->flags & SER_RS485_ENABLED) {
+ efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
+
+ if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
+ efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
}
+ spin_unlock_irqrestore(&port->lock, irqflags);
- sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
- SC16IS7XX_IER_THRI_BIT,
- 0);
+ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
}
-static void sc16is7xx_stop_rx(struct uart_port* port)
+static void sc16is7xx_reg_proc(struct kthread_work *ws)
{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work);
+ struct sc16is7xx_one_config config;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&one->port.lock, irqflags);
+ config = one->config;
+ memset(&one->config, 0, sizeof(one->config));
+ spin_unlock_irqrestore(&one->port.lock, irqflags);
+
+ if (config.flags & SC16IS7XX_RECONF_MD)
+ sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
+ SC16IS7XX_MCR_LOOP_BIT,
+ (one->port.mctrl & TIOCM_LOOP) ?
+ SC16IS7XX_MCR_LOOP_BIT : 0);
+
+ if (config.flags & SC16IS7XX_RECONF_IER)
+ sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
+ config.ier_clear, 0);
+
+ if (config.flags & SC16IS7XX_RECONF_RS485)
+ sc16is7xx_reconf_rs485(&one->port);
+}
+
+static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
+{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
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);
+ one->config.flags |= SC16IS7XX_RECONF_IER;
+ one->config.ier_clear |= bit;
+ queue_kthread_work(&s->kworker, &one->reg_work);
+}
+
+static void sc16is7xx_stop_tx(struct uart_port *port)
+{
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT);
+}
+
+static void sc16is7xx_stop_rx(struct uart_port *port)
+{
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
}
static void sc16is7xx_start_tx(struct uart_port *port)
{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- /* handle rs485 */
- if ((port->rs485.flags & SER_RS485_ENABLED) &&
- (port->rs485.delay_rts_before_send > 0)) {
- mdelay(port->rs485.delay_rts_before_send);
- }
-
- if (!work_pending(&one->tx_work))
- schedule_work(&one->tx_work);
+ queue_kthread_work(&s->kworker, &one->tx_work);
}
static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
{
- unsigned int lvl, lsr;
+ unsigned int 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;
+ return (lsr & SC16IS7XX_LSR_TEMT_BIT) ? TIOCSER_TEMT : 0;
}
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
@@ -713,21 +759,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
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_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- schedule_work(&one->md_work);
+ one->config.flags |= SC16IS7XX_RECONF_MD;
+ queue_kthread_work(&s->kworker, &one->reg_work);
}
static void sc16is7xx_break_ctl(struct uart_port *port, int break_state)
@@ -831,9 +869,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
static int sc16is7xx_config_rs485(struct uart_port *port,
struct serial_rs485 *rs485)
{
- const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
- SC16IS7XX_EFCR_RTS_INVERT_BIT;
- u32 efcr = 0;
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
if (rs485->flags & SER_RS485_ENABLED) {
bool rts_during_rx, rts_during_tx;
@@ -841,21 +878,23 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND;
rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND;
- efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
-
- if (!rts_during_rx && rts_during_tx)
- /* default */;
- else if (rts_during_rx && !rts_during_tx)
- efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
- else
+ if (rts_during_rx == rts_during_tx)
dev_err(port->dev,
"unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n",
rts_during_tx, rts_during_rx);
- }
- sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
+ /*
+ * RTS signal is handled by HW, it's timing can't be influenced.
+ * However, it's sometimes useful to delay TX even without RTS
+ * control therefore we try to handle .delay_rts_before_send.
+ */
+ if (rs485->delay_rts_after_send)
+ return -EINVAL;
+ }
port->rs485 = *rs485;
+ one->config.flags |= SC16IS7XX_RECONF_RS485;
+ queue_kthread_work(&s->kworker, &one->reg_work);
return 0;
}
@@ -916,6 +955,8 @@ static int sc16is7xx_startup(struct uart_port *port)
static void sc16is7xx_shutdown(struct uart_port *port)
{
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+
/* Disable all interrupts */
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
/* Disable TX/RX */
@@ -926,6 +967,8 @@ static void sc16is7xx_shutdown(struct uart_port *port)
SC16IS7XX_EFCR_TXDISABLE_BIT);
sc16is7xx_power(port, 0);
+
+ flush_kthread_worker(&s->kworker);
}
static const char *sc16is7xx_type(struct uart_port *port)
@@ -1043,6 +1086,7 @@ static int sc16is7xx_probe(struct device *dev,
struct sc16is7xx_devtype *devtype,
struct regmap *regmap, int irq, unsigned long flags)
{
+ struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
unsigned long freq, *pfreq = dev_get_platdata(dev);
int i, ret;
struct sc16is7xx_port *s;
@@ -1084,6 +1128,16 @@ static int sc16is7xx_probe(struct device *dev,
goto out_clk;
}
+ init_kthread_worker(&s->kworker);
+ init_kthread_work(&s->irq_work, sc16is7xx_ist);
+ s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
+ "sc16is7xx");
+ if (IS_ERR(s->kworker_task)) {
+ ret = PTR_ERR(s->kworker_task);
+ goto out_uart;
+ }
+ sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param);
+
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio) {
/* Setup GPIO cotroller */
@@ -1099,12 +1153,10 @@ static int sc16is7xx_probe(struct device *dev,
s->gpio.can_sleep = 1;
ret = gpiochip_add(&s->gpio);
if (ret)
- goto out_uart;
+ goto out_thread;
}
#endif
- mutex_init(&s->mutex);
-
for (i = 0; i < devtype->nr_uart; ++i) {
/* Initialize port data */
s->p[i].port.line = i;
@@ -1123,10 +1175,9 @@ static int sc16is7xx_probe(struct device *dev,
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);
+ /* Initialize kthread work structs */
+ init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
+ init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
/* Register port */
uart_add_one_port(&s->uart, &s->p[i].port);
/* Go to suspend mode */
@@ -1134,22 +1185,23 @@ static int sc16is7xx_probe(struct device *dev,
}
/* Setup interrupt */
- ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist,
- IRQF_ONESHOT | flags, dev_name(dev), s);
+ ret = devm_request_irq(dev, irq, sc16is7xx_irq,
+ IRQF_ONESHOT | flags, dev_name(dev), s);
if (!ret)
return 0;
for (i = 0; i < s->uart.nr; i++)
uart_remove_one_port(&s->uart, &s->p[i].port);
- mutex_destroy(&s->mutex);
-
#ifdef CONFIG_GPIOLIB
if (devtype->nr_gpio)
gpiochip_remove(&s->gpio);
-out_uart:
+out_thread:
#endif
+ kthread_stop(s->kworker_task);
+
+out_uart:
uart_unregister_driver(&s->uart);
out_clk:
@@ -1170,13 +1222,13 @@ static int sc16is7xx_remove(struct device *dev)
#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);
+ flush_kthread_worker(&s->kworker);
+ kthread_stop(s->kworker_task);
+
uart_unregister_driver(&s->uart);
if (!IS_ERR(s->clk))
clk_disable_unprepare(s->clk);
@@ -1204,6 +1256,75 @@ static struct regmap_config regcfg = {
.precious_reg = sc16is7xx_regmap_precious,
};
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+static int sc16is7xx_spi_probe(struct spi_device *spi)
+{
+ struct sc16is7xx_devtype *devtype;
+ unsigned long flags = 0;
+ struct regmap *regmap;
+ int ret;
+
+ /* Setup SPI bus */
+ spi->bits_per_word = 8;
+ /* only supports mode 0 on SC16IS762 */
+ spi->mode = spi->mode ? : SPI_MODE_0;
+ spi->max_speed_hz = spi->max_speed_hz ? : 15000000;
+ ret = spi_setup(spi);
+ if (ret)
+ return ret;
+
+ if (spi->dev.of_node) {
+ const struct of_device_id *of_id =
+ of_match_device(sc16is7xx_dt_ids, &spi->dev);
+
+ devtype = (struct sc16is7xx_devtype *)of_id->data;
+ } else {
+ const struct spi_device_id *id_entry = spi_get_device_id(spi);
+
+ devtype = (struct sc16is7xx_devtype *)id_entry->driver_data;
+ flags = IRQF_TRIGGER_FALLING;
+ }
+
+ regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
+ (devtype->nr_uart - 1);
+ regmap = devm_regmap_init_spi(spi, &regcfg);
+
+ return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags);
+}
+
+static int sc16is7xx_spi_remove(struct spi_device *spi)
+{
+ return sc16is7xx_remove(&spi->dev);
+}
+
+static const struct spi_device_id sc16is7xx_spi_id_table[] = {
+ { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (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(spi, sc16is7xx_spi_id_table);
+
+static struct spi_driver sc16is7xx_spi_uart_driver = {
+ .driver = {
+ .name = SC16IS7XX_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sc16is7xx_dt_ids),
+ },
+ .probe = sc16is7xx_spi_probe,
+ .remove = sc16is7xx_spi_remove,
+ .id_table = sc16is7xx_spi_id_table,
+};
+
+MODULE_ALIAS("spi:sc16is7xx");
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1235,6 +1356,8 @@ static int sc16is7xx_i2c_remove(struct i2c_client *client)
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
@@ -1253,8 +1376,43 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
.remove = sc16is7xx_i2c_remove,
.id_table = sc16is7xx_i2c_id_table,
};
-module_i2c_driver(sc16is7xx_i2c_uart_driver);
+
MODULE_ALIAS("i2c:sc16is7xx");
+#endif
+
+static int __init sc16is7xx_init(void)
+{
+ int ret = 0;
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
+ ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
+ if (ret < 0) {
+ pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
+ return ret;
+ }
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+ ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
+ if (ret < 0) {
+ pr_err("failed to init sc16is7xx spi --> %d\n", ret);
+ return ret;
+ }
+#endif
+ return ret;
+}
+module_init(sc16is7xx_init);
+
+static void __exit sc16is7xx_exit(void)
+{
+#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
+ i2c_del_driver(&sc16is7xx_i2c_uart_driver);
+#endif
+
+#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
+ spi_unregister_driver(&sc16is7xx_spi_uart_driver);
+#endif
+}
+module_exit(sc16is7xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 1d5ea3964ee5..cf0133ae762d 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -131,8 +131,8 @@ struct tegra_uart_port {
struct dma_async_tx_descriptor *rx_dma_desc;
dma_cookie_t tx_cookie;
dma_cookie_t rx_cookie;
- int tx_bytes_requested;
- int rx_bytes_requested;
+ unsigned int tx_bytes_requested;
+ unsigned int rx_bytes_requested;
};
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup);
@@ -234,6 +234,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
tup->lcr_shadow = lcr;
}
+/**
+ * tegra_uart_wait_cycle_time: Wait for N UART clock periods
+ *
+ * @tup: Tegra serial port data structure.
+ * @cycles: Number of clock periods to wait.
+ *
+ * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART
+ * clock speed is 16X the current baud rate.
+ */
+static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup,
+ unsigned int cycles)
+{
+ if (tup->current_baud)
+ udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16));
+}
+
/* Wait for a symbol-time. */
static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup,
unsigned int syms)
@@ -263,8 +279,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits)
/* Dummy read to ensure the write is posted */
tegra_uart_read(tup, UART_SCR);
- /* Wait for the flush to propagate. */
- tegra_uart_wait_sym_time(tup, 1);
+ /*
+ * For all tegra devices (up to t210), there is a hardware issue that
+ * requires software to wait for 32 UART clock periods for the flush
+ * to propagate, otherwise data could be lost.
+ */
+ tegra_uart_wait_cycle_time(tup, 32);
}
static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud)
@@ -388,9 +408,9 @@ static void tegra_uart_tx_dma_complete(void *args)
struct circ_buf *xmit = &tup->uport.state->xmit;
struct dma_tx_state state;
unsigned long flags;
- int count;
+ unsigned int count;
- dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state);
+ dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
count = tup->tx_bytes_requested - state.residue;
async_tx_ack(tup->tx_dma_desc);
spin_lock_irqsave(&tup->uport.lock, flags);
@@ -480,7 +500,7 @@ static void tegra_uart_stop_tx(struct uart_port *u)
struct tegra_uart_port *tup = to_tegra_uport(u);
struct circ_buf *xmit = &tup->uport.state->xmit;
struct dma_tx_state state;
- int count;
+ unsigned int count;
if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
return;
@@ -530,10 +550,15 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
}
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
- struct tty_port *tty, int count)
+ struct tty_port *tty,
+ unsigned int count)
{
int copied;
+ /* If count is zero, then there is no data to be copied */
+ if (!count)
+ return;
+
tup->uport.icount.rx += count;
if (!tty) {
dev_err(tup->uport.dev, "No tty port\n");
@@ -555,21 +580,30 @@ static void tegra_uart_rx_dma_complete(void *args)
{
struct tegra_uart_port *tup = args;
struct uart_port *u = &tup->uport;
- int count = tup->rx_bytes_requested;
+ unsigned int count = tup->rx_bytes_requested;
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &u->state->port;
unsigned long flags;
+ struct dma_tx_state state;
+ enum dma_status status;
- async_tx_ack(tup->rx_dma_desc);
spin_lock_irqsave(&u->lock, flags);
+ status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+
+ if (status == DMA_IN_PROGRESS) {
+ dev_dbg(tup->uport.dev, "RX DMA is in progress\n");
+ goto done;
+ }
+
+ async_tx_ack(tup->rx_dma_desc);
+
/* Deactivate flow control to stop sender */
if (tup->rts_active)
set_rts(tup, false);
/* If we are here, DMA is stopped */
- if (count)
- tegra_uart_copy_rx_to_tty(tup, port, count);
+ tegra_uart_copy_rx_to_tty(tup, port, count);
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
@@ -584,6 +618,7 @@ static void tegra_uart_rx_dma_complete(void *args)
if (tup->rts_active)
set_rts(tup, true);
+done:
spin_unlock_irqrestore(&u->lock, flags);
}
@@ -594,7 +629,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
struct tty_port *port = &tup->uport.state->port;
struct uart_port *u = &tup->uport;
- int count;
+ unsigned int count;
/* Deactivate flow control to stop sender */
if (tup->rts_active)
@@ -606,8 +641,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
count = tup->rx_bytes_requested - state.residue;
/* If we are here, DMA is stopped */
- if (count)
- tegra_uart_copy_rx_to_tty(tup, port, count);
+ tegra_uart_copy_rx_to_tty(tup, port, count);
tegra_uart_handle_rx_pio(tup, port);
if (tty) {
@@ -865,6 +899,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B;
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
+ /* Dummy read to ensure the write is posted */
+ tegra_uart_read(tup, UART_SCR);
+
+ /*
+ * For all tegra devices (up to t210), there is a hardware issue that
+ * requires software to wait for 3 UART clock periods after enabling
+ * the TX fifo, otherwise data could be lost.
+ */
+ tegra_uart_wait_cycle_time(tup, 3);
+
/*
* Initialize the UART with default configuration
* (115200, N, 8, 1) so that the receive DMA buffer may be
@@ -905,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
return 0;
}
+static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
+ bool dma_to_memory)
+{
+ if (dma_to_memory) {
+ dmaengine_terminate_all(tup->rx_dma_chan);
+ dma_release_channel(tup->rx_dma_chan);
+ dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
+ tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
+ tup->rx_dma_chan = NULL;
+ tup->rx_dma_buf_phys = 0;
+ tup->rx_dma_buf_virt = NULL;
+ } else {
+ dmaengine_terminate_all(tup->tx_dma_chan);
+ dma_release_channel(tup->tx_dma_chan);
+ dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ tup->tx_dma_chan = NULL;
+ tup->tx_dma_buf_phys = 0;
+ tup->tx_dma_buf_virt = NULL;
+ }
+}
+
static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
bool dma_to_memory)
{
@@ -933,67 +999,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
dma_release_channel(dma_chan);
return -ENOMEM;
}
+ dma_sconfig.src_addr = tup->uport.mapbase;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_sconfig.src_maxburst = 4;
+ tup->rx_dma_chan = dma_chan;
+ tup->rx_dma_buf_virt = dma_buf;
+ tup->rx_dma_buf_phys = dma_phys;
} else {
dma_phys = dma_map_single(tup->uport.dev,
tup->uport.state->xmit.buf, UART_XMIT_SIZE,
DMA_TO_DEVICE);
+ if (dma_mapping_error(tup->uport.dev, dma_phys)) {
+ dev_err(tup->uport.dev, "dma_map_single tx failed\n");
+ dma_release_channel(dma_chan);
+ return -ENOMEM;
+ }
dma_buf = tup->uport.state->xmit.buf;
- }
-
- if (dma_to_memory) {
- dma_sconfig.src_addr = tup->uport.mapbase;
- dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- dma_sconfig.src_maxburst = 4;
- } else {
dma_sconfig.dst_addr = tup->uport.mapbase;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_sconfig.dst_maxburst = 16;
+ tup->tx_dma_chan = dma_chan;
+ tup->tx_dma_buf_virt = dma_buf;
+ tup->tx_dma_buf_phys = dma_phys;
}
ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
if (ret < 0) {
dev_err(tup->uport.dev,
"Dma slave config failed, err = %d\n", ret);
- goto scrub;
+ tegra_uart_dma_channel_free(tup, dma_to_memory);
+ return ret;
}
- if (dma_to_memory) {
- tup->rx_dma_chan = dma_chan;
- tup->rx_dma_buf_virt = dma_buf;
- tup->rx_dma_buf_phys = dma_phys;
- } else {
- tup->tx_dma_chan = dma_chan;
- tup->tx_dma_buf_virt = dma_buf;
- tup->tx_dma_buf_phys = dma_phys;
- }
return 0;
-
-scrub:
- dma_release_channel(dma_chan);
- return ret;
-}
-
-static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
- bool dma_to_memory)
-{
- struct dma_chan *dma_chan;
-
- if (dma_to_memory) {
- dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
- tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
- dma_chan = tup->rx_dma_chan;
- tup->rx_dma_chan = NULL;
- tup->rx_dma_buf_phys = 0;
- tup->rx_dma_buf_virt = NULL;
- } else {
- dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
- UART_XMIT_SIZE, DMA_TO_DEVICE);
- dma_chan = tup->tx_dma_chan;
- tup->tx_dma_chan = NULL;
- tup->tx_dma_buf_phys = 0;
- tup->tx_dma_buf_virt = NULL;
- }
- dma_release_channel(dma_chan);
}
static int tegra_uart_startup(struct uart_port *u)
@@ -1060,8 +1098,6 @@ static void tegra_uart_shutdown(struct uart_port *u)
tegra_uart_dma_channel_free(tup, true);
tegra_uart_dma_channel_free(tup, false);
free_irq(u->irq, tup);
-
- tegra_uart_flush_buffer(u);
}
static void tegra_uart_enable_ms(struct uart_port *u)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 0b7bb12dfc68..7ae1592f7ec9 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -335,18 +335,29 @@ unsigned int
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
struct ktermios *old, unsigned int min, unsigned int max)
{
- unsigned int try, baud, altbaud = 38400;
+ unsigned int try;
+ unsigned int baud;
+ unsigned int altbaud;
int hung_up = 0;
upf_t flags = port->flags & UPF_SPD_MASK;
- if (flags == UPF_SPD_HI)
+ switch (flags) {
+ case UPF_SPD_HI:
altbaud = 57600;
- else if (flags == UPF_SPD_VHI)
+ break;
+ case UPF_SPD_VHI:
altbaud = 115200;
- else if (flags == UPF_SPD_SHI)
+ break;
+ case UPF_SPD_SHI:
altbaud = 230400;
- else if (flags == UPF_SPD_WARP)
+ break;
+ case UPF_SPD_WARP:
altbaud = 460800;
+ break;
+ default:
+ altbaud = 38400;
+ break;
+ }
for (try = 0; try < 2; try++) {
baud = tty_termios_baud_rate(termios);
@@ -894,12 +905,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
* need to rate-limit; it's CAP_SYS_ADMIN only.
*/
if (uport->flags & UPF_SPD_MASK) {
- char buf[64];
-
dev_notice(uport->dev,
"%s sets custom speed on %s. This is deprecated.\n",
current->comm,
- tty_name(port->tty, buf));
+ tty_name(port->tty));
}
uart_change_speed(tty, state, NULL);
}
@@ -1816,8 +1825,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* @options: ptr for <options> field; NULL if not present (out)
*
* Decodes earlycon kernel command line parameters of the form
- * earlycon=<name>,io|mmio|mmio32,<addr>,<options>
- * console=<name>,io|mmio|mmio32,<addr>,<options>
+ * earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
+ * console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
*
* The optional form
* earlycon=<name>,0x<addr>,<options>
@@ -1835,6 +1844,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
} else if (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
+ } else if (strncmp(p, "mmio32be,", 9) == 0) {
+ *iotype = UPIO_MEM32BE;
+ p += 9;
} else if (strncmp(p, "io,", 3) == 0) {
*iotype = UPIO_PORT;
p += 3;
diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index 5c79bdab985d..b4decf8787de 100644
--- a/drivers/tty/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
@@ -328,7 +328,7 @@ static int ks8695uart_startup(struct uart_port *port)
{
int retval;
- set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(KS8695_IRQ_UART_TX, IRQ_NOREQUEST, IRQ_NOAUTOEN);
tx_enable(port, 0);
rx_enable(port, 1);
ms_enable(port, 1);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 0ec756c62bcf..402f7fb54133 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -49,13 +49,12 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
unsigned int count = 0;
for (i = 0; i < UART_GPIO_MAX; i++)
- if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
- mctrl_gpios_desc[i].dir_out) {
+ if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
desc_array[count] = gpios->gpio[i];
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
count++;
}
- gpiod_set_array(count, desc_array, value_array);
+ gpiod_set_array_value(count, desc_array, value_array);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
@@ -118,7 +117,7 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
enum mctrl_gpio_idx i;
for (i = 0; i < UART_GPIO_MAX; i++)
- if (!IS_ERR_OR_NULL(gpios->gpio[i]))
+ if (gpios->gpio[i])
devm_gpiod_put(dev, gpios->gpio[i]);
devm_kfree(dev, gpios);
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e7d6566fafaf..1b2f894bdc9e 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -81,10 +81,11 @@ struct sci_port {
/* Platform configuration */
struct plat_sci_port *cfg;
- int overrun_bit;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
unsigned int error_mask;
unsigned int sampling_rate;
-
+ resource_size_t reg_size;
/* Break timer */
struct timer_list break_timer;
@@ -168,6 +169,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -188,6 +191,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -207,6 +212,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
@@ -226,6 +233,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = { 0x30, 16 },
+ [SCPDR] = { 0x34, 16 },
},
/*
@@ -246,6 +255,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -265,6 +276,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -284,6 +297,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -303,6 +318,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x20, 16 },
[SCLSR] = { 0x24, 16 },
[HSSRR] = { 0x40, 16 },
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -323,6 +340,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = { 0x24, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -343,6 +362,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = { 0x24, 16 },
[SCLSR] = { 0x28, 16 },
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
/*
@@ -363,6 +384,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
[SCSPTR] = sci_reg_invalid,
[SCLSR] = sci_reg_invalid,
[HSSRR] = sci_reg_invalid,
+ [SCPCR] = sci_reg_invalid,
+ [SCPDR] = sci_reg_invalid,
},
};
@@ -781,7 +804,7 @@ static int sci_handle_errors(struct uart_port *port)
struct sci_port *s = to_sci_port(port);
/* Handle overruns */
- if (status & (1 << s->overrun_bit)) {
+ if (status & s->overrun_mask) {
port->icount.overrun++;
/* overrun error */
@@ -844,32 +867,17 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
struct plat_sci_reg *reg;
- int copied = 0, offset;
- u16 status, bit;
-
- switch (port->type) {
- case PORT_SCIF:
- case PORT_HSCIF:
- offset = SCLSR;
- break;
- case PORT_SCIFA:
- case PORT_SCIFB:
- offset = SCxSR;
- break;
- default:
- return 0;
- }
+ int copied = 0;
+ u16 status;
- reg = sci_getreg(port, offset);
+ reg = sci_getreg(port, s->overrun_reg);
if (!reg->size)
return 0;
- status = serial_port_in(port, offset);
- bit = 1 << s->overrun_bit;
-
- if (status & bit) {
- status &= ~bit;
- serial_port_out(port, offset, status);
+ status = serial_port_in(port, s->overrun_reg);
+ if (status & s->overrun_mask) {
+ status &= ~s->overrun_mask;
+ serial_port_out(port, s->overrun_reg, status);
port->icount.overrun++;
@@ -1021,15 +1029,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ssr_status = serial_port_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR);
- switch (port->type) {
- case PORT_SCIF:
- case PORT_HSCIF:
- orer_status = serial_port_in(port, SCLSR);
- break;
- case PORT_SCIFA:
- case PORT_SCIFB:
+ if (s->overrun_reg == SCxSR)
orer_status = ssr_status;
- break;
+ else {
+ if (sci_getreg(port, s->overrun_reg)->size)
+ orer_status = serial_port_in(port, s->overrun_reg);
}
err_enabled = scr_status & port_rx_irq_mask(port);
@@ -1059,7 +1063,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
ret = sci_br_interrupt(irq, ptr);
/* Overrun Interrupt */
- if (orer_status & (1 << s->overrun_bit))
+ if (orer_status & s->overrun_mask)
sci_handle_fifo_overrun(port);
return ret;
@@ -2073,23 +2077,9 @@ static const char *sci_type(struct uart_port *port)
return NULL;
}
-static inline unsigned long sci_port_size(struct uart_port *port)
-{
- /*
- * Pick an arbitrary size that encapsulates all of the base
- * registers by default. This can be optimized later, or derived
- * from platform resource data at such a time that ports begin to
- * behave more erratically.
- */
- if (port->type == PORT_HSCIF)
- return 96;
- else
- return 64;
-}
-
static int sci_remap_port(struct uart_port *port)
{
- unsigned long size = sci_port_size(port);
+ struct sci_port *sport = to_sci_port(port);
/*
* Nothing to do if there's already an established membase.
@@ -2098,7 +2088,7 @@ static int sci_remap_port(struct uart_port *port)
return 0;
if (port->flags & UPF_IOREMAP) {
- port->membase = ioremap_nocache(port->mapbase, size);
+ port->membase = ioremap_nocache(port->mapbase, sport->reg_size);
if (unlikely(!port->membase)) {
dev_err(port->dev, "can't remap port#%d\n", port->line);
return -ENXIO;
@@ -2117,23 +2107,28 @@ static int sci_remap_port(struct uart_port *port)
static void sci_release_port(struct uart_port *port)
{
+ struct sci_port *sport = to_sci_port(port);
+
if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
port->membase = NULL;
}
- release_mem_region(port->mapbase, sci_port_size(port));
+ release_mem_region(port->mapbase, sport->reg_size);
}
static int sci_request_port(struct uart_port *port)
{
- unsigned long size = sci_port_size(port);
struct resource *res;
+ struct sci_port *sport = to_sci_port(port);
int ret;
- res = request_mem_region(port->mapbase, size, dev_name(port->dev));
- if (unlikely(res == NULL))
+ res = request_mem_region(port->mapbase, sport->reg_size,
+ dev_name(port->dev));
+ if (unlikely(res == NULL)) {
+ dev_err(port->dev, "request_mem_region failed.");
return -EBUSY;
+ }
ret = sci_remap_port(port);
if (unlikely(ret != 0)) {
@@ -2207,6 +2202,7 @@ static int sci_init_single(struct platform_device *dev,
return -ENOMEM;
port->mapbase = res->start;
+ sci_port->reg_size = resource_size(res);
for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i)
sci_port->irqs[i] = platform_get_irq(dev, i);
@@ -2234,32 +2230,38 @@ static int sci_init_single(struct platform_device *dev,
switch (p->type) {
case PORT_SCIFB:
port->fifosize = 256;
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
break;
case PORT_HSCIF:
port->fifosize = 128;
sampling_rate = 0;
- sci_port->overrun_bit = 0;
+ sci_port->overrun_reg = SCLSR;
+ sci_port->overrun_mask = SCLSR_ORER;
break;
case PORT_SCIFA:
port->fifosize = 64;
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
break;
case PORT_SCIF:
port->fifosize = 16;
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
- sci_port->overrun_bit = 9;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCIFA_ORER;
sampling_rate = 16;
} else {
- sci_port->overrun_bit = 0;
+ sci_port->overrun_reg = SCLSR;
+ sci_port->overrun_mask = SCLSR_ORER;
sampling_rate = 32;
}
break;
default:
port->fifosize = 1;
- sci_port->overrun_bit = 5;
+ sci_port->overrun_reg = SCxSR;
+ sci_port->overrun_mask = SCI_ORER;
sampling_rate = 32;
break;
}
@@ -2305,15 +2307,11 @@ static int sci_init_single(struct platform_device *dev,
SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
/*
- * Establish sensible defaults for the overrun detection, unless
- * the part has explicitly disabled support for it.
- */
-
- /*
* Make the error mask inclusive of overrun detection, if
* supported.
*/
- sci_port->error_mask |= 1 << sci_port->overrun_bit;
+ if (sci_port->overrun_reg == SCxSR)
+ sci_port->error_mask |= sci_port->overrun_mask;
port->type = p->type;
port->flags = UPF_FIXED_PORT | p->flags;
@@ -2536,6 +2534,12 @@ static const struct of_device_id of_sci_match[] = {
.regtype = SCIx_HSCIF_REGTYPE,
},
}, {
+ .compatible = "renesas,sci",
+ .data = &(const struct sci_port_info) {
+ .type = PORT_SCI,
+ .regtype = SCIx_SCI_REGTYPE,
+ },
+ }, {
/* Terminator */
},
};
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index d5db81a0a430..3393f67b4e84 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -1,7 +1,115 @@
+#include <linux/bitops.h>
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#define SCI_MAJOR 204
+#define SCI_MINOR_START 8
+
+
+/*
+ * SCI register subset common for all port types.
+ * Not all registers will exist on all parts.
+ */
+enum {
+ SCSMR, /* Serial Mode Register */
+ SCBRR, /* Bit Rate Register */
+ SCSCR, /* Serial Control Register */
+ SCxSR, /* Serial Status Register */
+ SCFCR, /* FIFO Control Register */
+ SCFDR, /* FIFO Data Count Register */
+ SCxTDR, /* Transmit (FIFO) Data Register */
+ SCxRDR, /* Receive (FIFO) Data Register */
+ SCLSR, /* Line Status Register */
+ SCTFDR, /* Transmit FIFO Data Count Register */
+ SCRFDR, /* Receive FIFO Data Count Register */
+ SCSPTR, /* Serial Port Register */
+ HSSRR, /* Sampling Rate Register */
+ SCPCR, /* Serial Port Control Register */
+ SCPDR, /* Serial Port Data Register */
+
+ SCIx_NR_REGS,
+};
+
+
+/* SCSMR (Serial Mode Register) */
+#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
+#define SCSMR_PE BIT(5) /* Parity Enable */
+#define SCSMR_ODD BIT(4) /* Odd Parity */
+#define SCSMR_STOP BIT(3) /* Stop Bit Length */
+#define SCSMR_CKS 0x0003 /* Clock Select */
+
+/* Serial Control Register, SCIFA/SCIFB only bits */
+#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
+#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
+
+/* SCxSR (Serial Status Register) on SCI */
+#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */
+#define SCI_RDRF BIT(6) /* Receive Data Register Full */
+#define SCI_ORER BIT(5) /* Overrun Error */
+#define SCI_FER BIT(4) /* Framing Error */
+#define SCI_PER BIT(3) /* Parity Error */
+#define SCI_TEND BIT(2) /* Transmit End */
+#define SCI_RESERVED 0x03 /* All reserved bits */
+
+#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
+
+#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
+#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
+#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+
+/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
+#define SCIF_ER BIT(7) /* Receive Error */
+#define SCIF_TEND BIT(6) /* Transmission End */
+#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */
+#define SCIF_BRK BIT(4) /* Break Detect */
+#define SCIF_FER BIT(3) /* Framing Error */
+#define SCIF_PER BIT(2) /* Parity Error */
+#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */
+#define SCIF_DR BIT(0) /* Receive Data Ready */
+/* SCIF only (optional) */
+#define SCIF_PERC 0xf000 /* Number of Parity Errors */
+#define SCIF_FERC 0x0f00 /* Number of Framing Errors */
+/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */
+#define SCIFA_ORER BIT(9) /* Overrun Error */
+
+#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
+
+#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF)
+#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
+#define SCIF_TDxE_CLEAR ~(SCIF_TDFE)
+#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK)
+
+/* SCFCR (FIFO Control Register) */
+#define SCFCR_MCE BIT(3) /* Modem Control Enable */
+#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
+#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
+#define SCFCR_LOOP BIT(0) /* Loopback Test */
+
+/* SCLSR (Line Status Register) on (H)SCIF */
+#define SCLSR_ORER BIT(0) /* Overrun Error */
+
+/* SCSPTR (Serial Port Register), optional */
+#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */
+#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */
+#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */
+#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */
+#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
+#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
+
+/* HSSRR HSCIF */
+#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
+
+/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
+#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */
+#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */
+
+/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
+#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
+#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */
+
+
#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
@@ -15,24 +123,24 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH73A0) || \
- defined(CONFIG_ARCH_SH7372) || \
defined(CONFIG_ARCH_R8A7740)
-# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc)
-# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73)
-# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf)
-# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3)
+# define SCxSR_RDxF_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
+# define SCxSR_ERROR_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
+# define SCxSR_TDxE_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
+# define SCxSR_BREAK_CLEAR(port) \
+ (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
#else
-# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
-# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
-# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
-# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+# define SCxSR_RDxF_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
+# define SCxSR_ERROR_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
+# define SCxSR_TDxE_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
+# define SCxSR_BREAK_CLEAR(port) \
+ ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
#endif
-/* SCFCR */
-#define SCFCR_RFRST 0x0002
-#define SCFCR_TFRST 0x0004
-#define SCFCR_MCE 0x0008
-
-#define SCI_MAJOR 204
-#define SCI_MINOR_START 8
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 9de3eabe5737..653cdd5fb508 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -36,8 +36,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
static struct uart_driver sirfsoc_uart_drv;
static void sirfsoc_uart_tx_dma_complete_callback(void *param);
-static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
-static void sirfsoc_uart_rx_dma_complete_callback(void *param);
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{4000000, 2359296},
{3500000, 1310721},
@@ -59,50 +57,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
{9600, 1114979},
};
-static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
- [0] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- },
- [1] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- },
- [2] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- },
- [3] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 3,
- },
- },
- [4] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 4,
- },
- },
- [5] = {
- .port = {
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 5,
- },
- },
-};
+static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR];
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
{
@@ -116,8 +71,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
-
- return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
+ return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0;
}
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
@@ -152,6 +106,26 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
unsigned int current_val;
+ if (mctrl & TIOCM_LOOP) {
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
+ wr_regl(port, ureg->sirfsoc_line_ctrl,
+ rd_regl(port, ureg->sirfsoc_line_ctrl) |
+ SIRFUART_LOOP_BACK);
+ else
+ wr_regl(port, ureg->sirfsoc_mode1,
+ rd_regl(port, ureg->sirfsoc_mode1) |
+ SIRFSOC_USP_LOOP_BACK_CTRL);
+ } else {
+ if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
+ wr_regl(port, ureg->sirfsoc_line_ctrl,
+ rd_regl(port, ureg->sirfsoc_line_ctrl) &
+ ~SIRFUART_LOOP_BACK);
+ else
+ wr_regl(port, ureg->sirfsoc_mode1,
+ rd_regl(port, ureg->sirfsoc_mode1) &
+ ~SIRFSOC_USP_LOOP_BACK_CTRL);
+ }
+
if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
return;
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
@@ -182,16 +156,19 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
}
} else {
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
+ ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
}
}
@@ -222,7 +199,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(uint_en->sirfsoc_txfifo_empty_en));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_txfifo_empty_en);
/*
* DMA requires buffer address and buffer length are both aligned with
@@ -290,8 +267,11 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
if (sirfport->tx_dma_chan)
sirfsoc_uart_tx_with_dma(sirfport);
else {
- sirfsoc_uart_pio_tx_chars(sirfport,
- SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+ wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
+ ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN);
+ wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+ sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
@@ -314,21 +294,25 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
+ ~(SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type) |
uint_en->sirfsoc_rx_done_en));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- SIRFUART_RX_DMA_INT_EN(port, uint_en)|
- uint_en->sirfsoc_rx_done_en);
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type)|
+ uint_en->sirfsoc_rx_done_en);
dmaengine_terminate_all(sirfport->rx_dma_chan);
} else {
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
- ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
+ ~(SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type)));
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
}
@@ -349,7 +333,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~uint_en->sirfsoc_cts_en);
else
- wr_regl(port, SIRFUART_INT_EN_CLR,
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
uint_en->sirfsoc_cts_en);
} else
disable_irq(gpio_to_irq(sirfport->cts_gpio));
@@ -379,7 +363,8 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) |
- SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
+ SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN |
+ SIRFUART_AFC_CTRL_RX_THD);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)
@@ -417,7 +402,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
if (!tty)
return -ENODEV;
while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
- ufifo_st->ff_empty(port->line))) {
+ ufifo_st->ff_empty(port))) {
ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
SIRFUART_DUMMY_READ;
if (unlikely(uart_handle_sysrq_char(port, ch)))
@@ -444,7 +429,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
unsigned int num_tx = 0;
while (!uart_circ_empty(xmit) &&
!(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
- ufifo_st->ff_full(port->line)) &&
+ ufifo_st->ff_full(port)) &&
count--) {
wr_regl(port, ureg->sirfsoc_tx_fifo_data,
xmit->buf[xmit->tail]);
@@ -478,139 +463,6 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
spin_unlock_irqrestore(&port->lock, flags);
}
-static void sirfsoc_uart_insert_rx_buf_to_tty(
- struct sirfsoc_uart_port *sirfport, int count)
-{
- struct uart_port *port = &sirfport->port;
- struct tty_port *tport = &port->state->port;
- int inserted;
-
- inserted = tty_insert_flip_string(tport,
- sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
- port->icount.rx += inserted;
-}
-
-static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
-{
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-
- sirfport->rx_dma_items[index].xmit.tail =
- sirfport->rx_dma_items[index].xmit.head = 0;
- sirfport->rx_dma_items[index].desc =
- dmaengine_prep_slave_single(sirfport->rx_dma_chan,
- sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
- if (!sirfport->rx_dma_items[index].desc) {
- dev_err(port->dev, "DMA slave single fail\n");
- return;
- }
- sirfport->rx_dma_items[index].desc->callback =
- sirfsoc_uart_rx_dma_complete_callback;
- sirfport->rx_dma_items[index].desc->callback_param = sirfport;
- sirfport->rx_dma_items[index].cookie =
- dmaengine_submit(sirfport->rx_dma_items[index].desc);
- dma_async_issue_pending(sirfport->rx_dma_chan);
-}
-
-static void sirfsoc_rx_tmo_process_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;
- 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(&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);
- sirfport->rx_completed++;
- sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
- }
- count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
- sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
- SIRFSOC_RX_DMA_BUF_SIZE);
- if (count > 0)
- sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
- wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
- rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
- SIRFUART_IO_MODE);
- sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
- if (sirfport->rx_io_count == 4) {
- sirfport->rx_io_count = 0;
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_done);
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_done_en);
- sirfsoc_uart_start_next_rx_dma(port);
- } else {
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_done);
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) |
- (uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- uint_en->sirfsoc_rx_done_en);
- }
- 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)
-{
- 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;
- struct dma_tx_state tx_state;
- dmaengine_tx_status(sirfport->rx_dma_chan,
- sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
- dmaengine_terminate_all(sirfport->rx_dma_chan);
- sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
- SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_timeout_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_timeout_en);
- tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
-}
-
-static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
-{
- 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;
- struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
-
- sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
- if (sirfport->rx_io_count == 4) {
- sirfport->rx_io_count = 0;
- if (!sirfport->is_atlas7)
- wr_regl(port, ureg->sirfsoc_int_en_reg,
- rd_regl(port, ureg->sirfsoc_int_en_reg) &
- ~(uint_en->sirfsoc_rx_done_en));
- else
- wr_regl(port, SIRFUART_INT_EN_CLR,
- uint_en->sirfsoc_rx_done_en);
- wr_regl(port, ureg->sirfsoc_int_st_reg,
- uint_st->sirfsoc_rx_timeout);
- sirfsoc_uart_start_next_rx_dma(port);
- }
-}
-
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
{
unsigned long intr_status;
@@ -628,20 +480,25 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
- if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
+ if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
+ sirfport->uart_reg->uart_type)))) {
if (intr_status & uint_st->sirfsoc_rxd_brk) {
port->icount.brk++;
if (uart_handle_break(port))
goto recv_char;
}
- if (intr_status & uint_st->sirfsoc_rx_oflow)
+ if (intr_status & uint_st->sirfsoc_rx_oflow) {
port->icount.overrun++;
+ flag = TTY_OVERRUN;
+ }
if (intr_status & uint_st->sirfsoc_frm_err) {
port->icount.frame++;
flag = TTY_FRAME;
}
- if (intr_status & uint_st->sirfsoc_parity_err)
+ if (intr_status & uint_st->sirfsoc_parity_err) {
+ port->icount.parity++;
flag = TTY_PARITY;
+ }
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);
@@ -662,15 +519,51 @@ recv_char:
uart_handle_cts_change(port, cts_status);
wake_up_interruptible(&state->port.delta_msr_wait);
}
- 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)
- sirfsoc_uart_handle_rx_done(sirfport);
- } else {
- if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
- sirfsoc_uart_pio_rx_chars(port,
- SIRFSOC_UART_IO_RX_MAX_CNT);
+ if (!sirfport->rx_dma_chan &&
+ (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) {
+ /*
+ * chip will trigger continuous RX_TIMEOUT interrupt
+ * in RXFIFO empty and not trigger if RXFIFO recevice
+ * data in limit time, original method use RX_TIMEOUT
+ * will trigger lots of useless interrupt in RXFIFO
+ * empty.RXFIFO received one byte will trigger RX_DONE
+ * interrupt.use RX_DONE to wait for data received
+ * into RXFIFO, use RX_THD/RX_FULL for lots data receive
+ * and use RX_TIMEOUT for the last left data.
+ */
+ if (intr_status & uint_st->sirfsoc_rx_done) {
+ if (!sirfport->is_atlas7) {
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ & ~(uint_en->sirfsoc_rx_done_en));
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ | (uint_en->sirfsoc_rx_timeout_en));
+ } else {
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
+ uint_en->sirfsoc_rx_done_en);
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_rx_timeout_en);
+ }
+ } else {
+ if (intr_status & uint_st->sirfsoc_rx_timeout) {
+ if (!sirfport->is_atlas7) {
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ & ~(uint_en->sirfsoc_rx_timeout_en));
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ rd_regl(port, ureg->sirfsoc_int_en_reg)
+ | (uint_en->sirfsoc_rx_done_en));
+ } else {
+ wr_regl(port,
+ ureg->sirfsoc_int_en_clr_reg,
+ uint_en->sirfsoc_rx_timeout_en);
+ wr_regl(port, ureg->sirfsoc_int_en_reg,
+ uint_en->sirfsoc_rx_done_en);
+ }
+ }
+ sirfsoc_uart_pio_rx_chars(port, port->fifosize);
+ }
}
spin_unlock(&port->lock);
tty_flip_buffer_push(&state->port);
@@ -684,10 +577,10 @@ recv_char:
return IRQ_HANDLED;
} else {
sirfsoc_uart_pio_tx_chars(sirfport,
- SIRFSOC_UART_IO_TX_REASONABLE_CNT);
+ port->fifosize);
if ((uart_circ_empty(xmit)) &&
(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
- ufifo_st->ff_empty(port->line)))
+ ufifo_st->ff_empty(port)))
sirfsoc_uart_stop_tx(port);
}
}
@@ -697,41 +590,8 @@ recv_char:
return IRQ_HANDLED;
}
-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;
- 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);
- 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(&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;
- unsigned long flags;
-
- spin_lock_irqsave(&sirfport->port.lock, flags);
- sirfport->rx_issued++;
- sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
- tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
- spin_unlock_irqrestore(&sirfport->port.lock, flags);
}
/* submit rx dma task into dmaengine */
@@ -740,21 +600,36 @@ 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;
- int i;
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);
- 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;
+ sirfport->rx_dma_items.xmit.tail =
+ sirfport->rx_dma_items.xmit.head = 0;
+ sirfport->rx_dma_items.desc =
+ dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
+ SIRFSOC_RX_DMA_BUF_SIZE / 2,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) {
+ dev_err(port->dev, "DMA slave single fail\n");
+ return;
+ }
+ sirfport->rx_dma_items.desc->callback =
+ sirfsoc_uart_rx_dma_complete_callback;
+ sirfport->rx_dma_items.desc->callback_param = sirfport;
+ sirfport->rx_dma_items.cookie =
+ dmaengine_submit(sirfport->rx_dma_items.desc);
+ dma_async_issue_pending(sirfport->rx_dma_chan);
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
- SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
- SIRFUART_RX_DMA_INT_EN(port, uint_en));
+ SIRFUART_RX_DMA_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
static void sirfsoc_uart_start_rx(struct uart_port *port)
@@ -773,10 +648,12 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
else
wr_regl(port, ureg->sirfsoc_int_en_reg,
- SIRFUART_RX_IO_INT_EN(port, uint_en));
+ SIRFUART_RX_IO_INT_EN(uint_en,
+ sirfport->uart_reg->uart_type));
}
}
@@ -789,7 +666,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate,
unsigned long ioclk_div = 0;
unsigned long temp_delta;
- for (sample_div = SIRF_MIN_SAMPLE_DIV;
+ for (sample_div = SIRF_USP_MIN_SAMPLE_DIV;
sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
temp_delta = ioclk_rate -
(ioclk_rate + (set_rate * sample_div) / 2)
@@ -910,10 +787,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
config_reg |= SIRFUART_STICK_BIT_MARK;
else
config_reg |= SIRFUART_STICK_BIT_SPACE;
- } else if (termios->c_cflag & PARODD) {
- config_reg |= SIRFUART_STICK_BIT_ODD;
} else {
- config_reg |= SIRFUART_STICK_BIT_EVEN;
+ if (termios->c_cflag & PARODD)
+ config_reg |= SIRFUART_STICK_BIT_ODD;
+ else
+ config_reg |= SIRFUART_STICK_BIT_EVEN;
}
}
} else {
@@ -976,7 +854,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
wr_regl(port, ureg->sirfsoc_tx_fifo_op,
(txfifo_op_reg & ~SIRFUART_FIFO_START));
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
- config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
+ config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out);
wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
} else {
/*tx frame ctrl*/
@@ -999,7 +877,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
/*async param*/
wr_regl(port, ureg->sirfsoc_async_param_reg,
- (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
+ (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) |
(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
SIRFSOC_USP_ASYNC_DIV2_OFFSET);
}
@@ -1011,6 +889,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
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);
+ sirfport->rx_period_time = 20000000;
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
if (set_baud < 1000000)
threshold_div = 1;
@@ -1032,19 +911,10 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- if (!state) {
- if (sirfport->is_bt_uart) {
- clk_prepare_enable(sirfport->clk_noc);
- clk_prepare_enable(sirfport->clk_general);
- }
+ if (!state)
clk_prepare_enable(sirfport->clk);
- } else {
+ else
clk_disable_unprepare(sirfport->clk);
- if (sirfport->is_bt_uart) {
- clk_disable_unprepare(sirfport->clk_general);
- clk_disable_unprepare(sirfport->clk_noc);
- }
- }
}
static int sirfsoc_uart_startup(struct uart_port *port)
@@ -1053,7 +923,7 @@ static int sirfsoc_uart_startup(struct uart_port *port)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
unsigned int index = port->line;
int ret;
- set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN);
ret = request_irq(port->irq,
sirfsoc_uart_isr,
0,
@@ -1064,7 +934,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
index, port->irq);
goto irq_err;
}
-
/* initial hardware settings */
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
@@ -1072,6 +941,9 @@ static int sirfsoc_uart_startup(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
SIRFUART_IO_MODE);
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+ ~SIRFUART_RX_DMA_FLUSH);
wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
@@ -1080,7 +952,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
SIRFSOC_USP_ENDIAN_CTRL_LSBF |
SIRFSOC_USP_EN);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
- wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
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_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
@@ -1100,8 +971,8 @@ static int sirfsoc_uart_startup(struct uart_port *port)
sirfport->ms_enabled = false;
if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
sirfport->hw_flow_ctrl) {
- set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
- IRQF_VALID | IRQF_NOAUTOEN);
+ irq_modify_status(gpio_to_irq(sirfport->cts_gpio),
+ IRQ_NOREQUEST, IRQ_NOAUTOEN);
ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
@@ -1110,8 +981,16 @@ static int sirfsoc_uart_startup(struct uart_port *port)
goto init_rx_err;
}
}
-
enable_irq(port->irq);
+ if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) {
+ sirfport->is_hrt_enabled = true;
+ sirfport->rx_period_time = 20000000;
+ sirfport->rx_dma_items.xmit.tail =
+ sirfport->rx_dma_items.xmit.head = 0;
+ hrtimer_start(&sirfport->hrt,
+ ns_to_ktime(sirfport->rx_period_time),
+ HRTIMER_MODE_REL);
+ }
return 0;
init_rx_err:
@@ -1127,7 +1006,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
else
- wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
+ wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL);
free_irq(port->irq, sirfport);
if (sirfport->ms_enabled)
@@ -1139,6 +1018,13 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
}
if (sirfport->tx_dma_chan)
sirfport->tx_dma_state = TX_DMA_IDLE;
+ if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) {
+ while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0)
+ ;
+ sirfport->is_hrt_enabled = false;
+ hrtimer_cancel(&sirfport->hrt);
+ }
}
static const char *sirfsoc_uart_type(struct uart_port *port)
@@ -1196,27 +1082,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options)
unsigned int bits = 8;
unsigned int parity = 'n';
unsigned int flow = 'n';
- struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
- struct sirfsoc_uart_port *sirfport = to_sirfport(port);
- struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+ struct sirfsoc_uart_port *sirfport;
+ struct sirfsoc_register *ureg;
if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
- return -EINVAL;
-
- if (!port->mapbase)
+ co->index = 1;
+ sirfport = sirf_ports[co->index];
+ if (!sirfport)
+ return -ENODEV;
+ ureg = &sirfport->uart_reg->uart_reg;
+ if (!sirfport->port.mapbase)
return -ENODEV;
/* enable usp in mode1 register */
if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
- wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
+ wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
SIRFSOC_USP_ENDIAN_CTRL_LSBF);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- port->cons = co;
+ sirfport->port.cons = co;
/* default console tx/rx transfer using io mode */
sirfport->rx_dma_chan = NULL;
sirfport->tx_dma_chan = NULL;
- return uart_set_options(port, co, baud, parity, bits, flow);
+ return uart_set_options(&sirfport->port, co, baud, parity, bits, flow);
}
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
@@ -1224,8 +1112,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
- while (rd_regl(port,
- ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
+ while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+ ufifo_st->ff_full(port))
cpu_relax();
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
}
@@ -1233,8 +1121,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
static void sirfsoc_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
- uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
+ struct sirfsoc_uart_port *sirfport = sirf_ports[co->index];
+
+ uart_console_write(&sirfport->port, s, count,
+ sirfsoc_uart_console_putchar);
}
static struct console sirfsoc_uart_console = {
@@ -1269,10 +1159,75 @@ static struct uart_driver sirfsoc_uart_drv = {
#endif
};
-static const struct of_device_id sirfsoc_uart_ids[] = {
+static enum hrtimer_restart
+ sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt)
+{
+ struct sirfsoc_uart_port *sirfport;
+ struct uart_port *port;
+ int count, inserted;
+ struct dma_tx_state tx_state;
+ struct tty_struct *tty;
+ struct sirfsoc_register *ureg;
+ struct circ_buf *xmit;
+
+ sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt);
+ port = &sirfport->port;
+ inserted = 0;
+ tty = port->state->port.tty;
+ ureg = &sirfport->uart_reg->uart_reg;
+ xmit = &sirfport->rx_dma_items.xmit;
+ dmaengine_tx_status(sirfport->rx_dma_chan,
+ sirfport->rx_dma_items.cookie, &tx_state);
+ xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ while (count > 0) {
+ inserted = tty_insert_flip_string(tty->port,
+ (const unsigned char *)&xmit->buf[xmit->tail], count);
+ if (!inserted)
+ goto next_hrt;
+ port->icount.rx += inserted;
+ xmit->tail = (xmit->tail + inserted) &
+ (SIRFSOC_RX_DMA_BUF_SIZE - 1);
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
+ SIRFSOC_RX_DMA_BUF_SIZE);
+ tty_flip_buffer_push(tty->port);
+ }
+ /*
+ * if RX DMA buffer data have all push into tty buffer, and there is
+ * only little data(less than a dma transfer unit) left in rxfifo,
+ * fetch it out in pio mode and switch back to dma immediately
+ */
+ if (!inserted && !count &&
+ ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0)) {
+ /* switch to pio mode */
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+ SIRFUART_IO_MODE);
+ while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+ SIRFUART_RX_FIFO_MASK) > 0) {
+ if (sirfsoc_uart_pio_rx_chars(port, 16) > 0)
+ tty_flip_buffer_push(tty->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);
+ /* switch back to dma mode */
+ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+ rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+ ~SIRFUART_IO_MODE);
+ }
+next_hrt:
+ hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time));
+ return HRTIMER_RESTART;
+}
+
+static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
+ { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp},
{}
};
MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
@@ -1283,7 +1238,6 @@ 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,
};
@@ -1293,16 +1247,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
const struct of_device_id *match;
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
- if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
- dev_err(&pdev->dev,
- "Unable to find cell-index in uart node.\n");
- ret = -EFAULT;
+ sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
+ if (!sirfport) {
+ ret = -ENOMEM;
goto err;
}
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
- pdev->id += ((struct sirfsoc_uart_register *)
- match->data)->uart_param.register_uart_nr;
- sirfport = &sirfsoc_uart_ports[pdev->id];
+ sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
+ sirf_ports[sirfport->port.line] = sirfport;
+ sirfport->port.iotype = UPIO_MEM;
+ sirfport->port.flags = UPF_BOOT_AUTOCONF;
port = &sirfport->port;
port->dev = &pdev->dev;
port->private_data = sirfport;
@@ -1310,9 +1263,12 @@ 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") ||
+ of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "sirf,prima2-usp-uart") || of_device_is_compatible(
+ pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
sirfport->uart_reg->uart_type = SIRF_USP_UART;
if (!sirfport->hw_flow_ctrl)
goto usp_no_flow_control;
@@ -1350,7 +1306,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
gpio_direction_output(sirfport->rts_gpio, 1);
}
usp_no_flow_control:
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
+ of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
sirfport->is_atlas7 = true;
if (of_property_read_u32(pdev->dev.of_node,
@@ -1368,12 +1325,9 @@ usp_no_flow_control:
ret = -EFAULT;
goto err;
}
- tasklet_init(&sirfport->rx_dma_complete_tasklet,
- sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
- tasklet_init(&sirfport->rx_tmo_process_tasklet,
- sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
port->mapbase = res->start;
- port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ port->membase = devm_ioremap(&pdev->dev,
+ res->start, resource_size(res));
if (!port->membase) {
dev_err(&pdev->dev, "Cannot remap resource.\n");
ret = -ENOMEM;
@@ -1393,20 +1347,6 @@ usp_no_flow_control:
goto err;
}
port->uartclk = clk_get_rate(sirfport->clk);
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
- sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
- if (IS_ERR(sirfport->clk_general)) {
- ret = PTR_ERR(sirfport->clk_general);
- goto err;
- }
- sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc");
- if (IS_ERR(sirfport->clk_noc)) {
- ret = PTR_ERR(sirfport->clk_noc);
- goto err;
- }
- sirfport->is_bt_uart = true;
- } else
- sirfport->is_bt_uart = false;
port->ops = &sirfsoc_uart_ops;
spin_lock_init(&port->lock);
@@ -1419,30 +1359,32 @@ usp_no_flow_control:
}
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;
+ sirfport->rx_dma_items.xmit.buf =
+ dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ &sirfport->rx_dma_items.dma_addr, GFP_KERNEL);
+ if (!sirfport->rx_dma_items.xmit.buf) {
+ dev_err(port->dev, "Uart alloc bufa failed\n");
+ ret = -ENOMEM;
+ goto alloc_coherent_err;
}
+ sirfport->rx_dma_items.xmit.head =
+ sirfport->rx_dma_items.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);
+ if (sirfport->rx_dma_chan) {
+ hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback;
+ sirfport->is_hrt_enabled = false;
+ }
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_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items.xmit.buf,
+ sirfport->rx_dma_items.dma_addr);
dma_release_channel(sirfport->rx_dma_chan);
err:
return ret;
@@ -1454,13 +1396,11 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
struct uart_port *port = &sirfport->port;
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);
+ dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+ sirfport->rx_dma_items.xmit.buf,
+ sirfport->rx_dma_items.dma_addr);
}
if (sirfport->tx_dma_chan) {
dmaengine_terminate_all(sirfport->tx_dma_chan);
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 727eb6b88fff..eb162b012eec 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -6,11 +6,11 @@
* Licensed under GPLv2 or later.
*/
#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/hrtimer.h>
struct sirfsoc_uart_param {
const char *uart_name;
const char *port_name;
- u32 uart_nr;
- u32 register_uart_nr;
};
struct sirfsoc_register {
@@ -21,6 +21,7 @@ struct sirfsoc_register {
u32 sirfsoc_tx_rx_en;
u32 sirfsoc_int_en_reg;
u32 sirfsoc_int_st_reg;
+ u32 sirfsoc_int_en_clr_reg;
u32 sirfsoc_tx_dma_io_ctrl;
u32 sirfsoc_tx_dma_io_len;
u32 sirfsoc_tx_fifo_ctrl;
@@ -45,8 +46,8 @@ struct sirfsoc_register {
u32 sirfsoc_async_param_reg;
};
-typedef u32 (*fifo_full_mask)(int line);
-typedef u32 (*fifo_empty_mask)(int line);
+typedef u32 (*fifo_full_mask)(struct uart_port *port);
+typedef u32 (*fifo_empty_mask)(struct uart_port *port);
struct sirfsoc_fifo_status {
fifo_full_mask ff_full;
@@ -105,21 +106,20 @@ struct sirfsoc_uart_register {
enum sirfsoc_uart_type uart_type;
};
-u32 usp_ff_full(int line)
+u32 uart_usp_ff_full_mask(struct uart_port *port)
{
- return 0x80;
-}
-u32 usp_ff_empty(int line)
-{
- return 0x100;
-}
-u32 uart_ff_full(int line)
-{
- return (line == 1) ? (0x20) : (0x80);
+ u32 full_bit;
+
+ full_bit = ilog2(port->fifosize);
+ return (1 << full_bit);
}
-u32 uart_ff_empty(int line)
+
+u32 uart_usp_ff_empty_mask(struct uart_port *port)
{
- return (line == 1) ? (0x40) : (0x100);
+ u32 empty_bit;
+
+ empty_bit = ilog2(port->fifosize) + 1;
+ return (1 << empty_bit);
}
struct sirfsoc_uart_register sirfsoc_usp = {
.uart_reg = {
@@ -145,6 +145,7 @@ struct sirfsoc_uart_register sirfsoc_usp = {
.sirfsoc_rx_fifo_op = 0x0130,
.sirfsoc_rx_fifo_status = 0x0134,
.sirfsoc_rx_fifo_data = 0x0138,
+ .sirfsoc_int_en_clr_reg = 0x140,
},
.uart_int_en = {
.sirfsoc_rx_done_en = BIT(0),
@@ -177,14 +178,12 @@ struct sirfsoc_uart_register sirfsoc_usp = {
.sirfsoc_rxd_brk = BIT(15),
},
.fifo_status = {
- .ff_full = usp_ff_full,
- .ff_empty = usp_ff_empty,
+ .ff_full = uart_usp_ff_full_mask,
+ .ff_empty = uart_usp_ff_empty_mask,
},
.uart_param = {
.uart_name = "ttySiRF",
.port_name = "sirfsoc-uart",
- .uart_nr = 2,
- .register_uart_nr = 3,
},
};
@@ -195,6 +194,7 @@ struct sirfsoc_uart_register sirfsoc_uart = {
.sirfsoc_divisor = 0x0050,
.sirfsoc_int_en_reg = 0x0054,
.sirfsoc_int_st_reg = 0x0058,
+ .sirfsoc_int_en_clr_reg = 0x0060,
.sirfsoc_tx_dma_io_ctrl = 0x0100,
.sirfsoc_tx_dma_io_len = 0x0104,
.sirfsoc_tx_fifo_ctrl = 0x0108,
@@ -249,14 +249,12 @@ struct sirfsoc_uart_register sirfsoc_uart = {
.sirfsoc_rts = BIT(15),
},
.fifo_status = {
- .ff_full = uart_ff_full,
- .ff_empty = uart_ff_empty,
+ .ff_full = uart_usp_ff_full_mask,
+ .ff_empty = uart_usp_ff_empty_mask,
},
.uart_param = {
.uart_name = "ttySiRF",
.port_name = "sirfsoc_uart",
- .uart_nr = 3,
- .register_uart_nr = 0,
},
};
/* uart io ctrl */
@@ -296,10 +294,10 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFUART_IO_MODE BIT(0)
#define SIRFUART_DMA_MODE 0x0
+#define SIRFUART_RX_DMA_FLUSH 0x4
-/* Macro Specific*/
-#define SIRFUART_INT_EN_CLR 0x0060
/* Baud Rate Calculation */
+#define SIRF_USP_MIN_SAMPLE_DIV 0x1
#define SIRF_MIN_SAMPLE_DIV 0xf
#define SIRF_MAX_SAMPLE_DIV 0x3f
#define SIRF_IOCLK_DIV_MAX 0xffff
@@ -326,55 +324,54 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24
#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f
#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16
-
+#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2)
/* USP-UART Common */
#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
#define SIRFUART_RECV_TIMEOUT_VALUE(x) \
(((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
-#define SIRFUART_RECV_TIMEOUT(port, x) \
- (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
+#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF)
+#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16)
-#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64)
-#define SIRFUART_ERR_INT_STAT(port, unit_st) \
+#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1)
+#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \
(uint_st->sirfsoc_rx_oflow | \
uint_st->sirfsoc_frm_err | \
uint_st->sirfsoc_rxd_brk | \
- ((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err))
-#define SIRFUART_RX_IO_INT_EN(port, uint_en) \
- (uint_en->sirfsoc_rx_timeout_en |\
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_st->sirfsoc_parity_err))
+#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \
+ (uint_en->sirfsoc_rx_done_en |\
uint_en->sirfsoc_rxfifo_thd_en |\
uint_en->sirfsoc_rxfifo_full_en |\
uint_en->sirfsoc_frm_err_en |\
uint_en->sirfsoc_rx_oflow_en |\
uint_en->sirfsoc_rxd_brk_en |\
- ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_en->sirfsoc_parity_err_en))
#define SIRFUART_RX_IO_INT_ST(uint_st) \
- (uint_st->sirfsoc_rx_timeout |\
- uint_st->sirfsoc_rxfifo_thd |\
- uint_st->sirfsoc_rxfifo_full)
+ (uint_st->sirfsoc_rxfifo_thd |\
+ uint_st->sirfsoc_rxfifo_full|\
+ uint_st->sirfsoc_rx_done |\
+ uint_st->sirfsoc_rx_timeout)
#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts)
-#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \
- (uint_en->sirfsoc_rx_timeout_en |\
- uint_en->sirfsoc_frm_err_en |\
+#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \
+ (uint_en->sirfsoc_frm_err_en |\
uint_en->sirfsoc_rx_oflow_en |\
uint_en->sirfsoc_rxd_brk_en |\
- ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+ ((uart_type != SIRF_REAL_UART) ? \
+ 0 : uint_en->sirfsoc_parity_err_en))
/* Generic Definitions */
#define SIRFSOC_UART_NAME "ttySiRF"
#define SIRFSOC_UART_MAJOR 0
#define SIRFSOC_UART_MINOR 0
#define SIRFUART_PORT_NAME "sirfsoc-uart"
#define SIRFUART_MAP_SIZE 0x200
-#define SIRFSOC_UART_NR 6
+#define SIRFSOC_UART_NR 11
#define SIRFSOC_PORT_TYPE 0xa5
/* Uart Common Use Macro*/
-#define SIRFSOC_RX_DMA_BUF_SIZE 256
+#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32)
#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3)
-#define LOOP_DMA_BUFA_FILL 1
-#define LOOP_DMA_BUFB_FILL 2
-#define TX_TRAN_PIO 1
-#define TX_TRAN_DMA 2
/* Uart Fifo Level Chk */
#define SIRFUART_TX_FIFO_SC_OFFSET 0
#define SIRFUART_TX_FIFO_LC_OFFSET 10
@@ -389,8 +386,8 @@ struct sirfsoc_uart_register sirfsoc_uart = {
#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
+#define SIRFUART_RX_FIFO_MASK 0x7f
/* Indicate how many buffers used */
-#define SIRFSOC_RX_LOOP_BUF_CNT 2
/* For Fast Baud Rate Calculation */
struct sirfsoc_baudrate_to_regv {
@@ -404,7 +401,7 @@ enum sirfsoc_tx_state {
TX_DMA_PAUSE,
};
-struct sirfsoc_loop_buffer {
+struct sirfsoc_rx_buffer {
struct circ_buf xmit;
dma_cookie_t cookie;
struct dma_async_tx_descriptor *desc;
@@ -417,10 +414,6 @@ struct sirfsoc_uart_port {
struct uart_port port;
struct clk *clk;
- /* UART6 for BT usage in A7DA platform need multi-clock source */
- bool is_bt_uart;
- struct clk *clk_general;
- struct clk *clk_noc;
/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
bool is_atlas7;
struct sirfsoc_uart_register *uart_reg;
@@ -428,17 +421,16 @@ struct sirfsoc_uart_port {
struct dma_chan *tx_dma_chan;
dma_addr_t tx_dma_addr;
struct dma_async_tx_descriptor *tx_dma_desc;
- struct tasklet_struct rx_dma_complete_tasklet;
- struct tasklet_struct rx_tmo_process_tasklet;
unsigned int rx_io_count;
unsigned long transfer_size;
enum sirfsoc_tx_state tx_dma_state;
unsigned int cts_gpio;
unsigned int rts_gpio;
- struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT];
- int rx_completed;
- int rx_issued;
+ struct sirfsoc_rx_buffer rx_dma_items;
+ struct hrtimer hrt;
+ bool is_hrt_enabled;
+ unsigned long rx_period_time;
};
/* Register Access Control */
@@ -447,10 +439,6 @@ struct sirfsoc_uart_port {
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
/* UART Port Mask */
-#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f))
-#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80))
-#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100))
-
-/* I/O Mode */
-#define SIRFSOC_UART_IO_RX_MAX_CNT 256
-#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256
+#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF)
+#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF)
+#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 582d2729f700..3866516c2926 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -716,7 +716,7 @@ static int sprd_probe(struct platform_device *pdev)
up->flags = UPF_BOOT_AUTOCONF;
clk = devm_clk_get(&pdev->dev, NULL);
- if (!IS_ERR(clk))
+ if (!IS_ERR_OR_NULL(clk))
up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
new file mode 100644
index 000000000000..4a6eab6da63e
--- /dev/null
+++ b/drivers/tty/serial/stm32-usart.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com>
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by st-asc.c from STMicroelectronics (c)
+ */
+
+#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "stm32-usart"
+
+/* Register offsets */
+#define USART_SR 0x00
+#define USART_DR 0x04
+#define USART_BRR 0x08
+#define USART_CR1 0x0c
+#define USART_CR2 0x10
+#define USART_CR3 0x14
+#define USART_GTPR 0x18
+
+/* USART_SR */
+#define USART_SR_PE BIT(0)
+#define USART_SR_FE BIT(1)
+#define USART_SR_NF BIT(2)
+#define USART_SR_ORE BIT(3)
+#define USART_SR_IDLE BIT(4)
+#define USART_SR_RXNE BIT(5)
+#define USART_SR_TC BIT(6)
+#define USART_SR_TXE BIT(7)
+#define USART_SR_LBD BIT(8)
+#define USART_SR_CTS BIT(9)
+#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
+ USART_SR_FE | USART_SR_PE)
+/* Dummy bits */
+#define USART_SR_DUMMY_RX BIT(16)
+
+/* USART_DR */
+#define USART_DR_MASK GENMASK(8, 0)
+
+/* USART_BRR */
+#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
+#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
+#define USART_BRR_DIV_M_SHIFT 4
+
+/* USART_CR1 */
+#define USART_CR1_SBK BIT(0)
+#define USART_CR1_RWU BIT(1)
+#define USART_CR1_RE BIT(2)
+#define USART_CR1_TE BIT(3)
+#define USART_CR1_IDLEIE BIT(4)
+#define USART_CR1_RXNEIE BIT(5)
+#define USART_CR1_TCIE BIT(6)
+#define USART_CR1_TXEIE BIT(7)
+#define USART_CR1_PEIE BIT(8)
+#define USART_CR1_PS BIT(9)
+#define USART_CR1_PCE BIT(10)
+#define USART_CR1_WAKE BIT(11)
+#define USART_CR1_M BIT(12)
+#define USART_CR1_UE BIT(13)
+#define USART_CR1_OVER8 BIT(15)
+#define USART_CR1_IE_MASK GENMASK(8, 4)
+
+/* USART_CR2 */
+#define USART_CR2_ADD_MASK GENMASK(3, 0)
+#define USART_CR2_LBDL BIT(5)
+#define USART_CR2_LBDIE BIT(6)
+#define USART_CR2_LBCL BIT(8)
+#define USART_CR2_CPHA BIT(9)
+#define USART_CR2_CPOL BIT(10)
+#define USART_CR2_CLKEN BIT(11)
+#define USART_CR2_STOP_2B BIT(13)
+#define USART_CR2_STOP_MASK GENMASK(13, 12)
+#define USART_CR2_LINEN BIT(14)
+
+/* USART_CR3 */
+#define USART_CR3_EIE BIT(0)
+#define USART_CR3_IREN BIT(1)
+#define USART_CR3_IRLP BIT(2)
+#define USART_CR3_HDSEL BIT(3)
+#define USART_CR3_NACK BIT(4)
+#define USART_CR3_SCEN BIT(5)
+#define USART_CR3_DMAR BIT(6)
+#define USART_CR3_DMAT BIT(7)
+#define USART_CR3_RTSE BIT(8)
+#define USART_CR3_CTSE BIT(9)
+#define USART_CR3_CTSIE BIT(10)
+#define USART_CR3_ONEBIT BIT(11)
+
+/* USART_GTPR */
+#define USART_GTPR_PSC_MASK GENMASK(7, 0)
+#define USART_GTPR_GT_MASK GENMASK(15, 8)
+
+#define DRIVER_NAME "stm32-usart"
+#define STM32_SERIAL_NAME "ttyS"
+#define STM32_MAX_PORTS 6
+
+struct stm32_port {
+ struct uart_port port;
+ struct clk *clk;
+ bool hw_flow_control;
+};
+
+static struct stm32_port stm32_ports[STM32_MAX_PORTS];
+static struct uart_driver stm32_usart_driver;
+
+static void stm32_stop_tx(struct uart_port *port);
+
+static inline struct stm32_port *to_stm32_port(struct uart_port *port)
+{
+ return container_of(port, struct stm32_port, port);
+}
+
+static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val |= bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
+{
+ u32 val;
+
+ val = readl_relaxed(port->membase + reg);
+ val &= ~bits;
+ writel_relaxed(val, port->membase + reg);
+}
+
+static void stm32_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ unsigned long c;
+ u32 sr;
+ char flag;
+
+ if (port->irq_wake)
+ pm_wakeup_event(tport->tty->dev, 0);
+
+ while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) {
+ sr |= USART_SR_DUMMY_RX;
+ c = readl_relaxed(port->membase + USART_DR);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (sr & USART_SR_ERR_MASK) {
+ if (sr & USART_SR_LBD) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & USART_SR_ORE) {
+ port->icount.overrun++;
+ } else if (sr & USART_SR_PE) {
+ port->icount.parity++;
+ } else if (sr & USART_SR_FE) {
+ port->icount.frame++;
+ }
+
+ sr &= port->read_status_mask;
+
+ if (sr & USART_SR_LBD)
+ flag = TTY_BREAK;
+ else if (sr & USART_SR_PE)
+ flag = TTY_PARITY;
+ else if (sr & USART_SR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, c))
+ continue;
+ uart_insert_char(port, sr, USART_SR_ORE, c, flag);
+ }
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(tport);
+ spin_lock(&port->lock);
+}
+
+static void stm32_transmit_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (port->x_char) {
+ writel_relaxed(port->x_char, port->membase + USART_DR);
+ port->x_char = 0;
+ port->icount.tx++;
+ return;
+ }
+
+ if (uart_tx_stopped(port)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ if (uart_circ_empty(xmit)) {
+ stm32_stop_tx(port);
+ return;
+ }
+
+ writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ stm32_stop_tx(port);
+}
+
+static irqreturn_t stm32_interrupt(int irq, void *ptr)
+{
+ struct uart_port *port = ptr;
+ u32 sr;
+
+ spin_lock(&port->lock);
+
+ sr = readl_relaxed(port->membase + USART_SR);
+
+ if (sr & USART_SR_RXNE)
+ stm32_receive_chars(port);
+
+ if (sr & USART_SR_TXE)
+ stm32_transmit_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int stm32_tx_empty(struct uart_port *port)
+{
+ return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE;
+}
+
+static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+ stm32_set_bits(port, USART_CR3, USART_CR3_RTSE);
+ else
+ stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE);
+}
+
+static unsigned int stm32_get_mctrl(struct uart_port *port)
+{
+ /* This routine is used to get signals of: DCD, DSR, RI, and CTS */
+ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* Transmit stop */
+static void stm32_stop_tx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE);
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void stm32_start_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+
+ if (uart_circ_empty(xmit))
+ return;
+
+ stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE);
+}
+
+/* Throttle the remote when input buffer is about to overflow. */
+static void stm32_throttle(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Unthrottle the remote, the input buffer can now accept data. */
+static void stm32_unthrottle(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* Receive stop */
+static void stm32_stop_rx(struct uart_port *port)
+{
+ stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE);
+}
+
+/* Handle breaks - ignored by us */
+static void stm32_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int stm32_startup(struct uart_port *port)
+{
+ const char *name = to_platform_device(port->dev)->name;
+ u32 val;
+ int ret;
+
+ ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
+ name, port);
+ if (ret)
+ return ret;
+
+ val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ return 0;
+}
+
+static void stm32_shutdown(struct uart_port *port)
+{
+ u32 val;
+
+ val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
+ stm32_set_bits(port, USART_CR1, val);
+
+ free_irq(port->irq, port);
+}
+
+static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct stm32_port *stm32_port = to_stm32_port(port);
+ unsigned int baud;
+ u32 usartdiv, mantissa, fraction, oversampling;
+ tcflag_t cflag = termios->c_cflag;
+ u32 cr1, cr2, cr3;
+ unsigned long flags;
+
+ if (!stm32_port->hw_flow_control)
+ cflag &= ~CRTSCTS;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Stop serial port and reset value */
+ writel_relaxed(0, port->membase + USART_CR1);
+
+ cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE;
+ cr2 = 0;
+ cr3 = 0;
+
+ if (cflag & CSTOPB)
+ cr2 |= USART_CR2_STOP_2B;
+
+ if (cflag & PARENB) {
+ cr1 |= USART_CR1_PCE;
+ if ((cflag & CSIZE) == CS8)
+ cr1 |= USART_CR1_M;
+ }
+
+ if (cflag & PARODD)
+ cr1 |= USART_CR1_PS;
+
+ port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
+ if (cflag & CRTSCTS) {
+ port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+ cr3 |= USART_CR3_CTSE;
+ }
+
+ usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+
+ /*
+ * The USART supports 16 or 8 times oversampling.
+ * By default we prefer 16 times oversampling, so that the receiver
+ * has a better tolerance to clock deviations.
+ * 8 times oversampling is only used to achieve higher speeds.
+ */
+ if (usartdiv < 16) {
+ oversampling = 8;
+ stm32_set_bits(port, USART_CR1, USART_CR1_OVER8);
+ } else {
+ oversampling = 16;
+ stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8);
+ }
+
+ mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
+ fraction = usartdiv % oversampling;
+ writel_relaxed(mantissa | fraction, port->membase + USART_BRR);
+
+ uart_update_timeout(port, cflag, baud);
+
+ port->read_status_mask = USART_SR_ORE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= USART_SR_LBD;
+
+ /* Characters to ignore */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= USART_SR_LBD;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= USART_SR_ORE;
+ }
+
+ /* Ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= USART_SR_DUMMY_RX;
+
+ writel_relaxed(cr3, port->membase + USART_CR3);
+ writel_relaxed(cr2, port->membase + USART_CR2);
+ writel_relaxed(cr1, port->membase + USART_CR1);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *stm32_type(struct uart_port *port)
+{
+ return (port->type == PORT_STM32) ? DRIVER_NAME : NULL;
+}
+
+static void stm32_release_port(struct uart_port *port)
+{
+}
+
+static int stm32_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void stm32_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_STM32;
+}
+
+static int
+stm32_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ /* No user changeable parameters */
+ return -EINVAL;
+}
+
+static void stm32_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct stm32_port *stm32port = container_of(port,
+ struct stm32_port, port);
+ unsigned long flags = 0;
+
+ switch (state) {
+ case UART_PM_STATE_ON:
+ clk_prepare_enable(stm32port->clk);
+ break;
+ case UART_PM_STATE_OFF:
+ spin_lock_irqsave(&port->lock, flags);
+ stm32_clr_bits(port, USART_CR1, USART_CR1_UE);
+ spin_unlock_irqrestore(&port->lock, flags);
+ clk_disable_unprepare(stm32port->clk);
+ break;
+ }
+}
+
+static const struct uart_ops stm32_uart_ops = {
+ .tx_empty = stm32_tx_empty,
+ .set_mctrl = stm32_set_mctrl,
+ .get_mctrl = stm32_get_mctrl,
+ .stop_tx = stm32_stop_tx,
+ .start_tx = stm32_start_tx,
+ .throttle = stm32_throttle,
+ .unthrottle = stm32_unthrottle,
+ .stop_rx = stm32_stop_rx,
+ .break_ctl = stm32_break_ctl,
+ .startup = stm32_startup,
+ .shutdown = stm32_shutdown,
+ .set_termios = stm32_set_termios,
+ .pm = stm32_pm,
+ .type = stm32_type,
+ .release_port = stm32_release_port,
+ .request_port = stm32_request_port,
+ .config_port = stm32_config_port,
+ .verify_port = stm32_verify_port,
+};
+
+static int stm32_init_port(struct stm32_port *stm32port,
+ struct platform_device *pdev)
+{
+ struct uart_port *port = &stm32port->port;
+ struct resource *res;
+ int ret;
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &stm32_uart_ops;
+ port->dev = &pdev->dev;
+ port->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ port->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
+ port->mapbase = res->start;
+
+ spin_lock_init(&port->lock);
+
+ stm32port->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(stm32port->clk))
+ return PTR_ERR(stm32port->clk);
+
+ /* Ensure that clk rate is correct by enabling the clk */
+ ret = clk_prepare_enable(stm32port->clk);
+ if (ret)
+ return ret;
+
+ stm32port->port.uartclk = clk_get_rate(stm32port->clk);
+ if (!stm32port->port.uartclk)
+ ret = -EINVAL;
+
+ clk_disable_unprepare(stm32port->clk);
+
+ return ret;
+}
+
+static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int id;
+
+ if (!np)
+ return NULL;
+
+ id = of_alias_get_id(np, "serial");
+ if (id < 0)
+ id = 0;
+
+ if (WARN_ON(id >= STM32_MAX_PORTS))
+ return NULL;
+
+ stm32_ports[id].hw_flow_control = of_property_read_bool(np,
+ "auto-flow-control");
+ stm32_ports[id].port.line = id;
+ return &stm32_ports[id];
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_match[] = {
+ { .compatible = "st,stm32-usart", },
+ { .compatible = "st,stm32-uart", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, stm32_match);
+#endif
+
+static int stm32_serial_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct stm32_port *stm32port;
+
+ stm32port = stm32_of_get_stm32_port(pdev);
+ if (!stm32port)
+ return -ENODEV;
+
+ ret = stm32_init_port(stm32port, pdev);
+ if (ret)
+ return ret;
+
+ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, &stm32port->port);
+
+ return 0;
+}
+
+static int stm32_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ return uart_remove_one_port(&stm32_usart_driver, port);
+}
+
+
+#ifdef CONFIG_SERIAL_STM32_CONSOLE
+static void stm32_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE))
+ cpu_relax();
+
+ writel_relaxed(ch, port->membase + USART_DR);
+}
+
+static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
+{
+ struct uart_port *port = &stm32_ports[co->index].port;
+ unsigned long flags;
+ u32 old_cr1, new_cr1;
+ 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);
+
+ /* Save and disable interrupts */
+ old_cr1 = readl_relaxed(port->membase + USART_CR1);
+ new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
+ writel_relaxed(new_cr1, port->membase + USART_CR1);
+
+ uart_console_write(port, s, cnt, stm32_console_putchar);
+
+ /* Restore interrupt state */
+ writel_relaxed(old_cr1, port->membase + USART_CR1);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int stm32_console_setup(struct console *co, char *options)
+{
+ struct stm32_port *stm32port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= STM32_MAX_PORTS)
+ return -ENODEV;
+
+ stm32port = &stm32_ports[co->index];
+
+ /*
+ * This driver does not support early console initialization
+ * (use ARM early printk support instead), so we only expect
+ * this to be called during the uart port registration when the
+ * driver gets probed and the port should be mapped at that point.
+ */
+ if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL)
+ return -ENXIO;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&stm32port->port, co, baud, parity, bits, flow);
+}
+
+static struct console stm32_console = {
+ .name = STM32_SERIAL_NAME,
+ .device = uart_console_device,
+ .write = stm32_console_write,
+ .setup = stm32_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &stm32_usart_driver,
+};
+
+#define STM32_SERIAL_CONSOLE (&stm32_console)
+
+#else
+#define STM32_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_STM32_CONSOLE */
+
+static struct uart_driver stm32_usart_driver = {
+ .driver_name = DRIVER_NAME,
+ .dev_name = STM32_SERIAL_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = STM32_MAX_PORTS,
+ .cons = STM32_SERIAL_CONSOLE,
+};
+
+static struct platform_driver stm32_serial_driver = {
+ .probe = stm32_serial_probe,
+ .remove = stm32_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(stm32_match),
+ },
+};
+
+static int __init usart_init(void)
+{
+ static char banner[] __initdata = "STM32 USART driver initialized";
+ int ret;
+
+ pr_info("%s\n", banner);
+
+ ret = uart_register_driver(&stm32_usart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&stm32_serial_driver);
+ if (ret)
+ uart_unregister_driver(&stm32_usart_driver);
+
+ return ret;
+}
+
+static void __exit usart_exit(void)
+{
+ platform_driver_unregister(&stm32_serial_driver);
+ uart_unregister_driver(&stm32_usart_driver);
+}
+
+module_init(usart_init);
+module_exit(usart_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 3ddbac767db3..009e0dbc12d2 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1075,7 +1075,8 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
}
-static void cdns_early_write(struct console *con, const char *s, unsigned n)
+static void __init cdns_early_write(struct console *con, const char *s,
+ unsigned n)
{
struct earlycon_device *dev = con->data;