summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/8250
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r--drivers/tty/serial/8250/8250.h14
-rw-r--r--drivers/tty/serial/8250/8250_accent.c13
-rw-r--r--drivers/tty/serial/8250/8250_acorn.c2
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c146
-rw-r--r--drivers/tty/serial/8250/8250_boca.c41
-rw-r--r--drivers/tty/serial/8250/8250_core.c30
-rw-r--r--drivers/tty/serial/8250/8250_dw.c137
-rw-r--r--drivers/tty/serial/8250/8250_early.c38
-rw-r--r--drivers/tty/serial/8250/8250_exar_st16c554.c17
-rw-r--r--drivers/tty/serial/8250/8250_fourport.c28
-rw-r--r--drivers/tty/serial/8250/8250_gsc.c7
-rw-r--r--drivers/tty/serial/8250/8250_hp300.c27
-rw-r--r--drivers/tty/serial/8250/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c14
-rw-r--r--drivers/tty/serial/8250/8250_mid.c35
-rw-r--r--drivers/tty/serial/8250/8250_moxa.c157
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c51
-rw-r--r--drivers/tty/serial/8250/8250_of.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c40
-rw-r--r--drivers/tty/serial/8250/8250_pci.c150
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c48
-rw-r--r--drivers/tty/serial/8250/8250_port.c453
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig50
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/8250/serial_cs.c90
26 files changed, 1124 insertions, 471 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index d54dcd87c..047a7ba67 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -92,6 +92,18 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0
#endif
+#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | (_flags), \
+ }
+
+#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
+
+
static inline int serial_in(struct uart_8250_port *up, int offset)
{
return up->port.serial_in(&up->port, offset);
@@ -117,6 +129,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
+int serial8250_em485_init(struct uart_8250_port *p);
+void serial8250_em485_destroy(struct uart_8250_port *p);
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
diff --git a/drivers/tty/serial/8250/8250_accent.c b/drivers/tty/serial/8250/8250_accent.c
index 34b51c651..522aeae05 100644
--- a/drivers/tty/serial/8250/8250_accent.c
+++ b/drivers/tty/serial/8250/8250_accent.c
@@ -10,18 +10,11 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port accent_data[] = {
- PORT(0x330, 4),
- PORT(0x338, 4),
+ SERIAL8250_PORT(0x330, 4),
+ SERIAL8250_PORT(0x338, 4),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c
index 549aa07c0..402dfdd49 100644
--- a/drivers/tty/serial/8250/8250_acorn.c
+++ b/drivers/tty/serial/8250/8250_acorn.c
@@ -70,7 +70,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
uart.port.regshift = 2;
uart.port.dev = &ec->dev;
- for (i = 0; i < info->num_ports; i ++) {
+ for (i = 0; i < info->num_ports; i++) {
uart.port.membase = info->vaddr + type->offset[i];
uart.port.mapbase = bus_addr + type->offset[i];
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
new file mode 100644
index 000000000..e10f12444
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -0,0 +1,146 @@
+/*
+ * Serial port driver for BCM2835AUX UART
+ *
+ * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
+ *
+ * Based on 8250_lpc18xx.c:
+ * Copyright (C) 2015 Joachim Eastwood <manabian@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"
+
+struct bcm2835aux_data {
+ struct uart_8250_port uart;
+ struct clk *clk;
+ int line;
+};
+
+static int bcm2835aux_serial_probe(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data;
+ struct resource *res;
+ int ret;
+
+ /* allocate the custom structure */
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* initialize data */
+ spin_lock_init(&data->uart.port.lock);
+ data->uart.capabilities = UART_CAP_FIFO;
+ data->uart.port.dev = &pdev->dev;
+ data->uart.port.regshift = 2;
+ data->uart.port.type = PORT_16550;
+ data->uart.port.iotype = UPIO_MEM;
+ data->uart.port.fifosize = 8;
+ data->uart.port.flags = UPF_SHARE_IRQ |
+ UPF_FIXED_PORT |
+ UPF_FIXED_TYPE |
+ UPF_SKIP_TEST;
+
+ /* get the clock - this also enables the HW */
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ ret = PTR_ERR_OR_ZERO(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+ return ret;
+ }
+
+ /* get the interrupt */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "irq not found - %i", ret);
+ return ret;
+ }
+ data->uart.port.irq = ret;
+
+ /* map the main registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "memory resource not found");
+ return -EINVAL;
+ }
+ data->uart.port.membase = devm_ioremap_resource(&pdev->dev, res);
+ ret = PTR_ERR_OR_ZERO(data->uart.port.membase);
+ if (ret)
+ return ret;
+
+ /* Check for a fixed line number */
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret >= 0)
+ data->uart.port.line = ret;
+
+ /* enable the clock as a last step */
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
+ ret);
+ return ret;
+ }
+
+ /* the HW-clock divider for bcm2835aux is 8,
+ * but 8250 expects a divider of 16,
+ * so we have to multiply the actual clock by 2
+ * to get identical baudrates.
+ */
+ data->uart.port.uartclk = clk_get_rate(data->clk) * 2;
+
+ /* register the port */
+ ret = serial8250_register_8250_port(&data->uart);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port - %d\n",
+ ret);
+ goto dis_clk;
+ }
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+dis_clk:
+ clk_disable_unprepare(data->clk);
+ return ret;
+}
+
+static int bcm2835aux_serial_remove(struct platform_device *pdev)
+{
+ struct bcm2835aux_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->uart.port.line);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835aux_serial_match[] = {
+ { .compatible = "brcm,bcm2835-aux-uart" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
+
+static struct platform_driver bcm2835aux_serial_driver = {
+ .driver = {
+ .name = "bcm2835-aux-uart",
+ .of_match_table = bcm2835aux_serial_match,
+ },
+ .probe = bcm2835aux_serial_probe,
+ .remove = bcm2835aux_serial_remove,
+};
+module_platform_driver(bcm2835aux_serial_driver);
+
+MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
+MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_boca.c b/drivers/tty/serial/8250/8250_boca.c
index d125dc107..a63b5998e 100644
--- a/drivers/tty/serial/8250/8250_boca.c
+++ b/drivers/tty/serial/8250/8250_boca.c
@@ -10,32 +10,25 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port boca_data[] = {
- PORT(0x100, 12),
- PORT(0x108, 12),
- PORT(0x110, 12),
- PORT(0x118, 12),
- PORT(0x120, 12),
- PORT(0x128, 12),
- PORT(0x130, 12),
- PORT(0x138, 12),
- PORT(0x140, 12),
- PORT(0x148, 12),
- PORT(0x150, 12),
- PORT(0x158, 12),
- PORT(0x160, 12),
- PORT(0x168, 12),
- PORT(0x170, 12),
- PORT(0x178, 12),
+ SERIAL8250_PORT(0x100, 12),
+ SERIAL8250_PORT(0x108, 12),
+ SERIAL8250_PORT(0x110, 12),
+ SERIAL8250_PORT(0x118, 12),
+ SERIAL8250_PORT(0x120, 12),
+ SERIAL8250_PORT(0x128, 12),
+ SERIAL8250_PORT(0x130, 12),
+ SERIAL8250_PORT(0x138, 12),
+ SERIAL8250_PORT(0x140, 12),
+ SERIAL8250_PORT(0x148, 12),
+ SERIAL8250_PORT(0x150, 12),
+ SERIAL8250_PORT(0x158, 12),
+ SERIAL8250_PORT(0x160, 12),
+ SERIAL8250_PORT(0x168, 12),
+ SERIAL8250_PORT(0x170, 12),
+ SERIAL8250_PORT(0x178, 12),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 279a842cd..11ccfa00c 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -597,6 +597,7 @@ static void univ8250_console_write(struct console *co, const char *s,
static int univ8250_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ int retval;
/*
* Check whether an invalid uart number has been specified, and
@@ -609,7 +610,10 @@ static int univ8250_console_setup(struct console *co, char *options)
/* link port to console */
port->cons = co;
- return serial8250_console_setup(port, options, false);
+ retval = serial8250_console_setup(port, options, false);
+ if (retval != 0)
+ port->cons = NULL;
+ return retval;
}
/**
@@ -687,7 +691,7 @@ static int __init univ8250_console_init(void)
}
console_initcall(univ8250_console_init);
-#define SERIAL8250_CONSOLE &univ8250_console
+#define SERIAL8250_CONSOLE (&univ8250_console)
#else
#define SERIAL8250_CONSOLE NULL
#endif
@@ -764,6 +768,7 @@ void serial8250_suspend_port(int line)
uart_suspend_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
@@ -789,6 +794,7 @@ void serial8250_resume_port(int line)
}
uart_resume_port(&serial8250_reg, port);
}
+EXPORT_SYMBOL(serial8250_resume_port);
/*
* Register a set of serial devices attached to a platform device. The
@@ -1068,6 +1074,15 @@ void serial8250_unregister_port(int line)
struct uart_8250_port *uart = &serial8250_ports[line];
mutex_lock(&serial_mutex);
+
+ if (uart->em485) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ serial8250_em485_destroy(uart);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+ }
+
uart_remove_one_port(&serial8250_reg, &uart->port);
if (serial8250_isa_devs) {
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
@@ -1093,9 +1108,8 @@ static int __init serial8250_init(void)
serial8250_isa_init_ports();
- printk(KERN_INFO "Serial: 8250/16550 driver, "
- "%d ports, IRQ sharing %sabled\n", nr_uarts,
- share_irqs ? "en" : "dis");
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
+ nr_uarts, share_irqs ? "en" : "dis");
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
@@ -1168,15 +1182,11 @@ static void __exit serial8250_exit(void)
module_init(serial8250_init);
module_exit(serial8250_exit);
-EXPORT_SYMBOL(serial8250_suspend_port);
-EXPORT_SYMBOL(serial8250_resume_port);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
module_param(share_irqs, uint, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
- " (unsafe)");
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
module_param(nr_uarts, uint, 0644);
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index a5d319e4a..a3fb95d85 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -68,12 +68,6 @@ struct dw8250_data {
unsigned int uart_16550_compatible:1;
};
-#define BYT_PRV_CLK 0x800
-#define BYT_PRV_CLK_EN (1 << 0)
-#define BYT_PRV_CLK_M_VAL_SHIFT 1
-#define BYT_PRV_CLK_N_VAL_SHIFT 16
-#define BYT_PRV_CLK_UPDATE (1 << 31)
-
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
@@ -95,25 +89,45 @@ static void dw8250_force_idle(struct uart_port *p)
(void)p->serial_in(p, UART_RX);
}
-static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+static void dw8250_check_lcr(struct uart_port *p, int value)
{
- writeb(value, p->membase + (offset << p->regshift));
+ void __iomem *offset = p->membase + (UART_LCR << p->regshift);
+ int tries = 1000;
/* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writeb(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
+ while (tries--) {
+ unsigned int lcr = p->serial_in(p, UART_LCR);
+
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
+
+ dw8250_force_idle(p);
+
+#ifdef CONFIG_64BIT
+ __raw_writeq(value & 0xff, offset);
+#else
+ if (p->iotype == UPIO_MEM32)
+ writel(value, offset);
+ else if (p->iotype == UPIO_MEM32BE)
+ iowrite32be(value, offset);
+ else
+ writeb(value, offset);
+#endif
}
+ /*
+ * FIXME: this deadlocks if port->lock is already held
+ * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
+ */
+}
+
+static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ writeb(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
@@ -135,49 +149,26 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- __raw_writeq(value & 0xff,
- p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
#endif /* CONFIG_64BIT */
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
+ struct dw8250_data *d = p->private_data;
+
writel(value, p->membase + (offset << p->regshift));
- /* Make sure LCR write wasn't ignored */
- if (offset == UART_LCR) {
- int tries = 1000;
- while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
- dw8250_force_idle(p);
- writel(value, p->membase + (UART_LCR << p->regshift));
- }
- /*
- * FIXME: this deadlocks if port->lock is already held
- * dev_err(p->dev, "Couldn't set LCR to %d\n", value);
- */
- }
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -187,14 +178,33 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
return dw8250_modify_msr(p, offset, value);
}
+static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
+{
+ struct dw8250_data *d = p->private_data;
+
+ iowrite32be(value, p->membase + (offset << p->regshift));
+
+ if (offset == UART_LCR && !d->uart_16550_compatible)
+ dw8250_check_lcr(p, value);
+}
+
+static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
+{
+ unsigned int value = ioread32be(p->membase + (offset << p->regshift));
+
+ return dw8250_modify_msr(p, offset, value);
+}
+
+
static int dw8250_handle_irq(struct uart_port *p)
{
struct dw8250_data *d = p->private_data;
unsigned int iir = p->serial_in(p, UART_IIR);
- if (serial8250_handle_irq(p, iir)) {
+ if (serial8250_handle_irq(p, iir))
return 1;
- } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+
+ if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
(void)p->serial_in(p, d->usr_reg);
@@ -281,6 +291,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
data->skip_autocfg = true;
}
#endif
+ if (of_device_is_big_endian(p->dev->of_node)) {
+ p->iotype = UPIO_MEM32BE;
+ p->serial_in = dw8250_serial_in32be;
+ p->serial_out = dw8250_serial_out32be;
+ }
} else if (has_acpi_companion(p->dev)) {
p->iotype = UPIO_MEM32;
p->regshift = 2;
@@ -309,14 +324,20 @@ static void dw8250_setup_port(struct uart_port *p)
* If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
*/
- reg = readl(p->membase + DW_UART_UCV);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_UCV);
+ else
+ reg = readl(p->membase + DW_UART_UCV);
if (!reg)
return;
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
- reg = readl(p->membase + DW_UART_CPR);
+ if (p->iotype == UPIO_MEM32BE)
+ reg = ioread32be(p->membase + DW_UART_CPR);
+ else
+ reg = readl(p->membase + DW_UART_CPR);
if (!reg)
return;
@@ -463,10 +484,8 @@ static int dw8250_probe(struct platform_device *pdev)
dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
- if (data->uart_16550_compatible) {
- p->serial_out = NULL;
+ if (data->uart_16550_compatible)
p->handle_irq = NULL;
- }
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 2aa151366..d3757a53c 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -39,15 +39,17 @@
static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
return readb(port->membase + offset);
case UPIO_MEM16:
- return readw(port->membase + (offset << 1));
+ return readw(port->membase + offset);
case UPIO_MEM32:
- return readl(port->membase + (offset << 2));
+ return readl(port->membase + offset);
case UPIO_MEM32BE:
- return ioread32be(port->membase + (offset << 2));
+ return ioread32be(port->membase + offset);
case UPIO_PORT:
return inb(port->iobase + offset);
default:
@@ -57,18 +59,20 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
{
+ offset <<= port->regshift;
+
switch (port->iotype) {
case UPIO_MEM:
writeb(value, port->membase + offset);
break;
case UPIO_MEM16:
- writew(value, port->membase + (offset << 1));
+ writew(value, port->membase + offset);
break;
case UPIO_MEM32:
- writel(value, port->membase + (offset << 2));
+ writel(value, port->membase + offset);
break;
case UPIO_MEM32BE:
- iowrite32be(value, port->membase + (offset << 2));
+ iowrite32be(value, port->membase + offset);
break;
case UPIO_PORT:
outb(value, port->iobase + offset);
@@ -145,3 +149,25 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
+OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
+
+#ifdef CONFIG_SERIAL_8250_OMAP
+
+static int __init early_omap8250_setup(struct earlycon_device *device,
+ const char *options)
+{
+ struct uart_port *port = &device->port;
+
+ if (!(device->port.membase || device->port.iobase))
+ return -ENODEV;
+
+ port->regshift = 2;
+ device->con->write = early_serial8250_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(omap8250, "ti,omap2-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap3-uart", early_omap8250_setup);
+OF_EARLYCON_DECLARE(omap8250, "ti,omap4-uart", early_omap8250_setup);
+
+#endif
diff --git a/drivers/tty/serial/8250/8250_exar_st16c554.c b/drivers/tty/serial/8250/8250_exar_st16c554.c
index bf53aabf9..3a7cb8262 100644
--- a/drivers/tty/serial/8250/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250/8250_exar_st16c554.c
@@ -13,20 +13,13 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF, \
- }
+#include "8250.h"
static struct plat_serial8250_port exar_data[] = {
- PORT(0x100, 5),
- PORT(0x108, 5),
- PORT(0x110, 5),
- PORT(0x118, 5),
+ SERIAL8250_PORT(0x100, 5),
+ SERIAL8250_PORT(0x108, 5),
+ SERIAL8250_PORT(0x110, 5),
+ SERIAL8250_PORT(0x118, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_fourport.c b/drivers/tty/serial/8250/8250_fourport.c
index be1582609..4045180a8 100644
--- a/drivers/tty/serial/8250/8250_fourport.c
+++ b/drivers/tty/serial/8250/8250_fourport.c
@@ -10,24 +10,20 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
- }
+#include "8250.h"
+
+#define SERIAL8250_FOURPORT(_base, _irq) \
+ SERIAL8250_PORT_FLAGS(_base, _irq, UPF_FOURPORT)
static struct plat_serial8250_port fourport_data[] = {
- PORT(0x1a0, 9),
- PORT(0x1a8, 9),
- PORT(0x1b0, 9),
- PORT(0x1b8, 9),
- PORT(0x2a0, 5),
- PORT(0x2a8, 5),
- PORT(0x2b0, 5),
- PORT(0x2b8, 5),
+ SERIAL8250_FOURPORT(0x1a0, 9),
+ SERIAL8250_FOURPORT(0x1a8, 9),
+ SERIAL8250_FOURPORT(0x1b0, 9),
+ SERIAL8250_FOURPORT(0x1b8, 9),
+ SERIAL8250_FOURPORT(0x2a0, 5),
+ SERIAL8250_FOURPORT(0x2a8, 5),
+ SERIAL8250_FOURPORT(0x2b0, 5),
+ SERIAL8250_FOURPORT(0x2b8, 5),
{ },
};
diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c
index 2e3ea1a70..b1e6ae9f1 100644
--- a/drivers/tty/serial/8250/8250_gsc.c
+++ b/drivers/tty/serial/8250/8250_gsc.c
@@ -42,7 +42,7 @@ static int __init serial_init_chip(struct parisc_device *dev)
* the user what they're missing.
*/
if (parisc_parent(dev)->id.hw_type != HPHW_IOA)
- printk(KERN_INFO
+ dev_info(&dev->dev,
"Serial: device 0x%llx not configured.\n"
"Enable support for Wax, Lasi, Asp or Dino.\n",
(unsigned long long)dev->hpa.start);
@@ -66,8 +66,9 @@ static int __init serial_init_chip(struct parisc_device *dev)
err = serial8250_register_8250_port(&uart);
if (err < 0) {
- printk(KERN_WARNING
- "serial8250_register_8250_port returned error %d\n", err);
+ dev_warn(&dev->dev,
+ "serial8250_register_8250_port returned error %d\n",
+ err);
iounmap(uart.port.membase);
return err;
}
diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c
index 2891958cd..38166db2b 100644
--- a/drivers/tty/serial/8250/8250_hp300.c
+++ b/drivers/tty/serial/8250/8250_hp300.c
@@ -24,8 +24,7 @@
#endif
#ifdef CONFIG_HPAPCI
-struct hp300_port
-{
+struct hp300_port {
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
};
@@ -111,7 +110,7 @@ int __init hp300_setup_serial_console(void)
/* Check for APCI console */
if (scode == 256) {
#ifdef CONFIG_HPAPCI
- printk(KERN_INFO "Serial console is HP APCI 1\n");
+ pr_info("Serial console is HP APCI 1\n");
port.uartclk = HPAPCI_BAUD_BASE * 16;
port.mapbase = (FRODO_BASE + FRODO_APCI_OFFSET(1));
@@ -119,7 +118,7 @@ int __init hp300_setup_serial_console(void)
port.regshift = 2;
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
+ pr_warn("Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n");
return 0;
#endif
} else {
@@ -128,7 +127,7 @@ int __init hp300_setup_serial_console(void)
if (!pa)
return 0;
- printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode);
+ pr_info("Serial console is HP DCA at select code %d\n", scode);
port.uartclk = HPDCA_BAUD_BASE * 16;
port.mapbase = (pa + UART_OFFSET);
@@ -142,13 +141,13 @@ int __init hp300_setup_serial_console(void)
if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80)
add_preferred_console("ttyS", port.line, "9600n8");
#else
- printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
+ pr_warn("Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n");
return 0;
#endif
}
if (early_serial_setup(&port) < 0)
- printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n");
+ pr_warn("%s: early_serial_setup() failed.\n", __func__);
return 0;
}
#endif /* CONFIG_SERIAL_8250_CONSOLE */
@@ -180,8 +179,9 @@ static int hpdca_init_one(struct dio_dev *d,
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
- " irq %d failed\n", d->scode, uart.port.irq);
+ dev_notice(&d->dev,
+ "8250_hp300: register_serial() DCA scode %d irq %d failed\n",
+ d->scode, uart.port.irq);
return -ENOMEM;
}
@@ -249,8 +249,8 @@ static int __init hp300_8250_init(void)
/* Memory mapped I/O */
uart.port.iotype = UPIO_MEM;
- uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
- | UPF_BOOT_AUTOCONF;
+ uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
uart.port.irq = 0;
uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
@@ -261,8 +261,9 @@ static int __init hp300_8250_init(void)
line = serial8250_register_8250_port(&uart);
if (line < 0) {
- printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
- " %d irq %d failed\n", i, uart.port.irq);
+ dev_notice(uart.port.dev,
+ "8250_hp300: register_serial() APCI %d irq %d failed\n",
+ i, uart.port.irq);
kfree(port);
continue;
}
diff --git a/drivers/tty/serial/8250/8250_hub6.c b/drivers/tty/serial/8250/8250_hub6.c
index a5c778e83..27124e21e 100644
--- a/drivers/tty/serial/8250/8250_hub6.c
+++ b/drivers/tty/serial/8250/8250_hub6.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
-#define HUB6(card,port) \
+#define HUB6(card, port) \
{ \
.iobase = 0x302, \
.irq = 3, \
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index d6e1ec9b4..b0677f610 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -48,7 +48,7 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6)
-#ifdef CONFIG_SERIAL_EARLYCON
+#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -154,14 +154,18 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
break;
case UART_IER:
- /* Enable receive timeout interrupt with the
- * receive line status interrupt */
+ /*
+ * Enable receive timeout interrupt with the receive line
+ * status interrupt.
+ */
value |= (value & 0x4) << 2;
break;
case UART_MCR:
- /* If we have enabled modem status IRQs we should enable modem
- * mode. */
+ /*
+ * If we have enabled modem status IRQs we should enable
+ * modem mode.
+ */
ier = p->serial_in(p, UART_IER);
if (ier & UART_IER_MSI)
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 88531a36b..ed489880e 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/dma/hsu.h>
+#include <linux/8250_pci.h>
#include "8250.h"
@@ -24,6 +25,7 @@
#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8
/* Intel MID Specific registers */
+#define INTEL_MID_UART_DNV_FISR 0x08
#define INTEL_MID_UART_PS 0x30
#define INTEL_MID_UART_MUL 0x34
#define INTEL_MID_UART_DIV 0x38
@@ -31,6 +33,7 @@
struct mid8250;
struct mid8250_board {
+ unsigned int flags;
unsigned long freq;
unsigned int base_baud;
int (*setup)(struct mid8250 *, struct uart_port *p);
@@ -88,16 +91,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
static int dnv_handle_irq(struct uart_port *p)
{
struct mid8250 *mid = p->private_data;
- int ret;
-
- ret = hsu_dma_irq(&mid->dma_chip, 0);
- ret |= hsu_dma_irq(&mid->dma_chip, 1);
-
- /* For now, letting the HW generate separate interrupt for the UART */
- if (ret)
- return ret;
-
- return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
+ int ret = IRQ_NONE;
+
+ if (fisr & BIT(2))
+ ret |= hsu_dma_irq(&mid->dma_chip, 1);
+ if (fisr & BIT(1))
+ ret |= hsu_dma_irq(&mid->dma_chip, 0);
+ if (fisr & BIT(0))
+ ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+ return ret;
}
#define DNV_DMA_CHAN_OFFSET 0x80
@@ -106,12 +109,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
{
struct hsu_dma_chip *chip = &mid->dma_chip;
struct pci_dev *pdev = to_pci_dev(p->dev);
+ unsigned int bar = FL_GET_BASE(mid->board->flags);
int ret;
chip->dev = &pdev->dev;
chip->irq = pdev->irq;
chip->regs = p->membase;
- chip->length = pci_resource_len(pdev, 0);
+ chip->length = pci_resource_len(pdev, bar);
chip->offset = DNV_DMA_CHAN_OFFSET;
/* Falling back to PIO mode if DMA probing fails */
@@ -217,6 +221,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct uart_8250_port uart;
struct mid8250 *mid;
+ unsigned int bar;
int ret;
ret = pcim_enable_device(pdev);
@@ -230,6 +235,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
mid->board = (struct mid8250_board *)id->driver_data;
+ bar = FL_GET_BASE(mid->board->flags);
memset(&uart, 0, sizeof(struct uart_8250_port));
@@ -242,8 +248,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.set_termios = mid8250_set_termios;
- uart.port.mapbase = pci_resource_start(pdev, 0);
- uart.port.membase = pcim_iomap(pdev, 0, 0);
+ uart.port.mapbase = pci_resource_start(pdev, bar);
+ uart.port.membase = pcim_iomap(pdev, bar, 0);
if (!uart.port.membase)
return -ENOMEM;
@@ -282,18 +288,21 @@ static void mid8250_remove(struct pci_dev *pdev)
}
static const struct mid8250_board pnw_board = {
+ .flags = FL_BASE0,
.freq = 50000000,
.base_baud = 115200,
.setup = pnw_setup,
};
static const struct mid8250_board tng_board = {
+ .flags = FL_BASE0,
.freq = 38400000,
.base_baud = 1843200,
.setup = tng_setup,
};
static const struct mid8250_board dnv_board = {
+ .flags = FL_BASE1,
.freq = 133333333,
.base_baud = 115200,
.setup = dnv_setup,
diff --git a/drivers/tty/serial/8250/8250_moxa.c b/drivers/tty/serial/8250/8250_moxa.c
new file mode 100644
index 000000000..26eb5393a
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_moxa.c
@@ -0,0 +1,157 @@
+/*
+ * 8250_moxa.c - MOXA Smartio/Industio MUE multiport serial driver.
+ *
+ * Author: Mathieu OTHACEHE <m.othacehe@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/module.h>
+#include <linux/pci.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
+#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
+#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
+#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
+#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
+#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
+#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
+#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
+#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
+#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
+#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
+#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+
+#define MOXA_BASE_BAUD 921600
+#define MOXA_UART_OFFSET 0x200
+#define MOXA_BASE_BAR 1
+
+struct moxa8250_board {
+ unsigned int num_ports;
+ int line[0];
+};
+
+enum {
+ moxa8250_2p = 0,
+ moxa8250_4p,
+ moxa8250_8p
+};
+
+static struct moxa8250_board moxa8250_boards[] = {
+ [moxa8250_2p] = { .num_ports = 2},
+ [moxa8250_4p] = { .num_ports = 4},
+ [moxa8250_8p] = { .num_ports = 8},
+};
+
+static int moxa8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct uart_8250_port uart;
+ struct moxa8250_board *brd;
+ void __iomem *ioaddr;
+ resource_size_t baseaddr;
+ unsigned int i, nr_ports;
+ unsigned int offset;
+ int ret;
+
+ brd = &moxa8250_boards[id->driver_data];
+ nr_ports = brd->num_ports;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ brd = devm_kzalloc(&pdev->dev, sizeof(struct moxa8250_board) +
+ sizeof(unsigned int) * nr_ports, GFP_KERNEL);
+ if (!brd)
+ return -ENOMEM;
+
+ memset(&uart, 0, sizeof(struct uart_8250_port));
+
+ uart.port.dev = &pdev->dev;
+ uart.port.irq = pdev->irq;
+ uart.port.uartclk = MOXA_BASE_BAUD * 16;
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+ baseaddr = pci_resource_start(pdev, MOXA_BASE_BAR);
+ ioaddr = pcim_iomap(pdev, MOXA_BASE_BAR, 0);
+ if (!ioaddr)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_ports; i++) {
+
+ /*
+ * MOXA Smartio MUE boards with 4 ports have
+ * a different offset for port #3
+ */
+ if (nr_ports == 4 && i == 3)
+ offset = 7 * MOXA_UART_OFFSET;
+ else
+ offset = i * MOXA_UART_OFFSET;
+
+ uart.port.iotype = UPIO_MEM;
+ uart.port.iobase = 0;
+ uart.port.mapbase = baseaddr + offset;
+ uart.port.membase = ioaddr + offset;
+ uart.port.regshift = 0;
+
+ dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
+ uart.port.iobase, uart.port.irq, uart.port.iotype);
+
+ brd->line[i] = serial8250_register_8250_port(&uart);
+ if (brd->line[i] < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
+ uart.port.iobase, uart.port.irq,
+ uart.port.iotype, brd->line[i]);
+ break;
+ }
+ }
+
+ pci_set_drvdata(pdev, brd);
+ return 0;
+}
+
+static void moxa8250_remove(struct pci_dev *pdev)
+{
+ struct moxa8250_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->num_ports; i++)
+ serial8250_unregister_port(brd->line[i]);
+}
+
+#define MOXA_DEVICE(id, data) { PCI_VDEVICE(MOXA, id), (kernel_ulong_t)data }
+
+static const struct pci_device_id pci_ids[] = {
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102E, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP102EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP104EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP114EL, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP116E_A_B, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118EL_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP118E_A_I, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP132EL, moxa8250_2p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP134EL_A, moxa8250_4p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP138E_A, moxa8250_8p),
+ MOXA_DEVICE(PCI_DEVICE_ID_MOXA_CP168EL_A, moxa8250_8p),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver moxa8250_pci_driver = {
+ .name = "8250_moxa",
+ .id_table = pci_ids,
+ .probe = moxa8250_probe,
+ .remove = moxa8250_remove,
+};
+
+module_pci_driver(moxa8250_pci_driver);
+
+MODULE_AUTHOR("Mathieu OTHACEHE");
+MODULE_DESCRIPTION("MOXA SmartIO MUE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 0e590b233..3489fbcb7 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -16,7 +16,7 @@
*/
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@@ -41,12 +41,10 @@ static void
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
unsigned int baud, quot;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
-
serial8250_do_set_termios(port, termios, old);
/*
@@ -116,7 +114,7 @@ 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)
+static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -126,7 +124,7 @@ static int mtk8250_runtime_suspend(struct device *dev)
return 0;
}
-static int mtk8250_runtime_resume(struct device *dev)
+static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
int err;
@@ -245,8 +243,24 @@ static int mtk8250_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int mtk8250_suspend(struct device *dev)
+static int mtk8250_remove(struct platform_device *pdev)
+{
+ struct mtk8250_data *data = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ serial8250_unregister_port(data->line);
+
+ 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;
+}
+
+static int __maybe_unused mtk8250_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -255,7 +269,7 @@ static int mtk8250_suspend(struct device *dev)
return 0;
}
-static int mtk8250_resume(struct device *dev)
+static int __maybe_unused mtk8250_resume(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
@@ -263,7 +277,6 @@ static int mtk8250_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops mtk8250_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
@@ -275,20 +288,20 @@ static const struct of_device_id mtk8250_of_match[] = {
{ .compatible = "mediatek,mt6577-uart" },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mtk8250_of_match);
static struct platform_driver mtk8250_platform_driver = {
.driver = {
- .name = "mt6577-uart",
- .pm = &mtk8250_pm_ops,
- .of_match_table = mtk8250_of_match,
- .suppress_bind_attrs = true,
-
+ .name = "mt6577-uart",
+ .pm = &mtk8250_pm_ops,
+ .of_match_table = mtk8250_of_match,
},
.probe = mtk8250_probe,
+ .remove = mtk8250_remove,
};
-builtin_platform_driver(mtk8250_platform_driver);
+module_platform_driver(mtk8250_platform_driver);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init early_mtk8250_setup(struct earlycon_device *device,
const char *options)
{
@@ -302,3 +315,7 @@ static int __init early_mtk8250_setup(struct earlycon_device *device,
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_of.c b/drivers/tty/serial/8250/8250_of.c
index 33021c1f7..c7ed3d2bc 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -335,6 +335,7 @@ static struct platform_driver of_platform_serial_driver = {
.driver = {
.name = "of_serial",
.of_match_table = of_platform_serial_table,
+ .pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
.remove = of_platform_serial_remove,
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index a2c0734c7..6f760510e 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -318,8 +318,7 @@ static void omap_8250_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = up->port.private_data;
unsigned char cval = 0;
unsigned int baud;
@@ -682,9 +681,8 @@ static void omap_8250_shutdown(struct uart_port *port)
static void omap_8250_throttle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -697,11 +695,40 @@ static void omap_8250_throttle(struct uart_port *port)
pm_runtime_put_autosuspend(port->dev);
}
+static int omap_8250_rs485_config(struct uart_port *port,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* Clamp the delays to [0, 100ms] */
+ rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+ rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
+
+ port->rs485 = *rs485;
+
+ /*
+ * Both serial8250_em485_init and serial8250_em485_destroy
+ * are idempotent
+ */
+ if (rs485->flags & SER_RS485_ENABLED) {
+ int ret = serial8250_em485_init(up);
+
+ if (ret) {
+ rs485->flags &= ~SER_RS485_ENABLED;
+ port->rs485.flags &= ~SER_RS485_ENABLED;
+ }
+ return ret;
+ }
+
+ serial8250_em485_destroy(up);
+
+ return 0;
+}
+
static void omap_8250_unthrottle(struct uart_port *port)
{
+ struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
pm_runtime_get_sync(port->dev);
@@ -1146,6 +1173,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.shutdown = omap_8250_shutdown;
up.port.throttle = omap_8250_throttle;
up.port.unthrottle = omap_8250_unthrottle;
+ up.port.rs485_config = omap_8250_rs485_config;
if (pdev->dev.of_node) {
const struct of_device_id *id;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 7cd6f9a90..4eedd1da3 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -55,7 +55,6 @@ struct pci_serial_quirk {
struct serial_private {
struct pci_dev *dev;
unsigned int nr;
- void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
struct pci_serial_quirk *quirk;
int line[0];
};
@@ -85,15 +84,13 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
- if (!priv->remapped_bar[bar])
+ if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
return -ENOMEM;
port->port.iotype = UPIO_MEM;
port->port.iobase = 0;
port->port.mapbase = pci_resource_start(dev, bar) + offset;
- port->port.membase = priv->remapped_bar[bar] + offset;
+ port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
} else {
port->port.iotype = UPIO_PORT;
@@ -721,7 +718,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
*/
pcibios_resource_to_bus(dev->bus, &region, &dev->resource[bar]);
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
- | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
+ | MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
writel(device_window, p + MITE_IOWBSR1);
/* Set window access to go to RAMSEL IO address space */
@@ -803,12 +800,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
unsigned int pi;
unsigned short sub_serports;
- pi = (c & 0xff);
+ pi = c & 0xff;
- if (pi == 2) {
+ if (pi == 2)
return 1;
- } else if ((pi == 0) &&
- (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
+
+ if ((pi == 0) && (dev->device == PCI_DEVICE_ID_NETMOS_9900)) {
/* two possibilities: 0x30ps encodes number of parallel and
* serial ports, or 0x1000 indicates *something*. This is not
* immediately obvious, since the 2s1p+4s configuration seems
@@ -816,12 +813,12 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
* advertising the same function 3 as the 4s+2s1p config.
*/
sub_serports = dev->subsystem_device & 0xf;
- if (sub_serports > 0) {
+ if (sub_serports > 0)
return sub_serports;
- } else {
- dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
- return 0;
- }
+
+ dev_err(&dev->dev,
+ "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
+ return 0;
}
moan_device("unknown NetMos/Mostech program interface", dev);
@@ -842,21 +839,21 @@ static int pci_netmos_init(struct pci_dev *dev)
return 0;
switch (dev->device) { /* FALLTHROUGH on all */
- case PCI_DEVICE_ID_NETMOS_9904:
- case PCI_DEVICE_ID_NETMOS_9912:
- case PCI_DEVICE_ID_NETMOS_9922:
- case PCI_DEVICE_ID_NETMOS_9900:
- num_serial = pci_netmos_9900_numports(dev);
- break;
+ case PCI_DEVICE_ID_NETMOS_9904:
+ case PCI_DEVICE_ID_NETMOS_9912:
+ case PCI_DEVICE_ID_NETMOS_9922:
+ case PCI_DEVICE_ID_NETMOS_9900:
+ num_serial = pci_netmos_9900_numports(dev);
+ break;
- default:
- if (num_serial == 0 ) {
- moan_device("unknown NetMos/Mostech device", dev);
- }
+ default:
+ break;
}
- if (num_serial == 0)
+ if (num_serial == 0) {
+ moan_device("unknown NetMos/Mostech device", dev);
return -ENODEV;
+ }
return num_serial;
}
@@ -1198,8 +1195,9 @@ static int pci_quatech_has_qmcr(struct uart_8250_port *port)
static int pci_quatech_test(struct uart_8250_port *port)
{
- u8 reg;
- u8 qopr = pci_quatech_rqopr(port);
+ u8 reg, qopr;
+
+ qopr = pci_quatech_rqopr(port);
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
reg = pci_quatech_rqopr(port) & 0xC0;
if (reg != QPCR_TEST_GET1)
@@ -1286,6 +1284,7 @@ static int pci_quatech_init(struct pci_dev *dev)
unsigned long base = pci_resource_start(dev, 0);
if (base) {
u32 tmp;
+
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
tmp = inl(base + 0x3c);
outl(tmp | 0x01000000, base + 0x3c);
@@ -1334,29 +1333,6 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-static int pci_pericom_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
-{
- unsigned int bar, offset = board->first_offset, maxnr;
-
- bar = FL_GET_BASE(board->flags);
- if (board->flags & FL_BASE_BARS)
- bar += idx;
- else
- offset += idx * board->uart_offset;
-
- maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
- (board->reg_shift + 3);
-
- if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
- return 1;
-
- port->port.uartclk = 14745600;
-
- return setup_port(priv, port, bar, offset, board->reg_shift);
-}
-
static int
ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
@@ -1401,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
unsigned long m, n;
u32 reg;
+ /* Gracefully handle the B0 case: fall back to B9600 */
+ fuart = fuart ? fuart : 9600 * 16;
+
/* Get Fuart closer to Fref */
fuart *= rounddown_pow_of_two(fref / fuart);
@@ -1541,10 +1520,9 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
static int pci_fintek_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
+ struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
u8 *index = (u8 *) port->private_data;
- struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
- dev);
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
@@ -1766,7 +1744,7 @@ 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));
+ (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358));
}
static int
@@ -1866,8 +1844,8 @@ pci_fastcom335_setup(struct serial_private *priv,
static int
pci_wch_ch353_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
@@ -1876,8 +1854,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
static int
pci_wch_ch38x_setup(struct serial_private *priv,
- const struct pciserial_board *board,
- struct uart_8250_port *port, int idx)
+ const struct pciserial_board *board,
+ struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16850;
@@ -2246,16 +2224,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.exit = pci_plx9050_exit,
},
/*
- * Pericom
- */
- {
- .vendor = PCI_VENDOR_ID_PERICOM,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .setup = pci_pericom_setup,
- },
- /*
* PLX
*/
{
@@ -3733,15 +3701,10 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600,
.reg_shift = 2,
},
- /*
- * Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
- * but is overridden by byt_set_termios.
- */
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
- .uart_offset = 0x80,
.reg_shift = 2,
},
[pbn_qrk] = {
@@ -3840,6 +3803,20 @@ static const struct pci_device_id blacklist[] = {
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
+ /* Moxa Smartio MUE boards handled by 8250_moxa */
+ { PCI_VDEVICE(MOXA, 0x1024), },
+ { PCI_VDEVICE(MOXA, 0x1025), },
+ { PCI_VDEVICE(MOXA, 0x1045), },
+ { PCI_VDEVICE(MOXA, 0x1144), },
+ { PCI_VDEVICE(MOXA, 0x1160), },
+ { PCI_VDEVICE(MOXA, 0x1161), },
+ { PCI_VDEVICE(MOXA, 0x1182), },
+ { PCI_VDEVICE(MOXA, 0x1183), },
+ { PCI_VDEVICE(MOXA, 0x1322), },
+ { PCI_VDEVICE(MOXA, 0x1342), },
+ { PCI_VDEVICE(MOXA, 0x1381), },
+ { PCI_VDEVICE(MOXA, 0x1683), },
+
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), },
{ PCI_VDEVICE(INTEL, 0x081c), },
@@ -4027,12 +4004,6 @@ void pciserial_remove_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
- for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
- if (priv->remapped_bar[i])
- iounmap(priv->remapped_bar[i]);
- priv->remapped_bar[i] = NULL;
- }
-
/*
* Find the exit quirks.
*/
@@ -4104,7 +4075,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
board = &pci_boards[ent->driver_data];
- rc = pci_enable_device(dev);
+ rc = pcim_enable_device(dev);
pci_save_state(dev);
if (rc)
return rc;
@@ -4123,7 +4094,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
*/
rc = serial_pci_guess_board(dev, &tmp);
if (rc)
- goto disable;
+ return rc;
} else {
/*
* We matched an explicit entry. If we are able to
@@ -4139,16 +4110,11 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
}
priv = pciserial_init_ports(dev, board);
- if (!IS_ERR(priv)) {
- pci_set_drvdata(dev, priv);
- return 0;
- }
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
- rc = PTR_ERR(priv);
-
- disable:
- pci_disable_device(dev);
- return rc;
+ pci_set_drvdata(dev, priv);
+ return 0;
}
static void pciserial_remove_one(struct pci_dev *dev)
@@ -4156,8 +4122,6 @@ static void pciserial_remove_one(struct pci_dev *dev)
struct serial_private *priv = pci_get_drvdata(dev);
pciserial_remove_ports(priv);
-
- pci_disable_device(dev);
}
#ifdef CONFIG_PM_SLEEP
@@ -4538,7 +4502,7 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
- PCI_ANY_ID , PCI_ANY_ID, 0, 0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_1152000 },
/*
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 658b392d1..34f05ed78 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -357,8 +357,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Fujitsu Wacom 1FGT Tablet PC device */
{ "FUJ02E9", 0 },
/*
- * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
- * disguise)
+ * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
+ * in disguise).
*/
{ "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
@@ -367,12 +367,14 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "PNPCXXX", UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
- /* Winbond CIR port, should not be probed. We should keep track
- of it to prevent the legacy serial driver from probing it */
+ /*
+ * Winbond CIR port, should not be probed. We should keep track of
+ * it to prevent the legacy serial driver from probing it.
+ */
{ "WEC1022", CIR_PORT },
/*
- * SMSC IrCC SIR/FIR port, should not be probed by serial driver
- * as well so its own driver can bind to it.
+ * SMSC IrCC SIR/FIR port, should not be probed by serial driver as
+ * well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 }
@@ -380,35 +382,35 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-static char *modem_names[] = {
+static const char *modem_names[] = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", NULL
};
-static int check_name(char *name)
+static bool check_name(const char *name)
{
- char **tmp;
+ const char **tmp;
for (tmp = modem_names; *tmp; tmp++)
if (strstr(name, *tmp))
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int check_resources(struct pnp_dev *dev)
+static bool check_resources(struct pnp_dev *dev)
{
- resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
- int i;
+ static const resource_size_t base[] = {0x2f8, 0x3f8, 0x2e8, 0x3e8};
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(base); i++) {
if (pnp_possible_config(dev, IORESOURCE_IO, base[i], 8))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/*
@@ -425,8 +427,8 @@ static int check_resources(struct pnp_dev *dev)
static int serial_pnp_guess_board(struct pnp_dev *dev)
{
if (!(check_name(pnp_dev_name(dev)) ||
- (dev->card && check_name(dev->card->name))))
- return -ENODEV;
+ (dev->card && check_name(dev->card->name))))
+ return -ENODEV;
if (check_resources(dev))
return 0;
@@ -462,11 +464,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
} else
return -ENODEV;
-#ifdef SERIAL_DEBUG_PNP
- printk(KERN_DEBUG
- "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
- uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
-#endif
+ dev_dbg(&dev->dev,
+ "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
+ uart.port.iobase, &uart.port.mapbase,
+ uart.port.irq, uart.port.iotype);
+
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index b1a6ba3c3..4743075ae 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -52,7 +53,7 @@
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
/*
* Here we define the default xmit fifo size used for each type of UART.
@@ -250,9 +251,11 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
-/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
-workaround of errata A-008006 which states that tx_loadsz should be
-configured less than Maximum supported fifo bytes */
+ /*
+ * tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+ * workaround of errata A-008006 which states that tx_loadsz should
+ * be configured less than Maximum supported fifo bytes.
+ */
[PORT_16550A_FSL64] = {
.name = "16550A_FSL64",
.fifo_size = 64,
@@ -522,6 +525,20 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
+{
+ unsigned char mcr = serial_in(p, UART_MCR);
+
+ if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(p, UART_MCR, mcr);
+}
+
+static void serial8250_em485_handle_start_tx(unsigned long arg);
+static void serial8250_em485_handle_stop_tx(unsigned long arg);
+
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
{
serial8250_clear_fifos(p);
@@ -546,6 +563,73 @@ void serial8250_rpm_put(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
+/**
+ * serial8250_em485_init() - put uart_8250_port into rs485 emulating
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to start rs485 software emulating on the
+ * &struct uart_8250_port* @p. Namely, RTS is switched before/after
+ * transmission. The function is idempotent, so it is safe to call it
+ * multiple times.
+ *
+ * The caller MUST enable interrupt on empty shift register before
+ * calling serial8250_em485_init(). This interrupt is not a part of
+ * 8250 standard, but implementation defined.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_destroy()
+ *
+ * Return 0 - success, -errno - otherwise
+ */
+int serial8250_em485_init(struct uart_8250_port *p)
+{
+ if (p->em485 != NULL)
+ return 0;
+
+ p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
+ if (p->em485 == NULL)
+ return -ENOMEM;
+
+ setup_timer(&p->em485->stop_tx_timer,
+ serial8250_em485_handle_stop_tx, (unsigned long)p);
+ setup_timer(&p->em485->start_tx_timer,
+ serial8250_em485_handle_start_tx, (unsigned long)p);
+ p->em485->active_timer = NULL;
+
+ serial8250_em485_rts_after_send(p);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_init);
+
+/**
+ * serial8250_em485_destroy() - put uart_8250_port into normal state
+ * @p: uart_8250_port port instance
+ *
+ * The function is used to stop rs485 software emulating on the
+ * &struct uart_8250_port* @p. The function is idempotent, so it is safe to
+ * call it multiple times.
+ *
+ * The function is supposed to be called from .rs485_config callback
+ * or from any other callback protected with p->port.lock spinlock.
+ *
+ * See also serial8250_em485_init()
+ */
+void serial8250_em485_destroy(struct uart_8250_port *p)
+{
+ if (p->em485 == NULL)
+ return;
+
+ del_timer(&p->em485->start_tx_timer);
+ del_timer(&p->em485->stop_tx_timer);
+
+ kfree(p->em485);
+ p->em485 = NULL;
+}
+EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
+
/*
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
@@ -1232,8 +1316,7 @@ static void autoconfig(struct uart_8250_port *up)
out_lock:
spin_unlock_irqrestore(&port->lock, flags);
if (up->capabilities != old_capabilities) {
- printk(KERN_WARNING
- "ttyS%d: detected caps %08x should be %08x\n",
+ pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities,
up->capabilities);
}
@@ -1298,7 +1381,78 @@ static void autoconfig_irq(struct uart_8250_port *up)
port->irq = (irq > 0) ? irq : 0;
}
-static inline void __stop_tx(struct uart_8250_port *p)
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
+}
+
+static void __do_stop_tx_rs485(struct uart_8250_port *p)
+{
+ if (!p->em485)
+ return;
+
+ serial8250_em485_rts_after_send(p);
+ /*
+ * Empty the RX FIFO, we are not interested in anything
+ * received during the half-duplex transmission.
+ * Enable previously disabled RX interrupts.
+ */
+ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+ serial8250_clear_fifos(p);
+
+ serial8250_rpm_get(p);
+
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_port_out(&p->port, UART_IER, p->ier);
+
+ serial8250_rpm_put(p);
+ }
+}
+
+static void serial8250_em485_handle_stop_tx(unsigned long arg)
+{
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->stop_tx_timer) {
+ __do_stop_tx_rs485(p);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
+}
+
+static void __stop_tx_rs485(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (!em485)
+ return;
+
+ /*
+ * __do_stop_tx_rs485 is going to set RTS according to config
+ * AND flush RX FIFO if required.
+ */
+ if (p->port.rs485.delay_rts_after_send > 0) {
+ em485->active_timer = &em485->stop_tx_timer;
+ mod_timer(&em485->stop_tx_timer, jiffies +
+ p->port.rs485.delay_rts_after_send * HZ / 1000);
+ } else {
+ __do_stop_tx_rs485(p);
+ }
+}
+
+static inline void __do_stop_tx(struct uart_8250_port *p)
{
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
@@ -1307,6 +1461,28 @@ static inline void __stop_tx(struct uart_8250_port *p)
}
}
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+ struct uart_8250_em485 *em485 = p->em485;
+
+ if (em485) {
+ unsigned char lsr = serial_in(p, UART_LSR);
+ /*
+ * To provide required timeing and allow FIFO transfer,
+ * __stop_tx_rs485 must be called only when both FIFO and
+ * shift register are empty. It is for device driver to enable
+ * interrupt on TEMT.
+ */
+ if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+ return;
+
+ del_timer(&em485->start_tx_timer);
+ em485->active_timer = NULL;
+ }
+ __do_stop_tx(p);
+ __stop_tx_rs485(p);
+}
+
static void serial8250_stop_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -1324,12 +1500,10 @@ static void serial8250_stop_tx(struct uart_port *port)
serial8250_rpm_put(up);
}
-static void serial8250_start_tx(struct uart_port *port)
+static inline void __start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- serial8250_rpm_get_tx(up);
-
if (up->dma && !up->dma->tx_dma(up))
return;
@@ -1339,6 +1513,7 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr;
+
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
if (lsr & UART_LSR_THRE)
@@ -1355,33 +1530,83 @@ static void serial8250_start_tx(struct uart_port *port)
}
}
-static void serial8250_throttle(struct uart_port *port)
+static inline void start_tx_rs485(struct uart_port *port)
{
- port->throttle(port);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
+ unsigned char mcr;
+
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ serial8250_stop_rx(&up->port);
+
+ del_timer(&em485->stop_tx_timer);
+ em485->active_timer = NULL;
+
+ mcr = serial_in(up, UART_MCR);
+ if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
+ !!(mcr & UART_MCR_RTS)) {
+ if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+ mcr |= UART_MCR_RTS;
+ else
+ mcr &= ~UART_MCR_RTS;
+ serial_out(up, UART_MCR, mcr);
+
+ if (up->port.rs485.delay_rts_before_send > 0) {
+ em485->active_timer = &em485->start_tx_timer;
+ mod_timer(&em485->start_tx_timer, jiffies +
+ up->port.rs485.delay_rts_before_send * HZ / 1000);
+ return;
+ }
+ }
+
+ __start_tx(port);
}
-static void serial8250_unthrottle(struct uart_port *port)
+static void serial8250_em485_handle_start_tx(unsigned long arg)
{
- port->unthrottle(port);
+ struct uart_8250_port *p = (struct uart_8250_port *)arg;
+ struct uart_8250_em485 *em485 = p->em485;
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->port.lock, flags);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer) {
+ __start_tx(&p->port);
+ em485->active_timer = NULL;
+ }
+ spin_unlock_irqrestore(&p->port.lock, flags);
}
-static void serial8250_stop_rx(struct uart_port *port)
+static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ struct uart_8250_em485 *em485 = up->em485;
- serial8250_rpm_get(up);
+ serial8250_rpm_get_tx(up);
- up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_port_out(port, UART_IER, up->ier);
+ if (em485 &&
+ em485->active_timer == &em485->start_tx_timer)
+ return;
- serial8250_rpm_put(up);
+ if (em485)
+ start_tx_rs485(port);
+ else
+ __start_tx(port);
+}
+
+static void serial8250_throttle(struct uart_port *port)
+{
+ port->throttle(port);
+}
+
+static void serial8250_unthrottle(struct uart_port *port)
+{
+ port->unthrottle(port);
}
static void serial8250_disable_ms(struct uart_port *port)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(port);
/* no MSR capabilities */
if (up->bugs & UART_BUG_NOMSR)
@@ -1406,81 +1631,85 @@ static void serial8250_enable_ms(struct uart_port *port)
serial8250_rpm_put(up);
}
+static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
+{
+ struct uart_port *port = &up->port;
+ unsigned char ch;
+ char flag = TTY_NORMAL;
+
+ if (likely(lsr & UART_LSR_DR))
+ ch = serial_in(up, UART_RX);
+ else
+ /*
+ * Intel 82571 has a Serial Over Lan device that will
+ * set UART_LSR_BI without setting UART_LSR_DR when
+ * it receives a break. To avoid reading from the
+ * receive buffer without UART_LSR_DR bit set, we
+ * just force the read character to be 0
+ */
+ ch = 0;
+
+ port->icount.rx++;
+
+ lsr |= up->lsr_saved_flags;
+ up->lsr_saved_flags = 0;
+
+ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+ if (lsr & UART_LSR_BI) {
+ lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+ port->icount.brk++;
+ /*
+ * We do the SysRQ and SAK checking
+ * here because otherwise the break
+ * may get masked by ignore_status_mask
+ * or read_status_mask.
+ */
+ if (uart_handle_break(port))
+ return;
+ } else if (lsr & UART_LSR_PE)
+ port->icount.parity++;
+ else if (lsr & UART_LSR_FE)
+ port->icount.frame++;
+ if (lsr & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ lsr &= port->read_status_mask;
+
+ if (lsr & UART_LSR_BI) {
+ DEBUG_INTR("handling break....");
+ flag = TTY_BREAK;
+ } else if (lsr & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (lsr & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+ if (uart_handle_sysrq_char(port, ch))
+ return;
+
+ uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
+}
+
/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
*/
-unsigned char
-serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
{
struct uart_port *port = &up->port;
- unsigned char ch;
int max_count = 256;
- char flag;
do {
- if (likely(lsr & UART_LSR_DR))
- ch = serial_in(up, UART_RX);
- else
- /*
- * Intel 82571 has a Serial Over Lan device that will
- * set UART_LSR_BI without setting UART_LSR_DR when
- * it receives a break. To avoid reading from the
- * receive buffer without UART_LSR_DR bit set, we
- * just force the read character to be 0
- */
- ch = 0;
-
- flag = TTY_NORMAL;
- port->icount.rx++;
-
- lsr |= up->lsr_saved_flags;
- up->lsr_saved_flags = 0;
-
- if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- if (lsr & UART_LSR_BI) {
- lsr &= ~(UART_LSR_FE | UART_LSR_PE);
- port->icount.brk++;
- /*
- * We do the SysRQ and SAK checking
- * here because otherwise the break
- * may get masked by ignore_status_mask
- * or read_status_mask.
- */
- if (uart_handle_break(port))
- goto ignore_char;
- } else if (lsr & UART_LSR_PE)
- port->icount.parity++;
- else if (lsr & UART_LSR_FE)
- port->icount.frame++;
- if (lsr & UART_LSR_OE)
- port->icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- lsr &= port->read_status_mask;
-
- if (lsr & UART_LSR_BI) {
- DEBUG_INTR("handling break....");
- flag = TTY_BREAK;
- } else if (lsr & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (lsr & UART_LSR_FE)
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
-
- uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
-
-ignore_char:
+ serial8250_read_char(up, lsr);
+ if (--max_count == 0)
+ break;
lsr = serial_in(up, UART_LSR);
- } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
- spin_unlock(&port->lock);
+ } while (lsr & (UART_LSR_DR | UART_LSR_BI));
+
tty_flip_buffer_push(&port->state->port);
- spin_lock(&port->lock);
return lsr;
}
EXPORT_SYMBOL_GPL(serial8250_rx_chars);
@@ -1513,11 +1742,9 @@ void serial8250_tx_chars(struct uart_8250_port *up)
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
- if (up->capabilities & UART_CAP_HFIFO) {
- if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
- BOTH_EMPTY)
- break;
- }
+ if ((up->capabilities & UART_CAP_HFIFO) &&
+ (serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
+ break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1746,6 +1973,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
+
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@@ -1979,23 +2207,23 @@ int serial8250_do_startup(struct uart_port *port)
serial8250_set_mctrl(port, port->mctrl);
- /* Serial over Lan (SoL) hack:
- Intel 8257x Gigabit ethernet chips have a
- 16550 emulation, to be used for Serial Over Lan.
- Those chips take a longer time than a normal
- serial device to signalize that a transmission
- data was queued. Due to that, the above test generally
- fails. One solution would be to delay the reading of
- iir. However, this is not reliable, since the timeout
- is variable. So, let's just don't test if we receive
- TX irq. This way, we'll never enable UART_BUG_TXEN.
+ /*
+ * Serial over Lan (SoL) hack:
+ * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
+ * used for Serial Over Lan. Those chips take a longer time than a
+ * normal serial device to signalize that a transmission data was
+ * queued. Due to that, the above test generally fails. One solution
+ * would be to delay the reading of iir. However, this is not
+ * reliable, since the timeout is variable. So, let's just don't
+ * test if we receive TX irq. This way, we'll never enable
+ * UART_BUG_TXEN.
*/
if (up->port.flags & UPF_NO_TXEN_TEST)
goto dont_test_tx_en;
/*
- * Do a quick test to see if we receive an
- * interrupt when we enable the TX irq.
+ * Do a quick test to see if we receive an interrupt when we enable
+ * the TX irq.
*/
serial_port_out(port, UART_IER, UART_IER_THRI);
lsr = serial_port_in(port, UART_LSR);
@@ -2078,8 +2306,12 @@ void serial8250_do_shutdown(struct uart_port *port)
/*
* Disable interrupts from this port
*/
+ spin_lock_irqsave(&port->lock, flags);
up->ier = 0;
serial_port_out(port, UART_IER, 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ synchronize_irq(port->irq);
if (up->dma)
serial8250_release_dma(up);
@@ -2245,9 +2477,9 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac);
}
-static unsigned int
-serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static unsigned int serial8250_get_baud_rate(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int tolerance = port->uartclk / 100;
@@ -2264,7 +2496,7 @@ serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
void
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+ struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
@@ -2577,8 +2809,7 @@ static int do_get_rxtrig(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1)
return -EINVAL;
@@ -2614,8 +2845,7 @@ static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
- struct uart_8250_port *up =
- container_of(uport, struct uart_8250_port, port);
+ struct uart_8250_port *up = up_to_u8250p(uport);
int rxtrig;
if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 ||
@@ -2739,8 +2969,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
-static const char *
-serial8250_type(struct uart_port *port)
+static const char *serial8250_type(struct uart_port *port)
{
int type = port->type;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index bab6b3ae2..1b7bd2655 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -35,7 +35,7 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock;
};
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE)
static int __init uniphier_early_console_setup(struct earlycon_device *device,
const char *options)
{
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index b03cb5175..4d7cb9c04 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -262,7 +262,12 @@ config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
- ::: To be written :::
+ Say Y here if you have a IODATA RSA-DV II/S ISA card and
+ would like to use its >115kbps speeds.
+ You will need to provide module parameter "probe_rsa", or boot-time
+ parameter 8250.probe_rsa with I/O addresses of this card then.
+
+ If you don't have such card, or if unsure, say N.
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
@@ -272,6 +277,30 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+config SERIAL_8250_BCM2835AUX
+ tristate "BCM2835 auxiliar mini UART support"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ
+ help
+ Support for the BCM2835 auxiliar mini UART.
+
+ Features and limitations of the UART are
+ Registers are similar to 16650 registers,
+ set bits in the control registers that are unsupported
+ are ignored and read back as 0
+ 7/8 bit operation with 1 start and 1 stop bit
+ 8 symbols deep fifo for rx and tx
+ SW controlled RTS and SW readable CTS
+ Clock rate derived from system clock
+ Uses 8 times oversampling (compared to 16 times for 16650)
+ Missing break detection (but break generation)
+ Missing framing error detection
+ Missing parity bit
+ Missing receive time-out interrupt
+ Missing DCD, DSR, DTR and RI signals
+
+ If unsure, say N.
+
config SERIAL_8250_FSL
bool
depends on SERIAL_8250_CONSOLE
@@ -346,7 +375,7 @@ config SERIAL_8250_LPC18XX
serial port, say Y to this option. If unsure, say Y.
config SERIAL_8250_MT6577
- bool "Mediatek serial port support"
+ tristate "Mediatek serial port support"
depends on SERIAL_8250 && ARCH_MEDIATEK
help
If you have a Mediatek based board and want to use the
@@ -360,9 +389,10 @@ config SERIAL_8250_UNIPHIER
serial ports, say Y to this option. If unsure, say N.
config SERIAL_8250_INGENIC
- bool "Support for Ingenic SoC serial ports"
- depends on OF_FLATTREE
- select LIBFDT
+ tristate "Support for Ingenic SoC serial ports"
+ depends on SERIAL_8250
+ depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON
+ depends on MIPS || COMPILE_TEST
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.
@@ -378,6 +408,16 @@ config SERIAL_8250_MID
present on the UART found on Intel Medfield SOC and various other
Intel platforms.
+config SERIAL_8250_MOXA
+ tristate "MOXA SmartIO MUE support"
+ depends on SERIAL_8250 && PCI
+ help
+ Say Y here if you have a Moxa SmartIO MUE multiport serial card.
+ If unsure, say N.
+
+ This driver can also be built as a module. The module will be called
+ 8250_moxa. If you want to do that, say M here.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index b9b9bca5b..c9a2d6ed8 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
+obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
@@ -28,6 +29,7 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
+obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 4d180c942..933c2688d 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -257,7 +257,7 @@ static const struct serial_quirk quirks[] = {
};
-static int serial_config(struct pcmcia_device * link);
+static int serial_config(struct pcmcia_device *link);
static void serial_remove(struct pcmcia_device *link)
@@ -309,7 +309,7 @@ static int serial_probe(struct pcmcia_device *link)
dev_dbg(&link->dev, "serial_attach()\n");
/* Create new serial device */
- info = kzalloc(sizeof (*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->p_dev = link;
@@ -339,7 +339,7 @@ static void serial_detach(struct pcmcia_device *link)
/*====================================================================*/
-static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
@@ -441,16 +441,20 @@ static int simple_config(struct pcmcia_device *link)
struct serial_info *info = link->priv;
int i = -ENODEV, try;
- /* First pass: look for a config entry that looks normal.
- * Two tries: without IO aliases, then with aliases */
+ /*
+ * First pass: look for a config entry that looks normal.
+ * Two tries: without IO aliases, then with aliases.
+ */
link->config_flags |= CONF_AUTO_SET_VPP;
for (try = 0; try < 4; try++)
if (!pcmcia_loop_config(link, simple_config_check, &try))
goto found_port;
- /* Second pass: try to find an entry that isn't picky about
- its base address, then try to grab any standard serial port
- address, and finally try to get any free port. */
+ /*
+ * Second pass: try to find an entry that isn't picky about
+ * its base address, then try to grab any standard serial port
+ * address, and finally try to get any free port.
+ */
if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL))
goto found_port;
@@ -480,8 +484,10 @@ static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
if (p_dev->resource[1]->end)
return -EINVAL;
- /* The quad port cards have bad CIS's, so just look for a
- window larger than 8 ports and assume it will be right */
+ /*
+ * The quad port cards have bad CIS's, so just look for a
+ * window larger than 8 ports and assume it will be right.
+ */
if (p_dev->resource[0]->end <= 8)
return -EINVAL;
@@ -527,8 +533,8 @@ static int multi_config(struct pcmcia_device *link)
info->multi = 2;
if (pcmcia_loop_config(link, multi_config_check_notpicky,
&base2)) {
- dev_warn(&link->dev, "no usable port range "
- "found, giving up\n");
+ dev_warn(&link->dev,
+ "no usable port range found, giving up\n");
return -ENODEV;
}
}
@@ -600,7 +606,7 @@ static int serial_check_for_multi(struct pcmcia_device *p_dev, void *priv_data)
}
-static int serial_config(struct pcmcia_device * link)
+static int serial_config(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
int i;
@@ -623,8 +629,10 @@ static int serial_config(struct pcmcia_device * link)
break;
}
- /* Another check for dual-serial cards: look for either serial or
- multifunction cards that ask for appropriate IO port ranges */
+ /*
+ * Another check for dual-serial cards: look for either serial or
+ * multifunction cards that ask for appropriate IO port ranges.
+ */
if ((info->multi == 0) &&
(link->has_func_id) &&
(link->socket->pcmcia_pfc == 0) &&
@@ -701,7 +709,7 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
- PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001", 0x18df0ba0, 0x831b1064),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
@@ -797,30 +805,30 @@ static const struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100",0x19ca78af,0x71d98e83),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232 1.00.",0x19ca78af,0x69fb7490),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL232",0x19ca78af,0xb6bc0235),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232",0x63f2e0bd,0xb9e175d3),
- PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.","SERIAL CARD: CF232-5",0x63f2e0bd,0xfce33442),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232",0x3beb8cf2,0x171e7190),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF232-5",0x3beb8cf2,0x20da4262),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF428",0x3beb8cf2,0xea5dd57d),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: CF500",0x3beb8cf2,0xd77255fa),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: IC232",0x3beb8cf2,0x6a709903),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: SL232",0x3beb8cf2,0x18430676),
- PCMCIA_DEVICE_PROD_ID12("Elan","Serial Port: XL232",0x3beb8cf2,0x6f933767),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(0,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: CF332",0x3beb8cf2,0x16dc1ba7),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL332",0x3beb8cf2,0x19816c41),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL385",0x3beb8cf2,0x64112029),
- PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
- PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232", 0x19ca78af, 0xb6bc0235),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232", 0x63f2e0bd, 0xb9e175d3),
+ PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c2000.", "SERIAL CARD: CF232-5", 0x63f2e0bd, 0xfce33442),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232", 0x3beb8cf2, 0x171e7190),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF232-5", 0x3beb8cf2, 0x20da4262),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF428", 0x3beb8cf2, 0xea5dd57d),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: CF500", 0x3beb8cf2, 0xd77255fa),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: IC232", 0x3beb8cf2, 0x6a709903),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: SL232", 0x3beb8cf2, 0x18430676),
+ PCMCIA_DEVICE_PROD_ID12("Elan", "Serial Port: XL232", 0x3beb8cf2, 0x6f933767),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "Elan", "Serial+Parallel Port: SP230", 0x3beb8cf2, 0xdb9e58bc),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: CF332", 0x3beb8cf2, 0x16dc1ba7),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL332", 0x3beb8cf2, 0x19816c41),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL385", 0x3beb8cf2, 0x64112029),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(2, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
+ PCMCIA_MFC_DEVICE_PROD_ID12(3, "Elan", "Serial Port: SL432", 0x3beb8cf2, 0x1cce7ac4),
PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */